Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

appview/state: style changes to good-first-issue

Signed-off-by: oppiliappan <me@oppi.li>

authored by

oppiliappan and committed by
Anirudh Oppiliappan
014c4249 4fd5dfd2

+109 -109
+14 -13
appview/models/label.go
··· 461 461 return result 462 462 } 463 463 464 + var ( 465 + LabelWontfix = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "wontfix") 466 + LabelDuplicate = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "duplicate") 467 + LabelAssignee = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "assignee") 468 + LabelGoodFirstIssue = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "good-first-issue") 469 + LabelDocumentation = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "documentation") 470 + ) 471 + 464 472 func DefaultLabelDefs() []string { 465 - rkeys := []string{ 466 - "wontfix", 467 - "duplicate", 468 - "assignee", 469 - "good-first-issue", 470 - "documentation", 473 + return []string{ 474 + LabelWontfix, 475 + LabelDuplicate, 476 + LabelAssignee, 477 + LabelGoodFirstIssue, 478 + LabelDocumentation, 471 479 } 472 - 473 - defs := make([]string, len(rkeys)) 474 - for i, r := range rkeys { 475 - defs[i] = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, r) 476 - } 477 - 478 - return defs 479 480 } 480 481 481 482 func FetchDefaultDefs(r *idresolver.Resolver) ([]LabelDefinition, error) {
+2
appview/pages/pages.go
··· 306 306 LoggedInUser *oauth.User 307 307 Timeline []models.TimelineEvent 308 308 Repos []models.Repo 309 + GfiLabel *models.LabelDefinition 309 310 } 310 311 311 312 func (p *Pages) Timeline(w io.Writer, params TimelineParams) error { ··· 318 317 Issues []models.Issue 319 318 RepoGroups []*models.RepoGroup 320 319 LabelDefs map[string]*models.LabelDefinition 320 + GfiLabel *models.LabelDefinition 321 321 Page pagination.Page 322 322 } 323 323
+50 -62
appview/pages/templates/goodfirstissues/index.html
··· 9 9 10 10 {{ define "content" }} 11 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> 12 + <header class="col-span-full md:col-span-10 px-6 py-2 text-center flex flex-col items-center justify-center py-8"> 13 + <h1 class="scale-150 dark:text-white mb-4"> 14 + {{ template "labels/fragments/label" (dict "def" .GfiLabel "val" "" "withPrefix" true) }} 15 + </h1> 14 16 <p class="text-gray-600 dark:text-gray-400 mb-2"> 15 17 Find beginner-friendly issues across all repositories to get started with open source contributions. 16 18 </p> ··· 37 35 {{ else }} 38 36 {{ range .RepoGroups }} 39 37 <div class="mb-4 gap-1 flex flex-col drop-shadow-sm rounded bg-white dark:bg-gray-800"> 40 - <div class="flex px-6 pt-4 pb-2 flex-row gap-1"> 41 - <div class="font-medium dark:text-white flex items-center justify-between"> 42 - <div class="flex items-center min-w-0 flex-1 mr-2"> 43 - {{ if .Repo.Source }} 44 - {{ i "git-fork" "w-4 h-4 mr-1.5 shrink-0" }} 45 - {{ else }} 46 - {{ i "book-marked" "w-4 h-4 mr-1.5 shrink-0" }} 47 - {{ end }} 48 - {{ $repoOwner := resolve .Repo.Did }} 49 - <a href="/{{ $repoOwner }}/{{ .Repo.Name }}" class="truncate min-w-0">{{ $repoOwner }}/{{ .Repo.Name }}</a> 38 + <div class="flex px-6 pt-4 flex-row gap-1 items-center justify-between"> 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> 50 49 </div> 51 - </div> 52 50 53 51 54 52 {{ if .Repo.RepoStats }} 55 - <div class="text-gray-400 text-sm font-mono inline-flex gap-4 mt-auto"> 53 + <div class="text-gray-400 text-sm font-mono inline-flex gap-4"> 56 54 {{ with .Repo.RepoStats.Language }} 57 55 <div class="flex gap-2 items-center text-sm"> 58 56 {{ template "repo/fragments/colorBall" (dict "color" (langColor .)) }} ··· 88 86 {{ end }} 89 87 90 88 {{ if gt (len .Issues) 0 }} 91 - <details class="bg-white dark:bg-gray-800 group" open> 92 - <summary class="py-4 px-6 text-xs list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400"> 93 - {{ $s := "s" }} 94 - {{ if eq (len .Issues) 1 }} 95 - {{ $s = "" }} 96 - {{ end }} 97 - <div class="group-open:hidden flex items-center gap-2"> 98 - {{ i "chevrons-up-down" "w-4 h-4" }} expand {{ len .Issues }} issue{{$s}} in this repo 99 - </div> 100 - <div class="hidden group-open:flex items-center gap-2"> 101 - {{ i "chevrons-down-up" "w-4 h-4" }} hide {{ len .Issues }} issue{{$s}} in this repo 102 - </div> 103 - </summary> 104 - <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"> 105 - {{ range .Issues }} 106 - <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"> 107 - <div class="py-2 px-6"> 108 - <div class="flex-grow min-w-0 w-full"> 109 - <div class="flex text-sm items-center justify-between w-full"> 110 - <div class="flex items-center gap-2 min-w-0 flex-1 pr-2"> 111 - <span class="truncate text-sm text-gray-800 dark:text-gray-200"> 112 - <span class="text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span> 113 - {{ .Title | description }} 114 - </span> 115 - </div> 116 - <div class="flex-shrink-0 flex items-center gap-2 text-gray-500 dark:text-gray-400"> 117 - <span> 118 - <div class="inline-flex items-center gap-1"> 119 - {{ i "message-square" "w-3 h-3 md:hidden" }} 120 - {{ len .Comments }} 121 - <span class="hidden md:inline">comment{{ if ne (len .Comments) 1 }}s{{ end }}</span> 122 - </div> 123 - </span> 124 - <span class="before:content-['·'] before:select-none"></span> 125 - <span class="text-xs"> 126 - {{ template "repo/fragments/time" .Created }} 127 - </span> 128 - <div class="hidden md:inline-flex md:gap-1"> 129 - {{ $labelState := .Labels }} 130 - {{ range $k, $d := $.LabelDefs }} 131 - {{ range $v, $s := $labelState.GetValSet $d.AtUri.String }} 132 - {{ template "labels/fragments/label" (dict "def" $d "val" $v "withPrefix" true) }} 133 - {{ end }} 134 - {{ end }} 89 + <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"> 90 + {{ range .Issues }} 91 + <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"> 92 + <div class="py-2 px-6"> 93 + <div class="flex-grow min-w-0 w-full"> 94 + <div class="flex text-sm items-center justify-between w-full"> 95 + <div class="flex items-center gap-2 min-w-0 flex-1 pr-2"> 96 + <span class="truncate text-sm text-gray-800 dark:text-gray-200"> 97 + <span class="text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span> 98 + {{ .Title | description }} 99 + </span> 100 + </div> 101 + <div class="flex-shrink-0 flex items-center gap-2 text-gray-500 dark:text-gray-400"> 102 + <span> 103 + <div class="inline-flex items-center gap-1"> 104 + {{ i "message-square" "w-3 h-3 md:hidden" }} 105 + {{ len .Comments }} 106 + <span class="hidden md:inline">comment{{ if ne (len .Comments) 1 }}s{{ end }}</span> 135 107 </div> 108 + </span> 109 + <span class="before:content-['·'] before:select-none"></span> 110 + <span class="text-sm"> 111 + {{ template "repo/fragments/time" .Created }} 112 + </span> 113 + <div class="hidden md:inline-flex md:gap-1"> 114 + {{ $labelState := .Labels }} 115 + {{ range $k, $d := $.LabelDefs }} 116 + {{ range $v, $s := $labelState.GetValSet $d.AtUri.String }} 117 + {{ template "labels/fragments/label" (dict "def" $d "val" $v "withPrefix" true) }} 118 + {{ end }} 119 + {{ end }} 136 120 </div> 137 121 </div> 138 122 </div> 139 123 </div> 140 - </a> 141 - {{ end }} 142 - </div> 143 - </details> 124 + </div> 125 + </a> 126 + {{ end }} 127 + </div> 144 128 {{ end }} 145 129 </div> 146 130 {{ end }}
+1 -1
appview/pages/templates/labels/fragments/label.html
··· 2 2 {{ $d := .def }} 3 3 {{ $v := .val }} 4 4 {{ $withPrefix := .withPrefix }} 5 - <span class="flex items-center gap-2 font-normal normal-case rounded py-1 px-2 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm"> 5 + <span class="w-fit flex items-center gap-2 font-normal normal-case rounded py-1 px-2 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm"> 6 6 {{ template "repo/fragments/colorBall" (dict "color" $d.GetColor) }} 7 7 8 8 {{ $lhs := printf "%s" $d.Name }}
+29 -27
appview/pages/templates/timeline/fragments/goodfirstissues.html
··· 1 1 {{ define "timeline/fragments/goodfirstissues" }} 2 - <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-sm mb-4"> 3 - <div class="px-6 py-4"> 4 - <div class="flex flex-col md:flex-row items-center gap-4"> 5 - <div class="flex-1"> 6 - <div class="flex items-center gap-2 mb-2"> 7 - <span class="text-sm text-gray-500 dark:text-gray-400">Oct&ndash;Nov 2025</span> 8 - </div> 9 - <h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2"> 10 - Get your first PR merged and earn Dolly stickers! 🎉 11 - </h4> 12 - <p class="text-sm text-gray-600 dark:text-gray-300 mb-3"> 13 - Merge a PR for "good first issue" (make this a label) a and get Tangled stickers shipped free. 14 - </p> 15 - <a href="/goodfirstissues" 16 - class="btn my-2 gap-2"> 17 - browse issues 18 - {{ i "arrow-right" "size-4" }} 19 - </a> 20 - </div> 21 - <div class="flex-shrink-0"> 22 - <div class="flex items-center gap-1 p-3 bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/20 dark:to-pink-900/20 rounded border border-purple-200 dark:border-purple-700"> 23 - {{ template "fragments/dolly/logo" "w-6 h-6" }} 24 - {{ template "fragments/dolly/silhouette" }} 25 - <span class="text-xs text-purple-600 dark:text-purple-400 font-medium">Free stickers!</span> 26 - </div> 27 - </div> 2 + {{ if .GfiLabel }} 3 + <a href="/goodfirstissues" class="no-underline hover:no-underline"> 4 + <div class="flex items-center justify-between gap-2 bg-purple-200 dark:bg-purple-900 border border-purple-400 dark:border-purple-500 rounded mb-4 py-4 px-6 "> 5 + <div class="flex-1 flex flex-col gap-2"> 6 + <div class="text-purple-500 dark:text-purple-400">Oct 2025</div> 7 + <p> 8 + Make your first contribution to an open-source project this October. 9 + </p> 10 + <p> 11 + <em>good-first-issue</em> is a collection of issues on open-source projects 12 + that are easy ways for new contributors to give back to the projects 13 + they love. 14 + </p> 15 + <span class="flex items-center gap-2 text-purple-500 dark:text-purple-400"> 16 + Browse issues {{ i "arrow-right" "size-4" }} 17 + </span> 18 + </div> 19 + <div class="hidden md:block relative px-16 scale-150"> 20 + <div class="relative opacity-60"> 21 + {{ template "labels/fragments/label" (dict "def" .GfiLabel "val" "" "withPrefix" true) }} 28 22 </div> 23 + <div class="relative -mt-4 ml-2 opacity-80"> 24 + {{ template "labels/fragments/label" (dict "def" .GfiLabel "val" "" "withPrefix" true) }} 25 + </div> 26 + <div class="relative -mt-4 ml-4"> 27 + {{ template "labels/fragments/label" (dict "def" .GfiLabel "val" "" "withPrefix" true) }} 28 + </div> 29 + </div> 29 30 </div> 30 - </div> 31 + </a> 32 + {{ end }} 31 33 {{ end }}
+5 -4
appview/state/gfi.go
··· 6 6 "net/http" 7 7 "sort" 8 8 9 + "github.com/bluesky-social/indigo/atproto/syntax" 9 10 "tangled.org/core/api/tangled" 10 11 "tangled.org/core/appview/db" 11 12 "tangled.org/core/appview/models" ··· 65 64 } 66 65 } 67 66 68 - repoGroups := make(map[string]*models.RepoGroup) 67 + repoGroups := make(map[syntax.ATURI]*models.RepoGroup) 69 68 for _, issue := range goodFirstIssues { 70 - repoKey := fmt.Sprintf("%s/%s", issue.Repo.Did, issue.Repo.Name) 71 - if group, exists := repoGroups[repoKey]; exists { 69 + if group, exists := repoGroups[issue.Repo.RepoAt()]; exists { 72 70 group.Issues = append(group.Issues, issue) 73 71 } else { 74 - repoGroups[repoKey] = &models.RepoGroup{ 72 + repoGroups[issue.Repo.RepoAt()] = &models.RepoGroup{ 75 73 Repo: issue.Repo, 76 74 Issues: []models.Issue{issue}, 77 75 } ··· 134 134 RepoGroups: paginatedGroups, 135 135 LabelDefs: labelDefsMap, 136 136 Page: page, 137 + GfiLabel: labelDefsMap[goodFirstIssueLabel], 137 138 }) 138 139 }
+8 -2
appview/state/state.go
··· 270 270 return 271 271 } 272 272 273 - s.pages.Timeline(w, pages.TimelineParams{ 273 + gfiLabel, err := db.GetLabelDefinition(s.db, db.FilterEq("at_uri", models.LabelGoodFirstIssue)) 274 + if err != nil { 275 + // non-fatal 276 + } 277 + 278 + fmt.Println(s.pages.Timeline(w, pages.TimelineParams{ 274 279 LoggedInUser: user, 275 280 Timeline: timeline, 276 281 Repos: repos, 277 - }) 282 + GfiLabel: gfiLabel, 283 + })) 278 284 } 279 285 280 286 func (s *State) UpgradeBanner(w http.ResponseWriter, r *http.Request) {