+18
-1
appview/knots/knots.go
+18
-1
appview/knots/knots.go
···
39
39
Knotstream *eventconsumer.Consumer
40
40
}
41
41
42
+
type tab = map[string]any
43
+
44
+
var (
45
+
knotsTabs []tab = []tab{
46
+
{"Name": "profile", "Icon": "user"},
47
+
{"Name": "keys", "Icon": "key"},
48
+
{"Name": "emails", "Icon": "mail"},
49
+
{"Name": "notifications", "Icon": "bell"},
50
+
{"Name": "knots", "Icon": "volleyball"},
51
+
{"Name": "spindles", "Icon": "spool"},
52
+
}
53
+
)
54
+
42
55
func (k *Knots) Router() http.Handler {
43
56
r := chi.NewRouter()
44
57
···
70
83
k.Pages.Knots(w, pages.KnotsParams{
71
84
LoggedInUser: user,
72
85
Registrations: registrations,
86
+
Tabs: knotsTabs,
87
+
Tab: "knots",
73
88
})
74
89
}
75
90
···
132
147
Members: members,
133
148
Repos: repoMap,
134
149
IsOwner: true,
150
+
Tabs: knotsTabs,
151
+
Tab: "knots",
135
152
})
136
153
}
137
154
···
596
613
}
597
614
598
615
// success
599
-
k.Pages.HxRedirect(w, fmt.Sprintf("/knots/%s", domain))
616
+
k.Pages.HxRedirect(w, fmt.Sprintf("/settings/knots/%s", domain))
600
617
}
601
618
602
619
func (k *Knots) removeMember(w http.ResponseWriter, r *http.Request) {
+10
appview/pages/pages.go
+10
appview/pages/pages.go
···
407
407
type KnotsParams struct {
408
408
LoggedInUser *oauth.User
409
409
Registrations []models.Registration
410
+
Tabs []map[string]any
411
+
Tab string
410
412
}
411
413
412
414
func (p *Pages) Knots(w io.Writer, params KnotsParams) error {
···
419
421
Members []string
420
422
Repos map[string][]models.Repo
421
423
IsOwner bool
424
+
Tabs []map[string]any
425
+
Tab string
422
426
}
423
427
424
428
func (p *Pages) Knot(w io.Writer, params KnotParams) error {
···
436
440
type SpindlesParams struct {
437
441
LoggedInUser *oauth.User
438
442
Spindles []models.Spindle
443
+
Tabs []map[string]any
444
+
Tab string
439
445
}
440
446
441
447
func (p *Pages) Spindles(w io.Writer, params SpindlesParams) error {
···
444
450
445
451
type SpindleListingParams struct {
446
452
models.Spindle
453
+
Tabs []map[string]any
454
+
Tab string
447
455
}
448
456
449
457
func (p *Pages) SpindleListing(w io.Writer, params SpindleListingParams) error {
···
455
463
Spindle models.Spindle
456
464
Members []string
457
465
Repos map[string][]models.Repo
466
+
Tabs []map[string]any
467
+
Tab string
458
468
}
459
469
460
470
func (p *Pages) SpindleDashboard(w io.Writer, params SpindleDashboardParams) error {
+23
-7
appview/pages/templates/knots/dashboard.html
+23
-7
appview/pages/templates/knots/dashboard.html
···
1
-
{{ define "title" }}{{ .Registration.Domain }} · knots{{ end }}
1
+
{{ define "title" }}{{ .Registration.Domain }} · {{ .Tab }} settings{{ end }}
2
2
3
3
{{ define "content" }}
4
-
<div class="px-6 py-4">
4
+
<div class="p-6">
5
+
<p class="text-xl font-bold dark:text-white">Settings</p>
6
+
</div>
7
+
<div class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
8
+
<section class="w-full grid grid-cols-1 md:grid-cols-4 gap-6">
9
+
<div class="col-span-1">
10
+
{{ template "user/settings/fragments/sidebar" . }}
11
+
</div>
12
+
<div class="col-span-1 md:col-span-3 flex flex-col gap-6">
13
+
{{ template "knotDash" . }}
14
+
</div>
15
+
</section>
16
+
</div>
17
+
{{ end }}
18
+
19
+
{{ define "knotDash" }}
20
+
<div>
5
21
<div class="flex justify-between items-center">
6
-
<h1 class="text-xl font-bold dark:text-white">{{ .Registration.Domain }}</h1>
22
+
<h2 class="text-sm pb-2 uppercase font-bold">{{ .Tab }} · {{ .Registration.Domain }}</h2>
7
23
<div id="right-side" class="flex gap-2">
8
24
{{ $style := "px-2 py-1 rounded flex items-center flex-shrink-0 gap-2" }}
9
25
{{ $isOwner := and .LoggedInUser (eq .LoggedInUser.Did .Registration.ByDid) }}
···
35
51
</div>
36
52
37
53
{{ if .Members }}
38
-
<section class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
54
+
<section class="bg-white dark:bg-gray-800 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
39
55
<div class="flex flex-col gap-2">
40
56
{{ block "member" . }} {{ end }}
41
57
</div>
···
79
95
<button
80
96
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
81
97
title="Delete knot"
82
-
hx-delete="/knots/{{ .Domain }}"
98
+
hx-delete="/settings/knots/{{ .Domain }}"
83
99
hx-swap="outerHTML"
84
100
hx-confirm="Are you sure you want to delete the knot '{{ .Domain }}'?"
85
101
hx-headers='{"shouldRedirect": "true"}'
···
95
111
<button
96
112
class="btn gap-2 group"
97
113
title="Retry knot verification"
98
-
hx-post="/knots/{{ .Domain }}/retry"
114
+
hx-post="/settings/knots/{{ .Domain }}/retry"
99
115
hx-swap="none"
100
116
hx-headers='{"shouldRefresh": "true"}'
101
117
>
···
113
129
<button
114
130
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
115
131
title="Remove member"
116
-
hx-post="/knots/{{ $root.Registration.Domain }}/remove"
132
+
hx-post="/settings/knots/{{ $root.Registration.Domain }}/remove"
117
133
hx-swap="none"
118
134
hx-vals='{"member": "{{$member}}" }'
119
135
hx-confirm="Are you sure you want to remove {{ $memberHandle }} from this knot?"
+1
-1
appview/pages/templates/knots/fragments/addMemberModal.html
+1
-1
appview/pages/templates/knots/fragments/addMemberModal.html
+3
-3
appview/pages/templates/knots/fragments/knotListing.html
+3
-3
appview/pages/templates/knots/fragments/knotListing.html
···
7
7
8
8
{{ define "knotLeftSide" }}
9
9
{{ if .Registered }}
10
-
<a href="/knots/{{ .Domain }}" class="hover:no-underline flex items-center gap-2 min-w-0 max-w-[60%]">
10
+
<a href="/settings/knots/{{ .Domain }}" class="hover:no-underline flex items-center gap-2 min-w-0 max-w-[60%]">
11
11
{{ i "hard-drive" "w-4 h-4" }}
12
12
<span class="hover:underline">
13
13
{{ .Domain }}
···
56
56
<button
57
57
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
58
58
title="Delete knot"
59
-
hx-delete="/knots/{{ .Domain }}"
59
+
hx-delete="/settings/knots/{{ .Domain }}"
60
60
hx-swap="outerHTML"
61
61
hx-target="#knot-{{.Id}}"
62
62
hx-confirm="Are you sure you want to delete the knot '{{ .Domain }}'?"
···
72
72
<button
73
73
class="btn gap-2 group"
74
74
title="Retry knot verification"
75
-
hx-post="/knots/{{ .Domain }}/retry"
75
+
hx-post="/settings/knots/{{ .Domain }}/retry"
76
76
hx-swap="none"
77
77
hx-target="#knot-{{.Id}}"
78
78
>
+42
-11
appview/pages/templates/knots/index.html
+42
-11
appview/pages/templates/knots/index.html
···
1
-
{{ define "title" }}knots{{ end }}
1
+
{{ define "title" }}{{ .Tab }} settings{{ end }}
2
2
3
3
{{ define "content" }}
4
-
<div class="px-6 py-4 flex items-center justify-between gap-4 align-bottom">
5
-
<h1 class="text-xl font-bold dark:text-white">Knots</h1>
6
-
<span class="flex items-center gap-1">
7
-
{{ i "book" "w-3 h-3" }}
8
-
<a href="https://tangled.org/@tangled.org/core/blob/master/docs/knot-hosting.md">docs</a>
9
-
</span>
10
-
</div>
4
+
<div class="p-6">
5
+
<p class="text-xl font-bold dark:text-white">Settings</p>
6
+
</div>
7
+
<div class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
8
+
<section class="w-full grid grid-cols-1 md:grid-cols-4 gap-6">
9
+
<div class="col-span-1">
10
+
{{ template "user/settings/fragments/sidebar" . }}
11
+
</div>
12
+
<div class="col-span-1 md:col-span-3 flex flex-col gap-6">
13
+
{{ template "knotsList" . }}
14
+
</div>
15
+
</section>
16
+
</div>
17
+
{{ end }}
18
+
19
+
{{ define "knotsList" }}
20
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-center">
21
+
<div class="col-span-1 md:col-span-2">
22
+
<h2 class="text-sm pb-2 uppercase font-bold">Knots</h2>
23
+
{{ block "about" . }} {{ end }}
24
+
</div>
25
+
<div class="col-span-1 md:col-span-1 md:justify-self-end">
26
+
{{ template "docsButton" . }}
27
+
</div>
28
+
</div>
11
29
12
-
<section class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
30
+
<section>
13
31
<div class="flex flex-col gap-6">
14
-
{{ block "about" . }} {{ end }}
15
32
{{ block "list" . }} {{ end }}
16
33
{{ block "register" . }} {{ end }}
17
34
</div>
···
50
67
<h2 class="text-sm font-bold py-2 uppercase dark:text-gray-300">register a knot</h2>
51
68
<p class="mb-2 dark:text-gray-300">Enter the hostname of your knot to get started.</p>
52
69
<form
53
-
hx-post="/knots/register"
70
+
hx-post="/settings/knots/register"
54
71
class="max-w-2xl mb-2 space-y-4"
55
72
hx-indicator="#register-button"
56
73
hx-swap="none"
···
84
101
85
102
</section>
86
103
{{ end }}
104
+
105
+
{{ define "docsButton" }}
106
+
<a
107
+
class="btn flex items-center gap-2"
108
+
href="https://tangled.org/@tangled.org/core/blob/master/docs/spindle/hosting.md">
109
+
{{ i "book" "size-4" }}
110
+
docs
111
+
</a>
112
+
<div
113
+
id="add-email-modal"
114
+
popover
115
+
class="bg-white w-full md:w-96 dark:bg-gray-800 p-4 rounded border border-gray-200 dark:border-gray-700 drop-shadow dark:text-white backdrop:bg-gray-400/50 dark:backdrop:bg-gray-800/50">
116
+
</div>
117
+
{{ end }}
-2
appview/pages/templates/layouts/fragments/topbar.html
-2
appview/pages/templates/layouts/fragments/topbar.html
···
61
61
<a href="/{{ $user }}">profile</a>
62
62
<a href="/{{ $user }}?tab=repos">repositories</a>
63
63
<a href="/{{ $user }}?tab=strings">strings</a>
64
-
<a href="/knots">knots</a>
65
-
<a href="/spindles">spindles</a>
66
64
<a href="/settings">settings</a>
67
65
<a href="#"
68
66
hx-post="/logout"
+1
-1
appview/pages/templates/repo/fork.html
+1
-1
appview/pages/templates/repo/fork.html
···
34
34
{{ end }}
35
35
</div>
36
36
</div>
37
-
<p class="text-sm text-gray-500 dark:text-gray-400">A knot hosts repository data. <a href="/knots" class="underline">Learn how to register your own knot.</a></p>
37
+
<p class="text-sm text-gray-500 dark:text-gray-400">A knot hosts repository data. <a href="/settings/knots" class="underline">Learn how to register your own knot.</a></p>
38
38
</fieldset>
39
39
40
40
<div class="space-y-2">
+1
-1
appview/pages/templates/repo/new.html
+1
-1
appview/pages/templates/repo/new.html
···
165
165
</div>
166
166
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
167
167
A knot hosts repository data and handles Git operations.
168
-
You can also <a href="/knots" class="underline">register your own knot</a>.
168
+
You can also <a href="/settings/knots" class="underline">register your own knot</a>.
169
169
</p>
170
170
</div>
171
171
{{ end }}
+22
-6
appview/pages/templates/spindles/dashboard.html
+22
-6
appview/pages/templates/spindles/dashboard.html
···
1
-
{{ define "title" }}{{.Spindle.Instance}} · spindles{{ end }}
1
+
{{ define "title" }}{{.Spindle.Instance}} · {{ .Tab }} settings{{ end }}
2
2
3
3
{{ define "content" }}
4
-
<div class="px-6 py-4">
4
+
<div class="p-6">
5
+
<p class="text-xl font-bold dark:text-white">Settings</p>
6
+
</div>
7
+
<div class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
8
+
<section class="w-full grid grid-cols-1 md:grid-cols-4 gap-6">
9
+
<div class="col-span-1">
10
+
{{ template "user/settings/fragments/sidebar" . }}
11
+
</div>
12
+
<div class="col-span-1 md:col-span-3 flex flex-col gap-6">
13
+
{{ template "spindleDash" . }}
14
+
</div>
15
+
</section>
16
+
</div>
17
+
{{ end }}
18
+
19
+
{{ define "spindleDash" }}
20
+
<div>
5
21
<div class="flex justify-between items-center">
6
-
<h1 class="text-xl font-bold dark:text-white">{{ .Spindle.Instance }}</h1>
22
+
<h2 class="text-sm pb-2 uppercase font-bold">{{ .Tab }} · {{ .Spindle.Instance }}</h2>
7
23
<div id="right-side" class="flex gap-2">
8
24
{{ $style := "px-2 py-1 rounded flex items-center flex-shrink-0 gap-2" }}
9
25
{{ $isOwner := and .LoggedInUser (eq .LoggedInUser.Did .Spindle.Owner) }}
···
71
87
<button
72
88
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
73
89
title="Delete spindle"
74
-
hx-delete="/spindles/{{ .Instance }}"
90
+
hx-delete="/settings/spindles/{{ .Instance }}"
75
91
hx-swap="outerHTML"
76
92
hx-confirm="Are you sure you want to delete the spindle '{{ .Instance }}'?"
77
93
hx-headers='{"shouldRedirect": "true"}'
···
87
103
<button
88
104
class="btn gap-2 group"
89
105
title="Retry spindle verification"
90
-
hx-post="/spindles/{{ .Instance }}/retry"
106
+
hx-post="/settings/spindles/{{ .Instance }}/retry"
91
107
hx-swap="none"
92
108
hx-headers='{"shouldRefresh": "true"}'
93
109
>
···
104
120
<button
105
121
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
106
122
title="Remove member"
107
-
hx-post="/spindles/{{ $root.Spindle.Instance }}/remove"
123
+
hx-post="/settings/spindles/{{ $root.Spindle.Instance }}/remove"
108
124
hx-swap="none"
109
125
hx-vals='{"member": "{{$member}}" }'
110
126
hx-confirm="Are you sure you want to remove {{ resolve $member }} from this instance?"
+1
-1
appview/pages/templates/spindles/fragments/addMemberModal.html
+1
-1
appview/pages/templates/spindles/fragments/addMemberModal.html
+3
-3
appview/pages/templates/spindles/fragments/spindleListing.html
+3
-3
appview/pages/templates/spindles/fragments/spindleListing.html
···
7
7
8
8
{{ define "spindleLeftSide" }}
9
9
{{ if .Verified }}
10
-
<a href="/spindles/{{ .Instance }}" class="hover:no-underline flex items-center gap-2 min-w-0 max-w-[60%]">
10
+
<a href="/settings/spindles/{{ .Instance }}" class="hover:no-underline flex items-center gap-2 min-w-0 max-w-[60%]">
11
11
{{ i "hard-drive" "w-4 h-4" }}
12
12
<span class="hover:underline">
13
13
{{ .Instance }}
···
50
50
<button
51
51
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
52
52
title="Delete spindle"
53
-
hx-delete="/spindles/{{ .Instance }}"
53
+
hx-delete="/settings/spindles/{{ .Instance }}"
54
54
hx-swap="outerHTML"
55
55
hx-target="#spindle-{{.Id}}"
56
56
hx-confirm="Are you sure you want to delete the spindle '{{ .Instance }}'?"
···
66
66
<button
67
67
class="btn gap-2 group"
68
68
title="Retry spindle verification"
69
-
hx-post="/spindles/{{ .Instance }}/retry"
69
+
hx-post="/settings/spindles/{{ .Instance }}/retry"
70
70
hx-swap="none"
71
71
hx-target="#spindle-{{.Id}}"
72
72
>
+90
-59
appview/pages/templates/spindles/index.html
+90
-59
appview/pages/templates/spindles/index.html
···
1
-
{{ define "title" }}spindles{{ end }}
1
+
{{ define "title" }}{{ .Tab }} settings{{ end }}
2
2
3
3
{{ define "content" }}
4
-
<div class="px-6 py-4 flex items-center justify-between gap-4 align-bottom">
5
-
<h1 class="text-xl font-bold dark:text-white">Spindles</h1>
6
-
<span class="flex items-center gap-1">
7
-
{{ i "book" "w-3 h-3" }}
8
-
<a href="https://tangled.org/@tangled.org/core/blob/master/docs/spindle/hosting.md">docs</a>
9
-
</span>
4
+
<div class="p-6">
5
+
<p class="text-xl font-bold dark:text-white">Settings</p>
6
+
</div>
7
+
<div class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
8
+
<section class="w-full grid grid-cols-1 md:grid-cols-4 gap-6">
9
+
<div class="col-span-1">
10
+
{{ template "user/settings/fragments/sidebar" . }}
11
+
</div>
12
+
<div class="col-span-1 md:col-span-3 flex flex-col gap-6">
13
+
{{ template "spindleList" . }}
14
+
</div>
15
+
</section>
16
+
</div>
17
+
{{ end }}
18
+
19
+
{{ define "spindleList" }}
20
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-center">
21
+
<div class="col-span-1 md:col-span-2">
22
+
<h2 class="text-sm pb-2 uppercase font-bold">Spindle</h2>
23
+
{{ block "about" . }} {{ end }}
24
+
</div>
25
+
<div class="col-span-1 md:col-span-1 md:justify-self-end">
26
+
{{ template "docsButton" . }}
27
+
</div>
10
28
</div>
11
29
12
-
<section class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto drop-shadow-sm dark:text-white">
30
+
<section>
13
31
<div class="flex flex-col gap-6">
14
-
{{ block "about" . }} {{ end }}
15
32
{{ block "list" . }} {{ end }}
16
33
{{ block "register" . }} {{ end }}
17
34
</div>
···
20
37
21
38
{{ define "about" }}
22
39
<section class="rounded flex items-center gap-2">
23
-
<p class="text-gray-500 dark:text-gray-400">
24
-
Spindles are small CI runners.
25
-
</p>
40
+
<p class="text-gray-500 dark:text-gray-400">
41
+
Spindles are small CI runners.
42
+
</p>
26
43
</section>
27
44
{{ end }}
28
45
29
46
{{ define "list" }}
30
-
<section class="rounded w-full flex flex-col gap-2">
31
-
<h2 class="text-sm font-bold py-2 uppercase dark:text-gray-300">your spindles</h2>
32
-
<div class="flex flex-col rounded border border-gray-200 dark:border-gray-700 w-full">
33
-
{{ range $spindle := .Spindles }}
34
-
{{ template "spindles/fragments/spindleListing" . }}
35
-
{{ else }}
36
-
<div class="flex items-center justify-center p-2 border-b border-gray-200 dark:border-gray-700 text-gray-500">
37
-
no spindles registered yet
38
-
</div>
39
-
{{ end }}
47
+
<section class="rounded w-full flex flex-col gap-2">
48
+
<h2 class="text-sm font-bold py-2 uppercase dark:text-gray-300">your spindles</h2>
49
+
<div class="flex flex-col rounded border border-gray-200 dark:border-gray-700 w-full">
50
+
{{ range $spindle := .Spindles }}
51
+
{{ template "spindles/fragments/spindleListing" . }}
52
+
{{ else }}
53
+
<div class="flex items-center justify-center p-2 border-b border-gray-200 dark:border-gray-700 text-gray-500">
54
+
no spindles registered yet
40
55
</div>
41
-
<div id="operation-error" class="text-red-500 dark:text-red-400"></div>
42
-
</section>
56
+
{{ end }}
57
+
</div>
58
+
<div id="operation-error" class="text-red-500 dark:text-red-400"></div>
59
+
</section>
43
60
{{ end }}
44
61
45
62
{{ define "register" }}
46
-
<section class="rounded w-full lg:w-fit flex flex-col gap-2">
47
-
<h2 class="text-sm font-bold py-2 uppercase dark:text-gray-300">register a spindle</h2>
48
-
<p class="mb-2 dark:text-gray-300">Enter the hostname of your spindle to get started.</p>
49
-
<form
50
-
hx-post="/spindles/register"
51
-
class="max-w-2xl mb-2 space-y-4"
52
-
hx-indicator="#register-button"
53
-
hx-swap="none"
54
-
>
55
-
<div class="flex gap-2">
56
-
<input
57
-
type="text"
58
-
id="instance"
59
-
name="instance"
60
-
placeholder="spindle.example.com"
61
-
required
62
-
class="flex-1 w-full dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400 px-3 py-2 border rounded"
63
-
>
64
-
<button
65
-
type="submit"
66
-
id="register-button"
67
-
class="btn rounded flex items-center py-2 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 group"
68
-
>
69
-
<span class="inline-flex items-center gap-2">
70
-
{{ i "plus" "w-4 h-4" }}
71
-
register
72
-
</span>
73
-
<span class="pl-2 hidden group-[.htmx-request]:inline">
74
-
{{ i "loader-circle" "w-4 h-4 animate-spin" }}
75
-
</span>
76
-
</button>
77
-
</div>
63
+
<section class="rounded w-full lg:w-fit flex flex-col gap-2">
64
+
<h2 class="text-sm font-bold py-2 uppercase dark:text-gray-300">register a spindle</h2>
65
+
<p class="mb-2 dark:text-gray-300">Enter the hostname of your spindle to get started.</p>
66
+
<form
67
+
hx-post="/settings/spindles/register"
68
+
class="max-w-2xl mb-2 space-y-4"
69
+
hx-indicator="#register-button"
70
+
hx-swap="none"
71
+
>
72
+
<div class="flex gap-2">
73
+
<input
74
+
type="text"
75
+
id="instance"
76
+
name="instance"
77
+
placeholder="spindle.example.com"
78
+
required
79
+
class="flex-1 w-full dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400 px-3 py-2 border rounded"
80
+
>
81
+
<button
82
+
type="submit"
83
+
id="register-button"
84
+
class="btn rounded flex items-center py-2 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 group"
85
+
>
86
+
<span class="inline-flex items-center gap-2">
87
+
{{ i "plus" "w-4 h-4" }}
88
+
register
89
+
</span>
90
+
<span class="pl-2 hidden group-[.htmx-request]:inline">
91
+
{{ i "loader-circle" "w-4 h-4 animate-spin" }}
92
+
</span>
93
+
</button>
94
+
</div>
78
95
79
-
<div id="register-error" class="dark:text-red-400"></div>
80
-
</form>
96
+
<div id="register-error" class="dark:text-red-400"></div>
97
+
</form>
98
+
99
+
</section>
100
+
{{ end }}
81
101
82
-
</section>
102
+
{{ define "docsButton" }}
103
+
<a
104
+
class="btn flex items-center gap-2"
105
+
href="https://tangled.org/@tangled.org/core/blob/master/docs/spindle/hosting.md">
106
+
{{ i "book" "size-4" }}
107
+
docs
108
+
</a>
109
+
<div
110
+
id="add-email-modal"
111
+
popover
112
+
class="bg-white w-full md:w-96 dark:bg-gray-800 p-4 rounded border border-gray-200 dark:border-gray-700 drop-shadow dark:text-white backdrop:bg-gray-400/50 dark:backdrop:bg-gray-800/50">
113
+
</div>
83
114
{{ end }}
+2
appview/settings/settings.go
+2
appview/settings/settings.go
+19
-2
appview/spindles/spindles.go
+19
-2
appview/spindles/spindles.go
···
38
38
Logger *slog.Logger
39
39
}
40
40
41
+
type tab = map[string]any
42
+
43
+
var (
44
+
spindlesTabs []tab = []tab{
45
+
{"Name": "profile", "Icon": "user"},
46
+
{"Name": "keys", "Icon": "key"},
47
+
{"Name": "emails", "Icon": "mail"},
48
+
{"Name": "notifications", "Icon": "bell"},
49
+
{"Name": "knots", "Icon": "volleyball"},
50
+
{"Name": "spindles", "Icon": "spool"},
51
+
}
52
+
)
53
+
41
54
func (s *Spindles) Router() http.Handler {
42
55
r := chi.NewRouter()
43
56
···
69
82
s.Pages.Spindles(w, pages.SpindlesParams{
70
83
LoggedInUser: user,
71
84
Spindles: all,
85
+
Tabs: spindlesTabs,
86
+
Tab: "spindles",
72
87
})
73
88
}
74
89
···
127
142
Spindle: spindle,
128
143
Members: members,
129
144
Repos: repoMap,
145
+
Tabs: spindlesTabs,
146
+
Tab: "spindles",
130
147
})
131
148
}
132
149
···
365
382
366
383
shouldRedirect := r.Header.Get("shouldRedirect")
367
384
if shouldRedirect == "true" {
368
-
s.Pages.HxRedirect(w, "/spindles")
385
+
s.Pages.HxRedirect(w, "/settings/spindles")
369
386
return
370
387
}
371
388
···
581
598
}
582
599
583
600
// success
584
-
s.Pages.HxRedirect(w, fmt.Sprintf("/spindles/%s", instance))
601
+
s.Pages.HxRedirect(w, fmt.Sprintf("/settings/spindles/%s", instance))
585
602
}
586
603
587
604
func (s *Spindles) removeMember(w http.ResponseWriter, r *http.Request) {
+4
-2
appview/state/router.go
+4
-2
appview/state/router.go
···
166
166
167
167
r.Mount("/settings", s.SettingsRouter())
168
168
r.Mount("/strings", s.StringsRouter(mw))
169
-
r.Mount("/knots", s.KnotsRouter())
170
-
r.Mount("/spindles", s.SpindlesRouter())
169
+
170
+
r.Mount("/settings/knots", s.KnotsRouter())
171
+
r.Mount("/settings/spindles", s.SpindlesRouter())
172
+
171
173
r.Mount("/notifications", s.NotificationsRouter(mw))
172
174
173
175
r.Mount("/signup", s.SignupRouter())
+2
-2
docs/hacking.md
+2
-2
docs/hacking.md
···
121
121
with `ssh` exposed on port 2222.
122
122
123
123
Once the services are running, head to
124
-
http://localhost:3000/knots and hit verify. It should
124
+
http://localhost:3000/settings/knots and hit verify. It should
125
125
verify the ownership of the services instantly if everything
126
126
went smoothly.
127
127
···
146
146
### running a spindle
147
147
148
148
The above VM should already be running a spindle on
149
-
`localhost:6555`. Head to http://localhost:3000/spindles and
149
+
`localhost:6555`. Head to http://localhost:3000/settings/spindles and
150
150
hit verify. You can then configure each repository to use
151
151
this spindle and run CI jobs.
152
152
+1
-1
docs/knot-hosting.md
+1
-1
docs/knot-hosting.md
···
131
131
132
132
You should now have a running knot server! You can finalize
133
133
your registration by hitting the `verify` button on the
134
-
[/knots](https://tangled.org/knots) page. This simply creates
134
+
[/settings/knots](https://tangled.org/settings/knots) page. This simply creates
135
135
a record on your PDS to announce the existence of the knot.
136
136
137
137
### custom paths
+3
-3
docs/migrations.md
+3
-3
docs/migrations.md
···
14
14
For knots:
15
15
16
16
- Upgrade to latest tag (v1.9.0 or above)
17
-
- Head to the [knot dashboard](https://tangled.org/knots) and
17
+
- Head to the [knot dashboard](https://tangled.org/settings/knots) and
18
18
hit the "retry" button to verify your knot
19
19
20
20
For spindles:
21
21
22
22
- Upgrade to latest tag (v1.9.0 or above)
23
23
- Head to the [spindle
24
-
dashboard](https://tangled.org/spindles) and hit the
24
+
dashboard](https://tangled.org/settings/spindles) and hit the
25
25
"retry" button to verify your spindle
26
26
27
27
## Upgrading from v1.7.x
···
41
41
[settings](https://tangled.org/settings) page.
42
42
- Restart your knot once you have replaced the environment
43
43
variable
44
-
- Head to the [knot dashboard](https://tangled.org/knots) and
44
+
- Head to the [knot dashboard](https://tangled.org/settings/knots) and
45
45
hit the "retry" button to verify your knot. This simply
46
46
writes a `sh.tangled.knot` record to your PDS.
47
47