+180
appview/pages/templates/goodfirstissues/index.html
+180
appview/pages/templates/goodfirstissues/index.html
···
···
1
+
{{ define "title" }}good first issues{{ end }}
2
+
3
+
{{ define "extrameta" }}
4
+
<meta property="og:title" content="good first issues · tangled" />
5
+
<meta property="og:type" content="object" />
6
+
<meta property="og:url" content="https://tangled.org/goodfirstissues" />
7
+
<meta property="og:description" content="Find good first issues to contribute to open source projects" />
8
+
{{ end }}
9
+
10
+
{{ define "content" }}
11
+
<div class="grid grid-cols-10">
12
+
<header class="col-span-full md:col-span-10 px-6 py-2 mb-4">
13
+
<h1 class="text-2xl font-bold dark:text-white mb-1">Good First Issues</h1>
14
+
<p class="text-gray-600 dark:text-gray-400 mb-2">
15
+
Find beginner-friendly issues across all repositories to get started with open source contributions.
16
+
</p>
17
+
</header>
18
+
19
+
<div class="col-span-full md:col-span-10 space-y-6">
20
+
{{ if eq (len .RepoGroups) 0 }}
21
+
<div class="bg-white dark:bg-gray-800 drop-shadow-sm rounded p-6 md:px-10">
22
+
<div class="text-center py-16">
23
+
<div class="text-gray-500 dark:text-gray-400 mb-4">
24
+
{{ i "circle-dot" "w-16 h-16 mx-auto" }}
25
+
</div>
26
+
<h3 class="text-xl font-medium text-gray-900 dark:text-white mb-2">No good first issues available</h3>
27
+
<p class="text-gray-600 dark:text-gray-400 mb-3 max-w-md mx-auto">
28
+
There are currently no open issues labeled as "good-first-issue" across all repositories.
29
+
</p>
30
+
<p class="text-gray-500 dark:text-gray-500 text-sm max-w-md mx-auto">
31
+
Repository maintainers can add the "good-first-issue" label to beginner-friendly issues to help newcomers get started.
32
+
</p>
33
+
</div>
34
+
</div>
35
+
{{ else }}
36
+
{{ range .RepoGroups }}
37
+
<div class="mb-4 gap-1 flex flex-col drop-shadow-sm rounded bg-white dark:bg-gray-800">
38
+
<div class="flex px-6 pt-4 pb-2 flex-row gap-1">
39
+
<div class="font-medium dark:text-white flex items-center justify-between">
40
+
<div class="flex items-center min-w-0 flex-1 mr-2">
41
+
{{ if .Repo.Source }}
42
+
{{ i "git-fork" "w-4 h-4 mr-1.5 shrink-0" }}
43
+
{{ else }}
44
+
{{ i "book-marked" "w-4 h-4 mr-1.5 shrink-0" }}
45
+
{{ end }}
46
+
{{ $repoOwner := resolve .Repo.Did }}
47
+
<a href="/{{ $repoOwner }}/{{ .Repo.Name }}" class="truncate min-w-0">{{ $repoOwner }}/{{ .Repo.Name }}</a>
48
+
</div>
49
+
</div>
50
+
51
+
52
+
{{ if .Repo.RepoStats }}
53
+
<div class="text-gray-400 text-sm font-mono inline-flex gap-4 mt-auto">
54
+
{{ with .Repo.RepoStats.Language }}
55
+
<div class="flex gap-2 items-center text-sm">
56
+
{{ template "repo/fragments/colorBall" (dict "color" (langColor .)) }}
57
+
<span>{{ . }}</span>
58
+
</div>
59
+
{{ end }}
60
+
{{ with .Repo.RepoStats.StarCount }}
61
+
<div class="flex gap-1 items-center text-sm">
62
+
{{ i "star" "w-3 h-3 fill-current" }}
63
+
<span>{{ . }}</span>
64
+
</div>
65
+
{{ end }}
66
+
{{ with .Repo.RepoStats.IssueCount.Open }}
67
+
<div class="flex gap-1 items-center text-sm">
68
+
{{ i "circle-dot" "w-3 h-3" }}
69
+
<span>{{ . }}</span>
70
+
</div>
71
+
{{ end }}
72
+
{{ with .Repo.RepoStats.PullCount.Open }}
73
+
<div class="flex gap-1 items-center text-sm">
74
+
{{ i "git-pull-request" "w-3 h-3" }}
75
+
<span>{{ . }}</span>
76
+
</div>
77
+
{{ end }}
78
+
</div>
79
+
{{ end }}
80
+
</div>
81
+
82
+
{{ with .Repo.Description }}
83
+
<div class="pl-6 pb-2 text-gray-600 dark:text-gray-300 text-sm line-clamp-2">
84
+
{{ . | description }}
85
+
</div>
86
+
{{ end }}
87
+
88
+
{{ if gt (len .Issues) 0 }}
89
+
<details class="bg-white dark:bg-gray-800 group" open>
90
+
<summary class="py-4 px-6 text-xs list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
91
+
{{ $s := "s" }}
92
+
{{ if eq (len .Issues) 1 }}
93
+
{{ $s = "" }}
94
+
{{ end }}
95
+
<div class="group-open:hidden flex items-center gap-2">
96
+
{{ i "chevrons-up-down" "w-4 h-4" }} expand {{ len .Issues }} issue{{$s}} in this repo
97
+
</div>
98
+
<div class="hidden group-open:flex items-center gap-2">
99
+
{{ i "chevrons-down-up" "w-4 h-4" }} hide {{ len .Issues }} issue{{$s}} in this repo
100
+
</div>
101
+
</summary>
102
+
<div class="grid grid-cols-1 rounded-b border-b border-t border-gray-200 dark:border-gray-900 divide-y divide-gray-200 dark:divide-gray-900">
103
+
{{ range .Issues }}
104
+
<a href="/{{ resolve .Repo.Did }}/{{ .Repo.Name }}/issues/{{ .IssueId }}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25">
105
+
<div class="py-2 px-6">
106
+
<div class="flex-grow min-w-0 w-full">
107
+
<div class="flex text-sm items-center justify-between w-full">
108
+
<div class="flex items-center gap-2 min-w-0 flex-1 pr-2">
109
+
<span class="truncate text-sm text-gray-800 dark:text-gray-200">
110
+
<span class="text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span>
111
+
{{ .Title | description }}
112
+
</span>
113
+
</div>
114
+
<div class="flex-shrink-0 flex items-center gap-2 text-gray-500 dark:text-gray-400">
115
+
<span>
116
+
<div class="inline-flex items-center gap-1">
117
+
{{ i "message-square" "w-3 h-3 md:hidden" }}
118
+
{{ len .Comments }}
119
+
<span class="hidden md:inline">comment{{ if ne (len .Comments) 1 }}s{{ end }}</span>
120
+
</div>
121
+
</span>
122
+
<span class="before:content-['·'] before:select-none"></span>
123
+
<span class="text-xs">
124
+
{{ template "repo/fragments/time" .Created }}
125
+
</span>
126
+
<div class="hidden md:inline-flex md:gap-1">
127
+
{{ $labelState := .Labels }}
128
+
{{ range $k, $d := $.LabelDefs }}
129
+
{{ range $v, $s := $labelState.GetValSet $d.AtUri.String }}
130
+
{{ template "labels/fragments/label" (dict "def" $d "val" $v "withPrefix" true) }}
131
+
{{ end }}
132
+
{{ end }}
133
+
</div>
134
+
</div>
135
+
</div>
136
+
</div>
137
+
</div>
138
+
</a>
139
+
{{ end }}
140
+
</div>
141
+
</details>
142
+
{{ end }}
143
+
</div>
144
+
{{ end }}
145
+
146
+
{{ if or (gt .Page.Offset 0) (eq (len .RepoGroups) .Page.Limit) }}
147
+
<div class="flex justify-center mt-8">
148
+
<div class="flex gap-2">
149
+
{{ if gt .Page.Offset 0 }}
150
+
{{ $prev := .Page.Previous }}
151
+
<a
152
+
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
153
+
hx-boost="true"
154
+
href="/goodfirstissues?offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
155
+
>
156
+
{{ i "chevron-left" "w-4 h-4" }}
157
+
previous
158
+
</a>
159
+
{{ else }}
160
+
<div></div>
161
+
{{ end }}
162
+
163
+
{{ if eq (len .RepoGroups) .Page.Limit }}
164
+
{{ $next := .Page.Next }}
165
+
<a
166
+
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
167
+
hx-boost="true"
168
+
href="/goodfirstissues?offset={{ $next.Offset }}&limit={{ $next.Limit }}"
169
+
>
170
+
next
171
+
{{ i "chevron-right" "w-4 h-4" }}
172
+
</a>
173
+
{{ end }}
174
+
</div>
175
+
</div>
176
+
{{ end }}
177
+
{{ end }}
178
+
</div>
179
+
</div>
180
+
{{ 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 }}
+55
appview/pages/templates/repo/issues/fragments/issueListing.html
+55
appview/pages/templates/repo/issues/fragments/issueListing.html
···
···
1
+
{{ define "repo/issues/fragments/issueListing" }}
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">
6
+
<a
7
+
href="/{{ $.RepoPrefix }}/issues/{{ .IssueId }}"
8
+
class="no-underline hover:underline"
9
+
>
10
+
{{ .Title | description }}
11
+
<span class="text-gray-500">#{{ .IssueId }}</span>
12
+
</a>
13
+
</div>
14
+
<div class="text-sm text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-1">
15
+
{{ $bgColor := "bg-gray-800 dark:bg-gray-700" }}
16
+
{{ $icon := "ban" }}
17
+
{{ $state := "closed" }}
18
+
{{ if .Open }}
19
+
{{ $bgColor = "bg-green-600 dark:bg-green-700" }}
20
+
{{ $icon = "circle-dot" }}
21
+
{{ $state = "open" }}
22
+
{{ end }}
23
+
24
+
<span class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm">
25
+
{{ i $icon "w-3 h-3 mr-1.5 text-white dark:text-white" }}
26
+
<span class="text-white dark:text-white">{{ $state }}</span>
27
+
</span>
28
+
29
+
<span class="ml-1">
30
+
{{ template "user/fragments/picHandleLink" .Did }}
31
+
</span>
32
+
33
+
<span class="before:content-['·']">
34
+
{{ template "repo/fragments/time" .Created }}
35
+
</span>
36
+
37
+
<span class="before:content-['·']">
38
+
{{ $s := "s" }}
39
+
{{ if eq (len .Comments) 1 }}
40
+
{{ $s = "" }}
41
+
{{ end }}
42
+
<a href="/{{ $.RepoPrefix }}/issues/{{ .IssueId }}" class="text-gray-500 dark:text-gray-400">{{ len .Comments }} comment{{$s}}</a>
43
+
</span>
44
+
45
+
{{ $state := .Labels }}
46
+
{{ range $k, $d := $.LabelDefs }}
47
+
{{ range $v, $s := $state.GetValSet $d.AtUri.String }}
48
+
{{ template "labels/fragments/label" (dict "def" $d "val" $v "withPrefix" true) }}
49
+
{{ end }}
50
+
{{ end }}
51
+
</div>
52
+
</div>
53
+
{{ end }}
54
+
</div>
55
+
{{ end }}
+2
-52
appview/pages/templates/repo/issues/issues.html
+2
-52
appview/pages/templates/repo/issues/issues.html
···
37
{{ end }}
38
39
{{ define "repoAfter" }}
40
-
<div class="flex flex-col gap-2 mt-2">
41
-
{{ range .Issues }}
42
-
<div class="rounded drop-shadow-sm bg-white px-6 py-4 dark:bg-gray-800 dark:border-gray-700">
43
-
<div class="pb-2">
44
-
<a
45
-
href="/{{ $.RepoInfo.FullName }}/issues/{{ .IssueId }}"
46
-
class="no-underline hover:underline"
47
-
>
48
-
{{ .Title | description }}
49
-
<span class="text-gray-500">#{{ .IssueId }}</span>
50
-
</a>
51
-
</div>
52
-
<div class="text-sm text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-1">
53
-
{{ $bgColor := "bg-gray-800 dark:bg-gray-700" }}
54
-
{{ $icon := "ban" }}
55
-
{{ $state := "closed" }}
56
-
{{ if .Open }}
57
-
{{ $bgColor = "bg-green-600 dark:bg-green-700" }}
58
-
{{ $icon = "circle-dot" }}
59
-
{{ $state = "open" }}
60
-
{{ end }}
61
-
62
-
<span class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm">
63
-
{{ i $icon "w-3 h-3 mr-1.5 text-white dark:text-white" }}
64
-
<span class="text-white dark:text-white">{{ $state }}</span>
65
-
</span>
66
-
67
-
<span class="ml-1">
68
-
{{ template "user/fragments/picHandleLink" .Did }}
69
-
</span>
70
-
71
-
<span class="before:content-['·']">
72
-
{{ template "repo/fragments/time" .Created }}
73
-
</span>
74
-
75
-
<span class="before:content-['·']">
76
-
{{ $s := "s" }}
77
-
{{ if eq (len .Comments) 1 }}
78
-
{{ $s = "" }}
79
-
{{ end }}
80
-
<a href="/{{ $.RepoInfo.FullName }}/issues/{{ .IssueId }}" class="text-gray-500 dark:text-gray-400">{{ len .Comments }} comment{{$s}}</a>
81
-
</span>
82
-
83
-
{{ $state := .Labels }}
84
-
{{ range $k, $d := $.LabelDefs }}
85
-
{{ range $v, $s := $state.GetValSet $d.AtUri.String }}
86
-
{{ template "labels/fragments/label" (dict "def" $d "val" $v "withPrefix" true) }}
87
-
{{ end }}
88
-
{{ end }}
89
-
</div>
90
-
</div>
91
-
{{ end }}
92
</div>
93
{{ block "pagination" . }} {{ end }}
94
{{ end }}
+1
-1
go.mod
+1
-1
go.mod
···
43
github.com/yuin/goldmark v1.7.12
44
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
45
golang.org/x/crypto v0.40.0
46
golang.org/x/net v0.42.0
47
golang.org/x/sync v0.16.0
48
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
···
168
go.uber.org/atomic v1.11.0 // indirect
169
go.uber.org/multierr v1.11.0 // indirect
170
go.uber.org/zap v1.27.0 // indirect
171
-
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
172
golang.org/x/sys v0.34.0 // indirect
173
golang.org/x/text v0.27.0 // indirect
174
golang.org/x/time v0.12.0 // indirect
···
43
github.com/yuin/goldmark v1.7.12
44
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
45
golang.org/x/crypto v0.40.0
46
+
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
47
golang.org/x/net v0.42.0
48
golang.org/x/sync v0.16.0
49
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
···
169
go.uber.org/atomic v1.11.0 // indirect
170
go.uber.org/multierr v1.11.0 // indirect
171
go.uber.org/zap v1.27.0 // indirect
172
golang.org/x/sys v0.34.0 // indirect
173
golang.org/x/text v0.27.0 // indirect
174
golang.org/x/time v0.12.0 // indirect