+8
-9
appview/issues/issues.go
+8
-9
appview/issues/issues.go
···
129
}
130
131
rp.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{
132
-
LoggedInUser: user,
133
-
RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
134
-
Issue: issue,
135
-
CommentList: issue.CommentList(),
136
-
Backlinks: backlinks,
137
-
OrderedReactionKinds: models.OrderedReactionKinds,
138
-
Reactions: reactionMap,
139
-
UserReacted: userReactions,
140
-
LabelDefs: defs,
141
})
142
}
143
···
129
}
130
131
rp.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{
132
+
LoggedInUser: user,
133
+
RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
134
+
Issue: issue,
135
+
CommentList: issue.CommentList(),
136
+
Backlinks: backlinks,
137
+
Reactions: reactionMap,
138
+
UserReacted: userReactions,
139
+
LabelDefs: defs,
140
})
141
}
142
-15
appview/knots/knots.go
-15
appview/knots/knots.go
···
40
Knotstream *eventconsumer.Consumer
41
}
42
43
-
type tab = map[string]any
44
-
45
-
var (
46
-
knotsTabs []tab = []tab{
47
-
{"Name": "profile", "Icon": "user"},
48
-
{"Name": "keys", "Icon": "key"},
49
-
{"Name": "emails", "Icon": "mail"},
50
-
{"Name": "notifications", "Icon": "bell"},
51
-
{"Name": "knots", "Icon": "volleyball"},
52
-
{"Name": "spindles", "Icon": "spool"},
53
-
}
54
-
)
55
-
56
func (k *Knots) Router() http.Handler {
57
r := chi.NewRouter()
58
···
84
k.Pages.Knots(w, pages.KnotsParams{
85
LoggedInUser: user,
86
Registrations: registrations,
87
-
Tabs: knotsTabs,
88
Tab: "knots",
89
})
90
}
···
148
Members: members,
149
Repos: repoMap,
150
IsOwner: true,
151
-
Tabs: knotsTabs,
152
Tab: "knots",
153
})
154
}
···
40
Knotstream *eventconsumer.Consumer
41
}
42
43
func (k *Knots) Router() http.Handler {
44
r := chi.NewRouter()
45
···
71
k.Pages.Knots(w, pages.KnotsParams{
72
LoggedInUser: user,
73
Registrations: registrations,
74
Tab: "knots",
75
})
76
}
···
134
Members: members,
135
Repos: repoMap,
136
IsOwner: true,
137
Tab: "knots",
138
})
139
}
+29
-20
appview/pages/funcmap.go
+29
-20
appview/pages/funcmap.go
···
32
"tangled.org/core/crypto"
33
)
34
35
func (p *Pages) funcMap() template.FuncMap {
36
return template.FuncMap{
37
"split": func(s string) []string {
···
334
},
335
"deref": func(v any) any {
336
val := reflect.ValueOf(v)
337
-
if val.Kind() == reflect.Pointer && !val.IsNil() {
338
return val.Elem().Interface()
339
}
340
return nil
···
366
return p.AvatarUrl(handle, "")
367
},
368
"langColor": enry.GetColor,
369
-
"reverse": func(s any) any {
370
-
if s == nil {
371
-
return nil
372
-
}
373
-
374
-
v := reflect.ValueOf(s)
375
-
376
-
if v.Kind() != reflect.Slice {
377
-
return s
378
-
}
379
-
380
-
length := v.Len()
381
-
reversed := reflect.MakeSlice(v.Type(), length, length)
382
383
-
for i := range length {
384
-
reversed.Index(i).Set(v.Index(length - 1 - i))
385
-
}
386
-
387
-
return reversed.Interface()
388
-
},
389
"normalizeForHtmlId": func(s string) string {
390
normalized := strings.ReplaceAll(s, ":", "_")
391
normalized = strings.ReplaceAll(normalized, ".", "_")
···
397
return "error"
398
}
399
return fp
400
},
401
}
402
}
···
32
"tangled.org/core/crypto"
33
)
34
35
+
type tab map[string]string
36
+
37
func (p *Pages) funcMap() template.FuncMap {
38
return template.FuncMap{
39
"split": func(s string) []string {
···
336
},
337
"deref": func(v any) any {
338
val := reflect.ValueOf(v)
339
+
if val.Kind() == reflect.Ptr && !val.IsNil() {
340
return val.Elem().Interface()
341
}
342
return nil
···
368
return p.AvatarUrl(handle, "")
369
},
370
"langColor": enry.GetColor,
371
+
"layoutSide": func() string {
372
+
return "col-span-1 md:col-span-2 lg:col-span-3"
373
+
},
374
+
"layoutCenter": func() string {
375
+
return "col-span-1 md:col-span-8 lg:col-span-6"
376
+
},
377
378
"normalizeForHtmlId": func(s string) string {
379
normalized := strings.ReplaceAll(s, ":", "_")
380
normalized = strings.ReplaceAll(normalized, ".", "_")
···
386
return "error"
387
}
388
return fp
389
+
},
390
+
// constant values used to define a template
391
+
"const": func() map[string]any {
392
+
return map[string]any{
393
+
"OrderedReactionKinds": models.OrderedReactionKinds,
394
+
// would be great to have ordered maps right about now
395
+
"UserSettingsTabs": []tab{
396
+
{"Name": "profile", "Icon": "user"},
397
+
{"Name": "keys", "Icon": "key"},
398
+
{"Name": "emails", "Icon": "mail"},
399
+
{"Name": "notifications", "Icon": "bell"},
400
+
{"Name": "knots", "Icon": "volleyball"},
401
+
{"Name": "spindles", "Icon": "spool"},
402
+
},
403
+
"RepoSettingsTabs": []tab{
404
+
{"Name": "general", "Icon": "sliders-horizontal"},
405
+
{"Name": "access", "Icon": "users"},
406
+
{"Name": "pipelines", "Icon": "layers-2"},
407
+
},
408
+
}
409
},
410
}
411
}
+18
-36
appview/pages/pages.go
+18
-36
appview/pages/pages.go
···
336
337
type UserProfileSettingsParams struct {
338
LoggedInUser *oauth.User
339
-
Tabs []map[string]any
340
Tab string
341
}
342
···
375
type UserKeysSettingsParams struct {
376
LoggedInUser *oauth.User
377
PubKeys []models.PublicKey
378
-
Tabs []map[string]any
379
Tab string
380
}
381
···
386
type UserEmailsSettingsParams struct {
387
LoggedInUser *oauth.User
388
Emails []models.Email
389
-
Tabs []map[string]any
390
Tab string
391
}
392
···
397
type UserNotificationSettingsParams struct {
398
LoggedInUser *oauth.User
399
Preferences *models.NotificationPreferences
400
-
Tabs []map[string]any
401
Tab string
402
}
403
···
417
type KnotsParams struct {
418
LoggedInUser *oauth.User
419
Registrations []models.Registration
420
-
Tabs []map[string]any
421
Tab string
422
}
423
···
431
Members []string
432
Repos map[string][]models.Repo
433
IsOwner bool
434
-
Tabs []map[string]any
435
Tab string
436
}
437
···
450
type SpindlesParams struct {
451
LoggedInUser *oauth.User
452
Spindles []models.Spindle
453
-
Tabs []map[string]any
454
Tab string
455
}
456
···
460
461
type SpindleListingParams struct {
462
models.Spindle
463
-
Tabs []map[string]any
464
Tab string
465
}
466
···
473
Spindle models.Spindle
474
Members []string
475
Repos map[string][]models.Repo
476
-
Tabs []map[string]any
477
Tab string
478
}
479
···
881
SubscribedLabels map[string]struct{}
882
ShouldSubscribeAll bool
883
Active string
884
-
Tabs []map[string]any
885
Tab string
886
Branches []types.Branch
887
}
···
895
LoggedInUser *oauth.User
896
RepoInfo repoinfo.RepoInfo
897
Active string
898
-
Tabs []map[string]any
899
Tab string
900
Collaborators []Collaborator
901
}
···
909
LoggedInUser *oauth.User
910
RepoInfo repoinfo.RepoInfo
911
Active string
912
-
Tabs []map[string]any
913
Tab string
914
Spindles []string
915
CurrentSpindle string
···
947
Backlinks []models.RichReferenceLink
948
LabelDefs map[string]*models.LabelDefinition
949
950
-
OrderedReactionKinds []models.ReactionKind
951
-
Reactions map[models.ReactionKind]models.ReactionDisplayData
952
-
UserReacted map[models.ReactionKind]bool
953
}
954
955
func (p *Pages) RepoSingleIssue(w io.Writer, params RepoSingleIssueParams) error {
···
1103
MergeCheck types.MergeCheckResponse
1104
ResubmitCheck ResubmitResult
1105
Pipelines map[string]models.Pipeline
1106
-
Diff *types.NiceDiff
1107
-
DiffOpts types.DiffOpts
1108
1109
-
OrderedReactionKinds []models.ReactionKind
1110
-
Reactions map[models.ReactionKind]models.ReactionDisplayData
1111
-
UserReacted map[models.ReactionKind]bool
1112
1113
LabelDefs map[string]*models.LabelDefinition
1114
}
···
1119
}
1120
1121
type RepoPullPatchParams struct {
1122
-
LoggedInUser *oauth.User
1123
-
RepoInfo repoinfo.RepoInfo
1124
-
Pull *models.Pull
1125
-
Stack models.Stack
1126
-
Diff *types.NiceDiff
1127
-
Round int
1128
-
Submission *models.PullSubmission
1129
-
OrderedReactionKinds []models.ReactionKind
1130
-
DiffOpts types.DiffOpts
1131
}
1132
1133
// this name is a mouthful
···
1136
}
1137
1138
type RepoPullInterdiffParams struct {
1139
-
LoggedInUser *oauth.User
1140
-
RepoInfo repoinfo.RepoInfo
1141
-
Pull *models.Pull
1142
-
Round int
1143
-
Interdiff *patchutil.InterdiffResult
1144
-
OrderedReactionKinds []models.ReactionKind
1145
-
DiffOpts types.DiffOpts
1146
}
1147
1148
// this name is a mouthful
···
336
337
type UserProfileSettingsParams struct {
338
LoggedInUser *oauth.User
339
Tab string
340
}
341
···
374
type UserKeysSettingsParams struct {
375
LoggedInUser *oauth.User
376
PubKeys []models.PublicKey
377
Tab string
378
}
379
···
384
type UserEmailsSettingsParams struct {
385
LoggedInUser *oauth.User
386
Emails []models.Email
387
Tab string
388
}
389
···
394
type UserNotificationSettingsParams struct {
395
LoggedInUser *oauth.User
396
Preferences *models.NotificationPreferences
397
Tab string
398
}
399
···
413
type KnotsParams struct {
414
LoggedInUser *oauth.User
415
Registrations []models.Registration
416
Tab string
417
}
418
···
426
Members []string
427
Repos map[string][]models.Repo
428
IsOwner bool
429
Tab string
430
}
431
···
444
type SpindlesParams struct {
445
LoggedInUser *oauth.User
446
Spindles []models.Spindle
447
Tab string
448
}
449
···
453
454
type SpindleListingParams struct {
455
models.Spindle
456
Tab string
457
}
458
···
465
Spindle models.Spindle
466
Members []string
467
Repos map[string][]models.Repo
468
Tab string
469
}
470
···
872
SubscribedLabels map[string]struct{}
873
ShouldSubscribeAll bool
874
Active string
875
Tab string
876
Branches []types.Branch
877
}
···
885
LoggedInUser *oauth.User
886
RepoInfo repoinfo.RepoInfo
887
Active string
888
Tab string
889
Collaborators []Collaborator
890
}
···
898
LoggedInUser *oauth.User
899
RepoInfo repoinfo.RepoInfo
900
Active string
901
Tab string
902
Spindles []string
903
CurrentSpindle string
···
935
Backlinks []models.RichReferenceLink
936
LabelDefs map[string]*models.LabelDefinition
937
938
+
Reactions map[models.ReactionKind]models.ReactionDisplayData
939
+
UserReacted map[models.ReactionKind]bool
940
}
941
942
func (p *Pages) RepoSingleIssue(w io.Writer, params RepoSingleIssueParams) error {
···
1090
MergeCheck types.MergeCheckResponse
1091
ResubmitCheck ResubmitResult
1092
Pipelines map[string]models.Pipeline
1093
1094
+
Reactions map[models.ReactionKind]models.ReactionDisplayData
1095
+
UserReacted map[models.ReactionKind]bool
1096
1097
LabelDefs map[string]*models.LabelDefinition
1098
}
···
1103
}
1104
1105
type RepoPullPatchParams struct {
1106
+
LoggedInUser *oauth.User
1107
+
RepoInfo repoinfo.RepoInfo
1108
+
Pull *models.Pull
1109
+
Stack models.Stack
1110
+
Diff *types.NiceDiff
1111
+
Round int
1112
+
Submission *models.PullSubmission
1113
+
DiffOpts types.DiffOpts
1114
}
1115
1116
// this name is a mouthful
···
1119
}
1120
1121
type RepoPullInterdiffParams struct {
1122
+
LoggedInUser *oauth.User
1123
+
RepoInfo repoinfo.RepoInfo
1124
+
Pull *models.Pull
1125
+
Round int
1126
+
Interdiff *patchutil.InterdiffResult
1127
+
DiffOpts types.DiffOpts
1128
}
1129
1130
// this name is a mouthful
+1
-1
appview/pages/templates/layouts/repobase.html
+1
-1
appview/pages/templates/layouts/repobase.html
+50
appview/pages/templates/repo/fragments/reactions.html
+50
appview/pages/templates/repo/fragments/reactions.html
···
···
1
+
{{ define "repo/fragments/reactions" }}
2
+
<div class="flex flex-wrap items-center gap-2">
3
+
{{- $reactions := .Reactions -}}
4
+
{{- $userReacted := .UserReacted -}}
5
+
{{- $threadAt := .ThreadAt -}}
6
+
7
+
{{ template "reactionsPopup" }}
8
+
{{ range $kind := const.OrderedReactionKinds }}
9
+
{{ $reactionData := index $reactions $kind }}
10
+
{{ template "repo/fragments/reaction"
11
+
(dict
12
+
"Kind" $kind
13
+
"Count" $reactionData.Count
14
+
"IsReacted" (index $userReacted $kind)
15
+
"ThreadAt" $threadAt
16
+
"Users" $reactionData.Users) }}
17
+
{{ end }}
18
+
</div>
19
+
{{ end }}
20
+
21
+
{{ define "reactionsPopup" }}
22
+
<details
23
+
id="reactionsPopUp"
24
+
class="relative inline-block"
25
+
>
26
+
<summary
27
+
class="flex justify-center items-center min-w-8 min-h-8 rounded border border-gray-200 dark:border-gray-700
28
+
hover:bg-gray-50
29
+
hover:border-gray-300
30
+
dark:hover:bg-gray-700
31
+
dark:hover:border-gray-600
32
+
cursor-pointer list-none"
33
+
>
34
+
{{ i "smile" "size-4" }}
35
+
</summary>
36
+
<div
37
+
class="absolute flex left-0 z-10 mt-4 rounded bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700 shadow-lg"
38
+
>
39
+
{{ range $kind := const.OrderedReactionKinds }}
40
+
<button
41
+
id="reactBtn-{{ $kind }}"
42
+
class="size-12 hover:bg-gray-100 dark:hover:bg-gray-700"
43
+
hx-on:click="this.parentElement.parentElement.removeAttribute('open')"
44
+
>
45
+
{{ $kind }}
46
+
</button>
47
+
{{ end }}
48
+
</div>
49
+
</details>
50
+
{{ end }}
-30
appview/pages/templates/repo/fragments/reactionsPopUp.html
-30
appview/pages/templates/repo/fragments/reactionsPopUp.html
···
1
-
{{ define "repo/fragments/reactionsPopUp" }}
2
-
<details
3
-
id="reactionsPopUp"
4
-
class="relative inline-block"
5
-
>
6
-
<summary
7
-
class="flex justify-center items-center min-w-8 min-h-8 rounded border border-gray-200 dark:border-gray-700
8
-
hover:bg-gray-50
9
-
hover:border-gray-300
10
-
dark:hover:bg-gray-700
11
-
dark:hover:border-gray-600
12
-
cursor-pointer list-none"
13
-
>
14
-
{{ i "smile" "size-4" }}
15
-
</summary>
16
-
<div
17
-
class="absolute flex left-0 z-10 mt-4 rounded bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700 shadow-lg"
18
-
>
19
-
{{ range $kind := . }}
20
-
<button
21
-
id="reactBtn-{{ $kind }}"
22
-
class="size-12 hover:bg-gray-100 dark:hover:bg-gray-700"
23
-
hx-on:click="this.parentElement.parentElement.removeAttribute('open')"
24
-
>
25
-
{{ $kind }}
26
-
</button>
27
-
{{ end }}
28
-
</div>
29
-
</details>
30
-
{{ end }}
···
+22
-35
appview/pages/templates/repo/issues/fragments/commentList.html
+22
-35
appview/pages/templates/repo/issues/fragments/commentList.html
···
1
{{ define "repo/issues/fragments/commentList" }}
2
-
<div class="flex flex-col gap-4">
3
{{ range $item := .CommentList }}
4
{{ template "commentListing" (list $ .) }}
5
{{ end }}
···
19
<div class="rounded border border-gray-200 dark:border-gray-700 w-full overflow-hidden shadow-sm bg-gray-50 dark:bg-gray-800/50">
20
{{ template "topLevelComment" $params }}
21
22
-
<div class="relative ml-10 border-l-2 border-gray-200 dark:border-gray-700">
23
{{ range $index, $reply := $comment.Replies }}
24
-
<div class="-ml-4">
25
-
{{
26
-
template "replyComment"
27
-
(dict
28
-
"RepoInfo" $root.RepoInfo
29
-
"LoggedInUser" $root.LoggedInUser
30
-
"Issue" $root.Issue
31
-
"Comment" $reply)
32
-
}}
33
</div>
34
{{ end }}
35
</div>
···
39
{{ end }}
40
41
{{ define "topLevelComment" }}
42
-
<div class="rounded px-6 py-4 bg-white dark:bg-gray-800 flex gap-2 ">
43
-
<div class="flex-shrink-0">
44
-
<img
45
-
src="{{ tinyAvatar .Comment.Did }}"
46
-
alt=""
47
-
class="rounded-full size-8 mr-1 border-2 border-gray-100 dark:border-gray-900"
48
-
/>
49
-
</div>
50
-
<div class="flex-1 min-w-0">
51
-
{{ template "repo/issues/fragments/issueCommentHeader" . }}
52
-
{{ template "repo/issues/fragments/issueCommentBody" . }}
53
-
</div>
54
</div>
55
{{ end }}
56
57
{{ define "replyComment" }}
58
-
<div class="py-4 pr-4 w-full mx-auto overflow-hidden flex gap-2 ">
59
-
<div class="flex-shrink-0">
60
-
<img
61
-
src="{{ tinyAvatar .Comment.Did }}"
62
-
alt=""
63
-
class="rounded-full size-8 mr-1 border-2 border-gray-100 dark:border-gray-900"
64
-
/>
65
-
</div>
66
-
<div class="flex-1 min-w-0">
67
-
{{ template "repo/issues/fragments/issueCommentHeader" . }}
68
-
{{ template "repo/issues/fragments/issueCommentBody" . }}
69
-
</div>
70
</div>
71
{{ end }}
···
1
{{ define "repo/issues/fragments/commentList" }}
2
+
<div class="flex flex-col gap-8">
3
{{ range $item := .CommentList }}
4
{{ template "commentListing" (list $ .) }}
5
{{ end }}
···
19
<div class="rounded border border-gray-200 dark:border-gray-700 w-full overflow-hidden shadow-sm bg-gray-50 dark:bg-gray-800/50">
20
{{ template "topLevelComment" $params }}
21
22
+
<div class="relative ml-4 border-l-2 border-gray-200 dark:border-gray-700">
23
{{ range $index, $reply := $comment.Replies }}
24
+
<div class="relative ">
25
+
<!-- Horizontal connector -->
26
+
<div class="absolute left-0 top-6 w-4 h-1 bg-gray-200 dark:bg-gray-700"></div>
27
+
28
+
<div class="pl-2">
29
+
{{
30
+
template "replyComment"
31
+
(dict
32
+
"RepoInfo" $root.RepoInfo
33
+
"LoggedInUser" $root.LoggedInUser
34
+
"Issue" $root.Issue
35
+
"Comment" $reply)
36
+
}}
37
+
</div>
38
</div>
39
{{ end }}
40
</div>
···
44
{{ end }}
45
46
{{ define "topLevelComment" }}
47
+
<div class="rounded px-6 py-4 bg-white dark:bg-gray-800">
48
+
{{ template "repo/issues/fragments/issueCommentHeader" . }}
49
+
{{ template "repo/issues/fragments/issueCommentBody" . }}
50
</div>
51
{{ end }}
52
53
{{ define "replyComment" }}
54
+
<div class="p-4 w-full mx-auto overflow-hidden">
55
+
{{ template "repo/issues/fragments/issueCommentHeader" . }}
56
+
{{ template "repo/issues/fragments/issueCommentBody" . }}
57
</div>
58
{{ end }}
+63
appview/pages/templates/repo/issues/fragments/globalIssueListing.html
+63
appview/pages/templates/repo/issues/fragments/globalIssueListing.html
···
···
1
+
{{ define "repo/issues/fragments/globalIssueListing" }}
2
+
<div class="flex flex-col gap-2">
3
+
{{ range .Issues }}
4
+
<div class="rounded drop-shadow-sm bg-white px-6 py-4 dark:bg-gray-800 dark:border-gray-700">
5
+
<div class="pb-2 mb-3">
6
+
<div class="flex items-center gap-3 mb-2">
7
+
<a
8
+
href="/{{ resolve .Repo.Did }}/{{ .Repo.Name }}"
9
+
class="text-blue-600 dark:text-blue-400 font-medium hover:underline text-sm"
10
+
>
11
+
{{ resolve .Repo.Did }}/{{ .Repo.Name }}
12
+
</a>
13
+
</div>
14
+
<a
15
+
href="/{{ resolve .Repo.Did }}/{{ .Repo.Name }}/issues/{{ .IssueId }}"
16
+
class="no-underline hover:underline"
17
+
>
18
+
{{ .Title | description }}
19
+
<span class="text-gray-500">#{{ .IssueId }}</span>
20
+
</a>
21
+
</div>
22
+
<div class="text-sm text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-1">
23
+
{{ $bgColor := "bg-gray-800 dark:bg-gray-700" }}
24
+
{{ $icon := "ban" }}
25
+
{{ $state := "closed" }}
26
+
{{ if .Open }}
27
+
{{ $bgColor = "bg-green-600 dark:bg-green-700" }}
28
+
{{ $icon = "circle-dot" }}
29
+
{{ $state = "open" }}
30
+
{{ end }}
31
+
32
+
<span class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm">
33
+
{{ i $icon "w-3 h-3 mr-1.5 text-white dark:text-white" }}
34
+
<span class="text-white dark:text-white">{{ $state }}</span>
35
+
</span>
36
+
37
+
<span class="ml-1">
38
+
{{ template "user/fragments/picHandleLink" .Did }}
39
+
</span>
40
+
41
+
<span class="before:content-['ยท']">
42
+
{{ template "repo/fragments/time" .Created }}
43
+
</span>
44
+
45
+
<span class="before:content-['ยท']">
46
+
{{ $s := "s" }}
47
+
{{ if eq (len .Comments) 1 }}
48
+
{{ $s = "" }}
49
+
{{ end }}
50
+
<a href="/{{ resolve .Repo.Did }}/{{ .Repo.Name }}/issues/{{ .IssueId }}" class="text-gray-500 dark:text-gray-400">{{ len .Comments }} comment{{$s}}</a>
51
+
</span>
52
+
53
+
{{ $state := .Labels }}
54
+
{{ range $k, $d := $.LabelDefs }}
55
+
{{ range $v, $s := $state.GetValSet $d.AtUri.String }}
56
+
{{ template "labels/fragments/label" (dict "def" $d "val" $v "withPrefix" true) }}
57
+
{{ end }}
58
+
{{ end }}
59
+
</div>
60
+
</div>
61
+
{{ end }}
62
+
</div>
63
+
{{ end }}
+1
-2
appview/pages/templates/repo/issues/fragments/issueCommentHeader.html
+1
-2
appview/pages/templates/repo/issues/fragments/issueCommentHeader.html
···
1
{{ define "repo/issues/fragments/issueCommentHeader" }}
2
<div class="flex flex-wrap items-center gap-2 text-sm text-gray-500 dark:text-gray-400 ">
3
-
{{ resolve .Comment.Did }}
4
{{ template "hats" $ }}
5
-
<span class="before:content-['ยท']"></span>
6
{{ template "timestamp" . }}
7
{{ $isCommentOwner := and .LoggedInUser (eq .LoggedInUser.Did .Comment.Did) }}
8
{{ if and $isCommentOwner (not .Comment.Deleted) }}
···
1
{{ define "repo/issues/fragments/issueCommentHeader" }}
2
<div class="flex flex-wrap items-center gap-2 text-sm text-gray-500 dark:text-gray-400 ">
3
+
{{ template "user/fragments/picHandleLink" .Comment.Did }}
4
{{ template "hats" $ }}
5
{{ template "timestamp" . }}
6
{{ $isCommentOwner := and .LoggedInUser (eq .LoggedInUser.Did .Comment.Did) }}
7
{{ if and $isCommentOwner (not .Comment.Deleted) }}
+2
-2
appview/pages/templates/repo/issues/fragments/issueListing.html
+2
-2
appview/pages/templates/repo/issues/fragments/issueListing.html
+1
-1
appview/pages/templates/repo/issues/fragments/putIssue.html
+1
-1
appview/pages/templates/repo/issues/fragments/putIssue.html
+3
-3
appview/pages/templates/repo/issues/fragments/replyIssueCommentPlaceholder.html
+3
-3
appview/pages/templates/repo/issues/fragments/replyIssueCommentPlaceholder.html
···
1
{{ define "repo/issues/fragments/replyIssueCommentPlaceholder" }}
2
-
<div class="py-2 px-6 border-t flex gap-2 items-center border-gray-300 dark:border-gray-700">
3
{{ if .LoggedInUser }}
4
<img
5
src="{{ tinyAvatar .LoggedInUser.Did }}"
6
alt=""
7
-
class="rounded-full size-8 mr-1 border-2 border-gray-300 dark:border-gray-700"
8
/>
9
{{ end }}
10
<input
11
-
class="w-full p-0 border-none focus:outline-none"
12
placeholder="Leave a reply..."
13
hx-get="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment/{{ .Comment.Id }}/reply"
14
hx-trigger="focus"
···
1
{{ define "repo/issues/fragments/replyIssueCommentPlaceholder" }}
2
+
<div class="p-2 border-t flex gap-2 items-center border-gray-300 dark:border-gray-700">
3
{{ if .LoggedInUser }}
4
<img
5
src="{{ tinyAvatar .LoggedInUser.Did }}"
6
alt=""
7
+
class="rounded-full h-6 w-6 mr-1 border border-gray-300 dark:border-gray-700"
8
/>
9
{{ end }}
10
<input
11
+
class="w-full py-2 border-none focus:outline-none"
12
placeholder="Leave a reply..."
13
hx-get="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment/{{ .Comment.Id }}/reply"
14
hx-trigger="focus"
+10
-26
appview/pages/templates/repo/issues/issue.html
+10
-26
appview/pages/templates/repo/issues/issue.html
···
35
{{ if .Issue.Body }}
36
<article id="body" class="mt-4 prose dark:prose-invert">{{ .Issue.Body | markdown }}</article>
37
{{ end }}
38
-
<div class="flex flex-wrap gap-2 items-stretch mt-4">
39
-
{{ template "issueReactions" . }}
40
</div>
41
</section>
42
{{ end }}
···
58
{{ $icon = "circle-dot" }}
59
{{ end }}
60
<div class="inline-flex items-center gap-2">
61
-
<span class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }}">
62
-
{{ i $icon "w-3 h-3 mr-1.5 text-white dark:text-white" }}
63
-
<span class="text-white dark:text-white text-sm">{{ .Issue.State }}</span>
64
-
</span>
65
-
66
<span class="text-gray-500 dark:text-gray-400 text-sm flex flex-wrap items-center gap-1">
67
opened by
68
{{ template "user/fragments/picHandleLink" .Issue.Did }}
···
106
{{ i "loader-circle" "size-3 animate-spin hidden group-[.htmx-request]:inline" }}
107
</a>
108
{{ end }}
109
-
110
-
{{ define "issueReactions" }}
111
-
<div class="flex items-center gap-2">
112
-
{{ template "repo/fragments/reactionsPopUp" .OrderedReactionKinds }}
113
-
{{ range $kind := .OrderedReactionKinds }}
114
-
{{ $reactionData := index $.Reactions $kind }}
115
-
{{
116
-
template "repo/fragments/reaction"
117
-
(dict
118
-
"Kind" $kind
119
-
"Count" $reactionData.Count
120
-
"IsReacted" (index $.UserReacted $kind)
121
-
"ThreadAt" $.Issue.AtUri
122
-
"Users" $reactionData.Users)
123
-
}}
124
-
{{ end }}
125
-
</div>
126
-
{{ end }}
127
-
128
129
{{ define "repoAfter" }}
130
<div class="flex flex-col gap-4 mt-4">
···
35
{{ if .Issue.Body }}
36
<article id="body" class="mt-4 prose dark:prose-invert">{{ .Issue.Body | markdown }}</article>
37
{{ end }}
38
+
<div class="mt-4">
39
+
{{ template "repo/fragments/reactions"
40
+
(dict "Reactions" .Reactions
41
+
"UserReacted" .UserReacted
42
+
"ThreadAt" .Issue.AtUri) }}
43
</div>
44
</section>
45
{{ end }}
···
61
{{ $icon = "circle-dot" }}
62
{{ end }}
63
<div class="inline-flex items-center gap-2">
64
+
<div id="state"
65
+
class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}">
66
+
{{ i $icon "w-4 h-4 mr-1.5 text-white" }}
67
+
<span class="text-white">{{ .Issue.State }}</span>
68
+
</div>
69
<span class="text-gray-500 dark:text-gray-400 text-sm flex flex-wrap items-center gap-1">
70
opened by
71
{{ template "user/fragments/picHandleLink" .Issue.Did }}
···
109
{{ i "loader-circle" "size-3 animate-spin hidden group-[.htmx-request]:inline" }}
110
</a>
111
{{ end }}
112
113
{{ define "repoAfter" }}
114
<div class="flex flex-col gap-4 mt-4">
+7
-7
appview/pages/templates/repo/pulls/fragments/pullActions.html
+7
-7
appview/pages/templates/repo/pulls/fragments/pullActions.html
···
22
{{ $isLastRound := eq $roundNumber $lastIdx }}
23
{{ $isSameRepoBranch := .Pull.IsBranchBased }}
24
{{ $isUpToDate := .ResubmitCheck.No }}
25
-
<div id="actions-{{$roundNumber}}" class="flex flex-wrap gap-2 relative py-2 px-4">
26
<button
27
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ $roundNumber }}/comment"
28
hx-target="#actions-{{$roundNumber}}"
29
hx-swap="outerHtml"
30
-
class="btn-flat p-2 flex items-center gap-2 no-underline hover:no-underline group">
31
{{ i "message-square-plus" "w-4 h-4" }}
32
<span>comment</span>
33
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
37
hx-delete="/{{ .BranchDeleteStatus.Repo.Did }}/{{ .BranchDeleteStatus.Repo.Name }}/branches"
38
hx-vals='{"branch": "{{ .BranchDeleteStatus.Branch }}" }'
39
hx-swap="none"
40
-
class="btn-flat p-2 flex items-center gap-2 no-underline hover:no-underline group text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300">
41
{{ i "git-branch" "w-4 h-4" }}
42
<span>delete branch</span>
43
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
52
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
53
hx-swap="none"
54
hx-confirm="Are you sure you want to merge pull #{{ .Pull.PullId }} into the `{{ .Pull.TargetBranch }}` branch?"
55
-
class="btn-flat p-2 flex items-center gap-2 group" {{ $disabled }}>
56
{{ i "git-merge" "w-4 h-4" }}
57
<span>merge{{if $stackCount}} {{$stackCount}}{{end}}</span>
58
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
74
{{ end }}
75
76
hx-disabled-elt="#resubmitBtn"
77
-
class="btn-flat p-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed group" {{ $disabled }}
78
79
{{ if $disabled }}
80
title="Update this branch to resubmit this pull request"
···
92
<button
93
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/close"
94
hx-swap="none"
95
-
class="btn-flat p-2 flex items-center gap-2 group">
96
{{ i "ban" "w-4 h-4" }}
97
<span>close</span>
98
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
103
<button
104
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/reopen"
105
hx-swap="none"
106
-
class="btn-flat p-2 flex items-center gap-2 group">
107
{{ i "refresh-ccw-dot" "w-4 h-4" }}
108
<span>reopen</span>
109
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
22
{{ $isLastRound := eq $roundNumber $lastIdx }}
23
{{ $isSameRepoBranch := .Pull.IsBranchBased }}
24
{{ $isUpToDate := .ResubmitCheck.No }}
25
+
<div id="actions-{{$roundNumber}}" class="flex flex-wrap gap-2 relative">
26
<button
27
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ $roundNumber }}/comment"
28
hx-target="#actions-{{$roundNumber}}"
29
hx-swap="outerHtml"
30
+
class="btn p-2 flex items-center gap-2 no-underline hover:no-underline group">
31
{{ i "message-square-plus" "w-4 h-4" }}
32
<span>comment</span>
33
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
37
hx-delete="/{{ .BranchDeleteStatus.Repo.Did }}/{{ .BranchDeleteStatus.Repo.Name }}/branches"
38
hx-vals='{"branch": "{{ .BranchDeleteStatus.Branch }}" }'
39
hx-swap="none"
40
+
class="btn p-2 flex items-center gap-2 no-underline hover:no-underline group text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300">
41
{{ i "git-branch" "w-4 h-4" }}
42
<span>delete branch</span>
43
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
52
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
53
hx-swap="none"
54
hx-confirm="Are you sure you want to merge pull #{{ .Pull.PullId }} into the `{{ .Pull.TargetBranch }}` branch?"
55
+
class="btn p-2 flex items-center gap-2 group" {{ $disabled }}>
56
{{ i "git-merge" "w-4 h-4" }}
57
<span>merge{{if $stackCount}} {{$stackCount}}{{end}}</span>
58
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
74
{{ end }}
75
76
hx-disabled-elt="#resubmitBtn"
77
+
class="btn p-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed group" {{ $disabled }}
78
79
{{ if $disabled }}
80
title="Update this branch to resubmit this pull request"
···
92
<button
93
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/close"
94
hx-swap="none"
95
+
class="btn p-2 flex items-center gap-2 group">
96
{{ i "ban" "w-4 h-4" }}
97
<span>close</span>
98
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
···
103
<button
104
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/reopen"
105
hx-swap="none"
106
+
class="btn p-2 flex items-center gap-2 group">
107
{{ i "refresh-ccw-dot" "w-4 h-4" }}
108
<span>reopen</span>
109
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
+12
-22
appview/pages/templates/repo/pulls/fragments/pullHeader.html
+12
-22
appview/pages/templates/repo/pulls/fragments/pullHeader.html
···
1
{{ define "repo/pulls/fragments/pullHeader" }}
2
-
<header class="pb-2">
3
<h1 class="text-2xl dark:text-white">
4
{{ .Pull.Title | description }}
5
<span class="text-gray-500 dark:text-gray-400">#{{ .Pull.PullId }}</span>
···
17
{{ $icon = "git-merge" }}
18
{{ end }}
19
20
-
<section>
21
<div class="flex items-center gap-2">
22
-
<span
23
-
class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm"
24
>
25
-
{{ i $icon "w-3 h-3 mr-1.5 text-white" }}
26
<span class="text-white">{{ .Pull.State.String }}</span>
27
-
</span>
28
<span class="text-gray-500 dark:text-gray-400 text-sm flex flex-wrap items-center gap-1">
29
opened by
30
{{ template "user/fragments/picHandleLink" .Pull.OwnerDid }}
···
63
</article>
64
{{ end }}
65
66
-
{{ with .OrderedReactionKinds }}
67
-
<div class="flex items-center gap-2 mt-2">
68
-
{{ template "repo/fragments/reactionsPopUp" . }}
69
-
{{ range $kind := . }}
70
-
{{ $reactionData := index $.Reactions $kind }}
71
-
{{
72
-
template "repo/fragments/reaction"
73
-
(dict
74
-
"Kind" $kind
75
-
"Count" $reactionData.Count
76
-
"IsReacted" (index $.UserReacted $kind)
77
-
"ThreadAt" $.Pull.AtUri
78
-
"Users" $reactionData.Users)
79
-
}}
80
-
{{ end }}
81
</div>
82
-
{{ end }}
83
</section>
84
85
···
1
{{ define "repo/pulls/fragments/pullHeader" }}
2
+
<header class="pb-4">
3
<h1 class="text-2xl dark:text-white">
4
{{ .Pull.Title | description }}
5
<span class="text-gray-500 dark:text-gray-400">#{{ .Pull.PullId }}</span>
···
17
{{ $icon = "git-merge" }}
18
{{ end }}
19
20
+
<section class="mt-2">
21
<div class="flex items-center gap-2">
22
+
<div
23
+
id="state"
24
+
class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}"
25
>
26
+
{{ i $icon "w-4 h-4 mr-1.5 text-white" }}
27
<span class="text-white">{{ .Pull.State.String }}</span>
28
+
</div>
29
<span class="text-gray-500 dark:text-gray-400 text-sm flex flex-wrap items-center gap-1">
30
opened by
31
{{ template "user/fragments/picHandleLink" .Pull.OwnerDid }}
···
64
</article>
65
{{ end }}
66
67
+
<div class="mt-2">
68
+
{{ template "repo/fragments/reactions"
69
+
(dict "Reactions" .Reactions
70
+
"UserReacted" .UserReacted
71
+
"ThreadAt" .Pull.AtUri) }}
72
</div>
73
</section>
74
75
+1
-1
appview/pages/templates/repo/pulls/fragments/pullNewComment.html
+1
-1
appview/pages/templates/repo/pulls/fragments/pullNewComment.html
-20
appview/pages/templates/repo/pulls/fragments/replyPullCommentPlaceholder.html
-20
appview/pages/templates/repo/pulls/fragments/replyPullCommentPlaceholder.html
···
1
-
{{ define "repo/pulls/fragments/replyPullCommentPlaceholder" }}
2
-
<div class="py-2 px-6 border-t flex gap-2 items-center border-gray-300 dark:border-gray-700">
3
-
{{ if .LoggedInUser }}
4
-
<img
5
-
src="{{ tinyAvatar .LoggedInUser.Did }}"
6
-
alt=""
7
-
class="rounded-full size-8 mr-1 border-2 border-gray-300 dark:border-gray-700"
8
-
/>
9
-
{{ end }}
10
-
<input
11
-
class="w-full p-0 border-none focus:outline-none"
12
-
placeholder="Leave a reply..."
13
-
hx-get="/{{ .Submission.ID }}/reply"
14
-
hx-trigger="focus"
15
-
hx-target="closest div"
16
-
hx-swap="outerHTML"
17
-
>
18
-
</input>
19
-
</div>
20
-
{{ end }}
···
+28
-235
appview/pages/templates/repo/pulls/pull.html
+28
-235
appview/pages/templates/repo/pulls/pull.html
···
6
{{ template "repo/pulls/fragments/og" (dict "RepoInfo" .RepoInfo "Pull" .Pull) }}
7
{{ end }}
8
9
-
{{ define "mainLayout" }}
10
-
<div class="px-1 col-span-full flex-grow flex flex-col gap-4">
11
-
{{ block "contentLayout" . }}
12
-
{{ block "content" . }}{{ end }}
13
-
{{ end }}
14
-
</div>
15
-
{{ end }}
16
-
17
{{ define "repoContentLayout" }}
18
<div class="grid grid-cols-1 md:grid-cols-10 gap-4 w-full">
19
-
<div class="col-span-1 md:col-span-7">
20
-
<section class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto dark:text-white h-full">
21
{{ block "repoContent" . }}{{ end }}
22
</section>
23
{{ block "repoAfter" . }}{{ end }}
24
</div>
25
-
<div class="col-span-1 md:col-span-3 flex flex-col gap-6">
26
{{ template "repo/fragments/labelPanel"
27
(dict "RepoInfo" $.RepoInfo
28
"Defs" $.LabelDefs
···
34
"Backlinks" $.Backlinks) }}
35
{{ template "repo/fragments/externalLinkPanel" $.Pull.AtUri }}
36
</div>
37
-
38
-
<div class="col-span-1 md:col-span-7">
39
-
{{ template "repo/fragments/diff" (list .Diff .DiffOpts) }}
40
-
</div>
41
-
<div class="col-span-1 md:col-span-3 flex flex-col max-h-dvh sticky top-0">
42
-
<div class="z-20 sticky top-0 rounded-t p-3 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700">
43
-
<h2 class="font-bold uppercase">history</h2>
44
-
</div>
45
-
<div class="flex flex-col-reverse gap-4 overflow-y-auto">
46
-
{{ template "submissions2" . }}
47
-
</div>
48
-
</div>
49
</div>
50
{{ end }}
51
···
60
{{ end }}
61
62
{{ define "repoAfter" }}
63
-
<div id="pull-close"></div>
64
-
<div id="pull-reopen"></div>
65
-
{{ end }}
66
-
67
-
{{ define "submissions2" }}
68
-
{{ $lastIdx := sub (len .Pull.Submissions) 1 }}
69
-
{{ range $ridx, $item := reverse .Pull.Submissions }}
70
-
{{ $idx := sub $lastIdx $ridx }}
71
-
<div class="rounded border border-gray-200 dark:border-gray-700 w-full shadow-sm bg-gray-50 dark:bg-gray-800/50">
72
-
{{ with $item }}
73
-
{{ $patches := .AsFormatPatch }}
74
-
{{ $round := .RoundNumber }}
75
-
<div class="rounded px-6 py-4 bg-white dark:bg-gray-800 flex gap-2">
76
-
<div class="flex-shrink-0">
77
-
<img
78
-
src="{{ tinyAvatar $.Pull.OwnerDid }}"
79
-
alt=""
80
-
class="rounded-full size-8 mr-1 border-2 border-gray-100 dark:border-gray-900"
81
-
/>
82
-
</div>
83
-
<!-- right column: name and body in two rows -->
84
-
<div class="flex-1 min-w-0 flex flex-col gap-2">
85
-
<div class="flex gap-2 items-center justify-between mb-1">
86
-
<span class="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 hover:text-gray-500">
87
-
{{ resolve $.Pull.OwnerDid }} submitted v{{ $round }}
88
-
<span class="select-none before:content-['\00B7']"></span>
89
-
<a class="text-gray-500 dark:text-gray-400 hover:text-gray-500" href="#round-#{{ $round }}">{{ template "repo/fragments/shortTimeAgo" .Created }}</a>
90
-
</span>
91
-
{{ if ne $idx 0 }}
92
-
<a class="flex items-center gap-2 no-underline hover:no-underline text-sm"
93
-
hx-boost="true"
94
-
href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{$round}}/interdiff">
95
-
{{ i "chevrons-left-right-ellipsis" "w-4 h-4 rotate-90" }}
96
-
<span class="hidden md:inline">interdiff</span>
97
-
</a>
98
-
{{ end }}
99
-
</div>
100
-
<div>
101
-
{{ if eq 1 (len $patches) }}
102
-
<!-- only one commit, just inline the message into the round header -->
103
-
{{ $commit := index $patches 0 }}
104
-
<span>{{ $commit.Title | description }}</span>
105
-
{{ if gt (len $commit.Body) 0 }}
106
-
<p id="body-{{$round}}-{{$commit.SHA}}" class="mt-1 pb-2">
107
-
{{ nl2br $commit.Body }}
108
-
</p>
109
-
{{ end }}
110
-
{{ else }}
111
-
<span>Commits:</span>
112
-
{{ range $patches }}
113
-
<div id="commit-{{.SHA}}" class="py-1 px-2 relative w-full md:max-w-3/5 md:w-fit flex flex-col">
114
-
<div class="flex items-center gap-2">
115
-
{{ i "git-commit-horizontal" "w-4 h-4 flex-shrink-0" }}
116
-
<div class="flex items-center">
117
-
<span>{{ .Title | description }}</span>
118
-
{{ if gt (len .Body) 0 }}
119
-
<button
120
-
class="py-1/2 px-1 mx-2 bg-gray-200 hover:bg-gray-400 rounded dark:bg-gray-700 dark:hover:bg-gray-600"
121
-
hx-on:click="document.getElementById('body-{{$round}}-{{.SHA}}').classList.toggle('hidden')"
122
-
>
123
-
{{ i "ellipsis" "w-3 h-3" }}
124
-
</button>
125
-
{{ end }}
126
-
</div>
127
-
</div>
128
-
{{ if gt (len .Body) 0 }}
129
-
<p id="body-{{$round}}-{{.SHA}}" class="hidden mt-1 text-sm pb-2">
130
-
{{ nl2br .Body }}
131
-
</p>
132
-
{{ end }}
133
-
</div>
134
-
{{ end }}
135
-
{{ end }}
136
-
</div>
137
-
<div>
138
-
{{ block "pipelineStatus" (list $ .) }} {{ end }}
139
-
</div>
140
-
</div>
141
-
</div>
142
-
<div class="relative ml-10 border-l-2 border-gray-200 dark:border-gray-700">
143
-
{{ range $cidx, $c := .Comments }}
144
-
<div id="comment-{{$c.ID}}" class="flex gap-2 -ml-4 py-4 w-full mx-auto">
145
-
<!-- left column: profile picture -->
146
-
<div class="flex-shrink-0">
147
-
<img
148
-
src="{{ tinyAvatar $c.OwnerDid }}"
149
-
alt=""
150
-
class="rounded-full size-8 mr-1 border-2 border-gray-100 dark:border-gray-900"
151
-
/>
152
-
</div>
153
-
<!-- right column: name and body in two rows -->
154
-
<div class="flex-1 min-w-0">
155
-
<!-- Row 1: Author and timestamp -->
156
-
<div class="text-sm text-gray-500 dark:text-gray-400 flex items-center gap-1">
157
-
<span>{{ resolve $c.OwnerDid }}</span>
158
-
<span class="before:content-['ยท']"></span>
159
-
<a class="text-gray-500 dark:text-gray-400 hover:text-gray-500 dark:hover:text-gray-300" href="#comment-{{.ID}}">{{ template "repo/fragments/time" $c.Created }}</a>
160
-
</div>
161
-
<!-- Row 2: Body text -->
162
-
<div class="prose dark:prose-invert mt-1">
163
-
{{ $c.Body | markdown }}
164
-
</div>
165
-
</div>
166
-
</div>
167
-
{{ end }}
168
-
</div>
169
-
{{ end }}
170
-
{{ if eq $lastIdx .RoundNumber }}
171
-
{{ block "mergeStatus" $ }} {{ end }}
172
-
{{ block "resubmitStatus" $ }} {{ end }}
173
-
{{ end }}
174
-
{{ if $.LoggedInUser }}
175
-
{{ template "repo/pulls/fragments/pullActions"
176
-
(dict
177
-
"LoggedInUser" $.LoggedInUser
178
-
"Pull" $.Pull
179
-
"RepoInfo" $.RepoInfo
180
-
"RoundNumber" .RoundNumber
181
-
"MergeCheck" $.MergeCheck
182
-
"ResubmitCheck" $.ResubmitCheck
183
-
"BranchDeleteStatus" $.BranchDeleteStatus
184
-
"Stack" $.Stack) }}
185
-
{{ else }}
186
-
<div class="bg-amber-50 dark:bg-amber-900 border border-amber-500 rounded drop-shadow-sm p-2 relative flex gap-2 items-center">
187
-
<a href="/signup" class="btn-create py-0 hover:no-underline hover:text-white flex items-center gap-2">
188
-
sign up
189
-
</a>
190
-
<span class="text-gray-500 dark:text-gray-400">or</span>
191
-
<a href="/login" class="underline">login</a>
192
-
to add to the discussion
193
-
</div>
194
-
{{ end }}
195
-
</div>
196
-
{{ end }}
197
-
{{ end }}
198
-
199
-
{{ define "newComment" }}
200
-
{{ $root := index . 0 }}
201
-
{{ $submission := index . 1 }}
202
-
<form
203
-
id="comment-form"
204
-
hx-post="/{{ $root.RepoInfo.FullName }}/pulls/{{ $root.Pull.PullId }}/round/{{ $submission.RoundNumber }}/comment"
205
-
hx-on::after-request="if(event.detail.successful) this.reset()"
206
-
>
207
-
<div class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-4 px-4 relative w-full">
208
-
<div class="text-sm pb-2 text-gray-500 dark:text-gray-400">
209
-
{{ template "user/fragments/picHandleLink" $root.LoggedInUser.Did }}
210
</div>
211
-
<textarea
212
-
id="comment-textarea"
213
-
name="body"
214
-
class="w-full p-2 rounded border border-gray-200 dark:border-gray-700"
215
-
placeholder="Add to the discussion"
216
-
rows="8"
217
-
></textarea>
218
-
<div id="pull-comment"></div>
219
-
</div>
220
-
{{ template "replyActions" . }}
221
-
</form>
222
-
{{ end }}
223
224
-
{{ define "replyActions" }}
225
-
<div class="flex flex-wrap items-stretch justify-end gap-2 text-gray-500 dark:text-gray-400 text-sm">
226
-
{{ template "cancel" . }}
227
-
{{ template "reply" . }}
228
-
</div>
229
-
{{ end }}
230
-
231
-
{{ define "cancel" }}
232
-
<button
233
-
class="btn text-red-500 dark:text-red-400 flex gap-2 items-center group"
234
-
hx-get="TODO"
235
-
hx-target="TODO"
236
-
hx-swap="outerHTML">
237
-
{{ i "x" "size-4" }}
238
-
cancel
239
-
</button>
240
-
{{ end }}
241
-
242
-
{{ define "reply" }}
243
-
<button
244
-
id="TODO"
245
-
type="submit"
246
-
class="btn-create flex items-center gap-2 no-underline hover:no-underline">
247
-
{{ i "reply" "w-4 h-4 inline group-[.htmx-request]:hidden" }}
248
-
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
249
-
reply
250
-
</button>
251
{{ end }}
252
253
{{ define "submissions" }}
···
416
417
{{ define "mergeStatus" }}
418
{{ if .Pull.State.IsClosed }}
419
-
<div class="bg-gray-50 dark:bg-gray-700 border border-black dark:border-gray-500 rounded drop-shadow-sm px-6 py-2 relative">
420
<div class="flex items-center gap-2 text-black dark:text-white">
421
{{ i "ban" "w-4 h-4" }}
422
<span class="font-medium">closed without merging</span
···
424
</div>
425
</div>
426
{{ else if .Pull.State.IsMerged }}
427
-
<div class="bg-purple-50 dark:bg-purple-900 border border-purple-500 rounded drop-shadow-sm px-6 py-2 relative">
428
<div class="flex items-center gap-2 text-purple-500 dark:text-purple-300">
429
{{ i "git-merge" "w-4 h-4" }}
430
<span class="font-medium">pull request successfully merged</span
···
432
</div>
433
</div>
434
{{ else if .Pull.State.IsDeleted }}
435
-
<div class="bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative">
436
<div class="flex items-center gap-2 text-red-500 dark:text-red-300">
437
{{ i "git-pull-request-closed" "w-4 h-4" }}
438
<span class="font-medium">This pull has been deleted (possibly by jj abandon or jj squash)</span>
439
</div>
440
</div>
441
{{ else if and .MergeCheck .MergeCheck.Error }}
442
-
<div class="bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative">
443
<div class="flex items-center gap-2 text-red-500 dark:text-red-300">
444
{{ i "triangle-alert" "w-4 h-4" }}
445
<span class="font-medium">{{ .MergeCheck.Error }}</span>
446
</div>
447
</div>
448
{{ else if and .MergeCheck .MergeCheck.IsConflicted }}
449
-
<div class="bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative">
450
-
<details class="text-red-500 dark:text-red-300 group">
451
-
<summary class="flex items-center justify-between cursor-pointer list-none">
452
-
<div class="flex items-center gap-2 ">
453
-
{{ i "triangle-alert" "w-4 h-4" }}
454
-
<span class="font-medium">merge conflicts detected</span>
455
-
</div>
456
-
<div>
457
-
<span class="group-open:hidden inline">{{ i "chevrons-up-down" "w-4 h-4" }}</span>
458
-
<span class="hidden group-open:inline">{{ i "chevrons-down-up" "w-4 h-4" }}</span>
459
-
</div>
460
-
</summary>
461
{{ if gt (len .MergeCheck.Conflicts) 0 }}
462
-
<ul class="space-y-1 mt-2">
463
{{ range .MergeCheck.Conflicts }}
464
{{ if .Filename }}
465
-
<li class="flex items-center">
466
-
{{ i "file-warning" "inline-flex w-4 h-4 mr-1.5 text-red-500 dark:text-red-300 flex-shrink-0" }}
467
-
<span class="font-mono" style="word-break: keep-all; overflow-wrap: break-word;">{{ .Filename }}</span>
468
-
</li>
469
{{ else if .Reason }}
470
<li class="flex items-center">
471
{{ i "file-warning" "w-4 h-4 mr-1.5 text-red-500 dark:text-red-300" }}
···
475
{{ end }}
476
</ul>
477
{{ end }}
478
-
</details>
479
</div>
480
{{ else if .MergeCheck }}
481
-
<div class="bg-green-50 dark:bg-green-900 border border-green-500 rounded drop-shadow-sm px-6 py-2 relative">
482
<div class="flex items-center gap-2 text-green-500 dark:text-green-300">
483
{{ i "circle-check-big" "w-4 h-4" }}
484
<span class="font-medium">no conflicts, ready to merge</span>
···
489
490
{{ define "resubmitStatus" }}
491
{{ if .ResubmitCheck.Yes }}
492
-
<div class="bg-amber-50 dark:bg-amber-900 border border-amber-500 rounded drop-shadow-sm px-6 py-2 relative">
493
<div class="flex items-center gap-2 text-amber-500 dark:text-amber-300">
494
{{ i "triangle-alert" "w-4 h-4" }}
495
<span class="font-medium">this branch has been updated, consider resubmitting</span>
···
505
{{ with $pipeline }}
506
{{ $id := .Id }}
507
{{ if .Statuses }}
508
-
<span>Workflows:</span>
509
-
<div class=" grid grid-cols-1 bg-white dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700">
510
{{ range $name, $all := .Statuses }}
511
<a href="/{{ $root.RepoInfo.FullName }}/pipelines/{{ $id }}/workflow/{{ $name }}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25">
512
<div
···
6
{{ template "repo/pulls/fragments/og" (dict "RepoInfo" .RepoInfo "Pull" .Pull) }}
7
{{ end }}
8
9
{{ define "repoContentLayout" }}
10
<div class="grid grid-cols-1 md:grid-cols-10 gap-4 w-full">
11
+
<div class="col-span-1 md:col-span-8">
12
+
<section class="bg-white dark:bg-gray-800 p-6 rounded relative w-full mx-auto dark:text-white">
13
{{ block "repoContent" . }}{{ end }}
14
</section>
15
{{ block "repoAfter" . }}{{ end }}
16
</div>
17
+
<div class="col-span-1 md:col-span-2 flex flex-col gap-6">
18
{{ template "repo/fragments/labelPanel"
19
(dict "RepoInfo" $.RepoInfo
20
"Defs" $.LabelDefs
···
26
"Backlinks" $.Backlinks) }}
27
{{ template "repo/fragments/externalLinkPanel" $.Pull.AtUri }}
28
</div>
29
</div>
30
{{ end }}
31
···
40
{{ end }}
41
42
{{ define "repoAfter" }}
43
+
<section id="submissions" class="mt-4">
44
+
<div class="flex flex-col gap-4">
45
+
{{ block "submissions" . }} {{ end }}
46
</div>
47
+
</section>
48
49
+
<div id="pull-close"></div>
50
+
<div id="pull-reopen"></div>
51
{{ end }}
52
53
{{ define "submissions" }}
···
216
217
{{ define "mergeStatus" }}
218
{{ if .Pull.State.IsClosed }}
219
+
<div class="bg-gray-50 dark:bg-gray-700 border border-black dark:border-gray-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
220
<div class="flex items-center gap-2 text-black dark:text-white">
221
{{ i "ban" "w-4 h-4" }}
222
<span class="font-medium">closed without merging</span
···
224
</div>
225
</div>
226
{{ else if .Pull.State.IsMerged }}
227
+
<div class="bg-purple-50 dark:bg-purple-900 border border-purple-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
228
<div class="flex items-center gap-2 text-purple-500 dark:text-purple-300">
229
{{ i "git-merge" "w-4 h-4" }}
230
<span class="font-medium">pull request successfully merged</span
···
232
</div>
233
</div>
234
{{ else if .Pull.State.IsDeleted }}
235
+
<div class="bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
236
<div class="flex items-center gap-2 text-red-500 dark:text-red-300">
237
{{ i "git-pull-request-closed" "w-4 h-4" }}
238
<span class="font-medium">This pull has been deleted (possibly by jj abandon or jj squash)</span>
239
</div>
240
</div>
241
{{ else if and .MergeCheck .MergeCheck.Error }}
242
+
<div class="bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
243
<div class="flex items-center gap-2 text-red-500 dark:text-red-300">
244
{{ i "triangle-alert" "w-4 h-4" }}
245
<span class="font-medium">{{ .MergeCheck.Error }}</span>
246
</div>
247
</div>
248
{{ else if and .MergeCheck .MergeCheck.IsConflicted }}
249
+
<div class="bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
250
+
<div class="flex flex-col gap-2 text-red-500 dark:text-red-300">
251
+
<div class="flex items-center gap-2">
252
+
{{ i "triangle-alert" "w-4 h-4" }}
253
+
<span class="font-medium">merge conflicts detected</span>
254
+
</div>
255
{{ if gt (len .MergeCheck.Conflicts) 0 }}
256
+
<ul class="space-y-1">
257
{{ range .MergeCheck.Conflicts }}
258
{{ if .Filename }}
259
+
<li class="flex items-center">
260
+
{{ i "file-warning" "w-4 h-4 mr-1.5 text-red-500 dark:text-red-300" }}
261
+
<span class="font-mono">{{ .Filename }}</span>
262
+
</li>
263
{{ else if .Reason }}
264
<li class="flex items-center">
265
{{ i "file-warning" "w-4 h-4 mr-1.5 text-red-500 dark:text-red-300" }}
···
269
{{ end }}
270
</ul>
271
{{ end }}
272
+
</div>
273
</div>
274
{{ else if .MergeCheck }}
275
+
<div class="bg-green-50 dark:bg-green-900 border border-green-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
276
<div class="flex items-center gap-2 text-green-500 dark:text-green-300">
277
{{ i "circle-check-big" "w-4 h-4" }}
278
<span class="font-medium">no conflicts, ready to merge</span>
···
283
284
{{ define "resubmitStatus" }}
285
{{ if .ResubmitCheck.Yes }}
286
+
<div class="bg-amber-50 dark:bg-amber-900 border border-amber-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
287
<div class="flex items-center gap-2 text-amber-500 dark:text-amber-300">
288
{{ i "triangle-alert" "w-4 h-4" }}
289
<span class="font-medium">this branch has been updated, consider resubmitting</span>
···
299
{{ with $pipeline }}
300
{{ $id := .Id }}
301
{{ if .Statuses }}
302
+
<div class="max-w-80 grid grid-cols-1 bg-white dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700">
303
{{ range $name, $all := .Statuses }}
304
<a href="/{{ $root.RepoInfo.FullName }}/pipelines/{{ $id }}/workflow/{{ $name }}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25">
305
<div
+4
-14
appview/pulls/pulls.go
+4
-14
appview/pulls/pulls.go
···
232
defs[l.AtUri().String()] = &l
233
}
234
235
-
patch := pull.LatestSubmission().CombinedPatch()
236
-
diff := patchutil.AsNiceDiff(patch, pull.TargetBranch)
237
-
var diffOpts types.DiffOpts
238
-
if d := r.URL.Query().Get("diff"); d == "split" {
239
-
diffOpts.Split = true
240
-
}
241
-
242
-
log.Println(s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
243
LoggedInUser: user,
244
RepoInfo: s.repoResolver.GetRepoInfo(r, user),
245
Pull: pull,
···
250
MergeCheck: mergeCheckResponse,
251
ResubmitCheck: resubmitResult,
252
Pipelines: m,
253
-
Diff: &diff,
254
-
DiffOpts: diffOpts,
255
256
-
OrderedReactionKinds: models.OrderedReactionKinds,
257
-
Reactions: reactionMap,
258
-
UserReacted: userReactions,
259
260
LabelDefs: defs,
261
-
}))
262
}
263
264
func (s *Pulls) mergeCheck(r *http.Request, f *models.Repo, pull *models.Pull, stack models.Stack) types.MergeCheckResponse {
···
232
defs[l.AtUri().String()] = &l
233
}
234
235
+
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
236
LoggedInUser: user,
237
RepoInfo: s.repoResolver.GetRepoInfo(r, user),
238
Pull: pull,
···
243
MergeCheck: mergeCheckResponse,
244
ResubmitCheck: resubmitResult,
245
Pipelines: m,
246
247
+
Reactions: reactionMap,
248
+
UserReacted: userReactions,
249
250
LabelDefs: defs,
251
+
})
252
}
253
254
func (s *Pulls) mergeCheck(r *http.Request, f *models.Repo, pull *models.Pull, stack models.Stack) types.MergeCheckResponse {
-14
appview/repo/settings.go
-14
appview/repo/settings.go
···
22
indigoxrpc "github.com/bluesky-social/indigo/xrpc"
23
)
24
25
-
type tab = map[string]any
26
-
27
-
var (
28
-
// would be great to have ordered maps right about now
29
-
settingsTabs []tab = []tab{
30
-
{"Name": "general", "Icon": "sliders-horizontal"},
31
-
{"Name": "access", "Icon": "users"},
32
-
{"Name": "pipelines", "Icon": "layers-2"},
33
-
}
34
-
)
35
-
36
func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) {
37
l := rp.logger.With("handler", "SetDefaultBranch")
38
···
262
DefaultLabels: defaultLabels,
263
SubscribedLabels: subscribedLabels,
264
ShouldSubscribeAll: shouldSubscribeAll,
265
-
Tabs: settingsTabs,
266
Tab: "general",
267
})
268
}
···
308
rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{
309
LoggedInUser: user,
310
RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
311
-
Tabs: settingsTabs,
312
Tab: "access",
313
Collaborators: collaborators,
314
})
···
369
rp.pages.RepoPipelineSettings(w, pages.RepoPipelineSettingsParams{
370
LoggedInUser: user,
371
RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
372
-
Tabs: settingsTabs,
373
Tab: "pipelines",
374
Spindles: spindles,
375
CurrentSpindle: f.Spindle,
···
22
indigoxrpc "github.com/bluesky-social/indigo/xrpc"
23
)
24
25
func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) {
26
l := rp.logger.With("handler", "SetDefaultBranch")
27
···
251
DefaultLabels: defaultLabels,
252
SubscribedLabels: subscribedLabels,
253
ShouldSubscribeAll: shouldSubscribeAll,
254
Tab: "general",
255
})
256
}
···
296
rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{
297
LoggedInUser: user,
298
RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
299
Tab: "access",
300
Collaborators: collaborators,
301
})
···
356
rp.pages.RepoPipelineSettings(w, pages.RepoPipelineSettingsParams{
357
LoggedInUser: user,
358
RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
359
Tab: "pipelines",
360
Spindles: spindles,
361
CurrentSpindle: f.Spindle,
-17
appview/settings/settings.go
-17
appview/settings/settings.go
···
35
Config *config.Config
36
}
37
38
-
type tab = map[string]any
39
-
40
-
var (
41
-
settingsTabs []tab = []tab{
42
-
{"Name": "profile", "Icon": "user"},
43
-
{"Name": "keys", "Icon": "key"},
44
-
{"Name": "emails", "Icon": "mail"},
45
-
{"Name": "notifications", "Icon": "bell"},
46
-
{"Name": "knots", "Icon": "volleyball"},
47
-
{"Name": "spindles", "Icon": "spool"},
48
-
}
49
-
)
50
-
51
func (s *Settings) Router() http.Handler {
52
r := chi.NewRouter()
53
···
85
86
s.Pages.UserProfileSettings(w, pages.UserProfileSettingsParams{
87
LoggedInUser: user,
88
-
Tabs: settingsTabs,
89
Tab: "profile",
90
})
91
}
···
104
s.Pages.UserNotificationSettings(w, pages.UserNotificationSettingsParams{
105
LoggedInUser: user,
106
Preferences: prefs,
107
-
Tabs: settingsTabs,
108
Tab: "notifications",
109
})
110
}
···
146
s.Pages.UserKeysSettings(w, pages.UserKeysSettingsParams{
147
LoggedInUser: user,
148
PubKeys: pubKeys,
149
-
Tabs: settingsTabs,
150
Tab: "keys",
151
})
152
}
···
161
s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{
162
LoggedInUser: user,
163
Emails: emails,
164
-
Tabs: settingsTabs,
165
Tab: "emails",
166
})
167
}
···
35
Config *config.Config
36
}
37
38
func (s *Settings) Router() http.Handler {
39
r := chi.NewRouter()
40
···
72
73
s.Pages.UserProfileSettings(w, pages.UserProfileSettingsParams{
74
LoggedInUser: user,
75
Tab: "profile",
76
})
77
}
···
90
s.Pages.UserNotificationSettings(w, pages.UserNotificationSettingsParams{
91
LoggedInUser: user,
92
Preferences: prefs,
93
Tab: "notifications",
94
})
95
}
···
131
s.Pages.UserKeysSettings(w, pages.UserKeysSettingsParams{
132
LoggedInUser: user,
133
PubKeys: pubKeys,
134
Tab: "keys",
135
})
136
}
···
145
s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{
146
LoggedInUser: user,
147
Emails: emails,
148
Tab: "emails",
149
})
150
}
-15
appview/spindles/spindles.go
-15
appview/spindles/spindles.go
···
39
Logger *slog.Logger
40
}
41
42
-
type tab = map[string]any
43
-
44
-
var (
45
-
spindlesTabs []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
-
55
func (s *Spindles) Router() http.Handler {
56
r := chi.NewRouter()
57
···
83
s.Pages.Spindles(w, pages.SpindlesParams{
84
LoggedInUser: user,
85
Spindles: all,
86
-
Tabs: spindlesTabs,
87
Tab: "spindles",
88
})
89
}
···
143
Spindle: spindle,
144
Members: members,
145
Repos: repoMap,
146
-
Tabs: spindlesTabs,
147
Tab: "spindles",
148
})
149
}
···
39
Logger *slog.Logger
40
}
41
42
func (s *Spindles) Router() http.Handler {
43
r := chi.NewRouter()
44
···
70
s.Pages.Spindles(w, pages.SpindlesParams{
71
LoggedInUser: user,
72
Spindles: all,
73
Tab: "spindles",
74
})
75
}
···
129
Spindle: spindle,
130
Members: members,
131
Repos: repoMap,
132
Tab: "spindles",
133
})
134
}
+5
-6
docs/template.html
+5
-6
docs/template.html
-13
input.css
-13
input.css
···
124
dark:text-gray-100 dark:before:bg-gray-800 dark:before:border-gray-700;
125
}
126
127
-
.btn-flat {
128
-
@apply relative z-10 inline-flex min-h-[30px] cursor-pointer items-center justify-center
129
-
bg-transparent px-2 pb-[0.2rem] text-sm text-gray-900
130
-
before:absolute before:inset-0 before:-z-10 before:block before:rounded
131
-
before:border before:border-gray-200 before:bg-white
132
-
before:content-[''] before:transition-all before:duration-150 before:ease-in-out
133
-
hover:before:bg-gray-50
134
-
dark:hover:before:bg-gray-700
135
-
focus:outline-none focus-visible:before:outline focus-visible:before:outline-2 focus-visible:before:outline-gray-400
136
-
disabled:cursor-not-allowed disabled:opacity-50
137
-
dark:text-gray-100 dark:before:bg-gray-800 dark:before:border-gray-700;
138
-
}
139
-
140
.btn-create {
141
@apply btn text-white
142
before:bg-green-600 hover:before:bg-green-700