forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

appview: support star for `sh.tangled.string`

Not sending "XXX starred your string" notif yet.

Close: <https://tangled.org/tangled.org/core/issues/296>
Signed-off-by: Seongmin Lee <git@boltless.me>

authored by boltless.me and committed by Tangled c6a41ebf fe343b6c

Changed files
+49 -31
appview
models
pages
templates
fragments
layouts
strings
timeline
fragments
user
fragments
state
strings
+1 -1
appview/models/string.go
··· 22 Edited *time.Time 23 } 24 25 - func (s *String) StringAt() syntax.ATURI { 26 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", s.Did, tangled.StringNSID, s.Rkey)) 27 } 28
··· 22 Edited *time.Time 23 } 24 25 + func (s *String) AtUri() syntax.ATURI { 26 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", s.Did, tangled.StringNSID, s.Rkey)) 27 } 28
+8 -6
appview/pages/pages.go
··· 625 return p.executePlain("user/fragments/editPins", w, params) 626 } 627 628 - type RepoStarFragmentParams struct { 629 IsStarred bool 630 - RepoAt syntax.ATURI 631 - Stats models.RepoStats 632 } 633 634 - func (p *Pages) RepoStarFragment(w io.Writer, params RepoStarFragmentParams) error { 635 - return p.executePlain("repo/fragments/repoStar", w, params) 636 } 637 638 type RepoIndexParams struct { ··· 1376 ShowRendered bool 1377 RenderToggle bool 1378 RenderedContents template.HTML 1379 - String models.String 1380 Stats models.StringStats 1381 Owner identity.Identity 1382 } 1383
··· 625 return p.executePlain("user/fragments/editPins", w, params) 626 } 627 628 + type StarBtnFragmentParams struct { 629 IsStarred bool 630 + SubjectAt syntax.ATURI 631 + StarCount int 632 } 633 634 + func (p *Pages) StarBtnFragment(w io.Writer, params StarBtnFragmentParams) error { 635 + return p.executePlain("fragments/starBtn", w, params) 636 } 637 638 type RepoIndexParams struct { ··· 1376 ShowRendered bool 1377 RenderToggle bool 1378 RenderedContents template.HTML 1379 + String *models.String 1380 Stats models.StringStats 1381 + IsStarred bool 1382 + StarCount int 1383 Owner identity.Identity 1384 } 1385
+4 -1
appview/pages/templates/layouts/repobase.html
··· 49 </div> 50 51 <div class="w-full sm:w-fit grid grid-cols-3 gap-2 z-auto"> 52 - {{ template "repo/fragments/repoStar" .RepoInfo }} 53 <a 54 class="btn text-sm no-underline hover:no-underline flex items-center gap-2 group" 55 hx-boost="true"
··· 49 </div> 50 51 <div class="w-full sm:w-fit grid grid-cols-3 gap-2 z-auto"> 52 + {{ template "fragments/starBtn" 53 + (dict "SubjectAt" .RepoInfo.RepoAt 54 + "IsStarred" .RepoInfo.IsStarred 55 + "StarCount" .RepoInfo.Stats.StarCount) }} 56 <a 57 class="btn text-sm no-underline hover:no-underline flex items-center gap-2 group" 58 hx-boost="true"
+4 -4
appview/pages/templates/repo/fragments/repoStar.html appview/pages/templates/fragments/starBtn.html
··· 1 - {{ define "repo/fragments/repoStar" }} 2 <button 3 id="starBtn" 4 class="btn disabled:opacity-50 disabled:cursor-not-allowed flex gap-2 items-center group" 5 {{ if .IsStarred }} 6 - hx-delete="/star?subject={{ .RepoAt }}&countHint={{ .Stats.StarCount }}" 7 {{ else }} 8 - hx-post="/star?subject={{ .RepoAt }}&countHint={{ .Stats.StarCount }}" 9 {{ end }} 10 11 hx-trigger="click" ··· 19 {{ i "star" "w-4 h-4" }} 20 {{ end }} 21 <span class="text-sm"> 22 - {{ .Stats.StarCount }} 23 </span> 24 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 25 </button>
··· 1 + {{ define "fragments/starBtn" }} 2 <button 3 id="starBtn" 4 class="btn disabled:opacity-50 disabled:cursor-not-allowed flex gap-2 items-center group" 5 {{ if .IsStarred }} 6 + hx-delete="/star?subject={{ .SubjectAt }}&countHint={{ .StarCount }}" 7 {{ else }} 8 + hx-post="/star?subject={{ .SubjectAt }}&countHint={{ .StarCount }}" 9 {{ end }} 10 11 hx-trigger="click" ··· 19 {{ i "star" "w-4 h-4" }} 20 {{ end }} 21 <span class="text-sm"> 22 + {{ .StarCount }} 23 </span> 24 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 25 </button>
+8 -4
appview/pages/templates/strings/string.html
··· 17 <span class="select-none">/</span> 18 <a href="/strings/{{ $ownerId }}/{{ .String.Rkey }}" class="font-bold">{{ .String.Filename }}</a> 19 </div> 20 - {{ if and .LoggedInUser (eq .LoggedInUser.Did .String.Did) }} 21 - <div class="flex gap-2 text-base"> 22 <a class="btn flex items-center gap-2 no-underline hover:no-underline p-2 group" 23 hx-boost="true" 24 href="/strings/{{ .String.Did }}/{{ .String.Rkey }}/edit"> ··· 37 <span class="hidden md:inline">delete</span> 38 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 39 </button> 40 - </div> 41 - {{ end }} 42 </div> 43 <span> 44 {{ with .String.Description }}
··· 17 <span class="select-none">/</span> 18 <a href="/strings/{{ $ownerId }}/{{ .String.Rkey }}" class="font-bold">{{ .String.Filename }}</a> 19 </div> 20 + <div class="flex gap-2 text-base"> 21 + {{ if and .LoggedInUser (eq .LoggedInUser.Did .String.Did) }} 22 <a class="btn flex items-center gap-2 no-underline hover:no-underline p-2 group" 23 hx-boost="true" 24 href="/strings/{{ .String.Did }}/{{ .String.Rkey }}/edit"> ··· 37 <span class="hidden md:inline">delete</span> 38 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 39 </button> 40 + {{ end }} 41 + {{ template "fragments/starBtn" 42 + (dict "SubjectAt" .String.AtUri 43 + "IsStarred" .IsStarred 44 + "StarCount" .StarCount) }} 45 + </div> 46 </div> 47 <span> 48 {{ with .String.Description }}
+2 -2
appview/pages/templates/timeline/fragments/timeline.html
··· 52 <span class="text-gray-700 dark:text-gray-400 text-xs">{{ template "repo/fragments/time" $repo.Created }}</span> 53 </div> 54 {{ with $repo }} 55 - {{ template "user/fragments/repoCard" (list $root . true true (dict "IsStarred" $event.IsStarred "RepoAt" .RepoAt "Stats" (dict "StarCount" $event.StarCount))) }} 56 {{ end }} 57 {{ end }} 58 ··· 72 <span class="text-gray-700 dark:text-gray-400 text-xs">{{ template "repo/fragments/time" .Created }}</span> 73 </div> 74 {{ with .Repo }} 75 - {{ template "user/fragments/repoCard" (list $root . true true (dict "IsStarred" $event.IsStarred "RepoAt" .RepoAt "Stats" (dict "StarCount" $event.StarCount))) }} 76 {{ end }} 77 {{ end }} 78 {{ end }}
··· 52 <span class="text-gray-700 dark:text-gray-400 text-xs">{{ template "repo/fragments/time" $repo.Created }}</span> 53 </div> 54 {{ with $repo }} 55 + {{ template "user/fragments/repoCard" (list $root . true true (dict "IsStarred" $event.IsStarred "SubjectAt" .RepoAt "StarCount" $event.StarCount)) }} 56 {{ end }} 57 {{ end }} 58 ··· 72 <span class="text-gray-700 dark:text-gray-400 text-xs">{{ template "repo/fragments/time" .Created }}</span> 73 </div> 74 {{ with .Repo }} 75 + {{ template "user/fragments/repoCard" (list $root . true true (dict "IsStarred" $event.IsStarred "SubjectAt" .RepoAt "StarCount" $event.StarCount)) }} 76 {{ end }} 77 {{ end }} 78 {{ end }}
+2 -1
appview/pages/templates/user/fragments/repoCard.html
··· 1 {{ define "user/fragments/repoCard" }} 2 {{ $root := index . 0 }} 3 {{ $repo := index . 1 }} 4 {{ $fullName := index . 2 }} ··· 29 </div> 30 {{ if and $starButton $root.LoggedInUser }} 31 <div class="shrink-0"> 32 - {{ template "repo/fragments/repoStar" $starData }} 33 </div> 34 {{ end }} 35 </div>
··· 1 {{ define "user/fragments/repoCard" }} 2 + {{/* root, repo, fullName [,starButton [,starData]] */}} 3 {{ $root := index . 0 }} 4 {{ $repo := index . 1 }} 5 {{ $fullName := index . 2 }} ··· 30 </div> 31 {{ if and $starButton $root.LoggedInUser }} 32 <div class="shrink-0"> 33 + {{ template "fragments/starBtn" $starData }} 34 </div> 35 {{ end }} 36 </div>
+6 -10
appview/state/star.go
··· 75 76 s.notifier.NewStar(r.Context(), star) 77 78 - s.pages.RepoStarFragment(w, pages.RepoStarFragmentParams{ 79 IsStarred: true, 80 - RepoAt: subjectUri, 81 - Stats: models.RepoStats{ 82 - StarCount: starCount, 83 - }, 84 }) 85 86 return ··· 117 118 s.notifier.DeleteStar(r.Context(), star) 119 120 - s.pages.RepoStarFragment(w, pages.RepoStarFragmentParams{ 121 IsStarred: false, 122 - RepoAt: subjectUri, 123 - Stats: models.RepoStats{ 124 - StarCount: starCount, 125 - }, 126 }) 127 128 return
··· 75 76 s.notifier.NewStar(r.Context(), star) 77 78 + s.pages.StarBtnFragment(w, pages.StarBtnFragmentParams{ 79 IsStarred: true, 80 + SubjectAt: subjectUri, 81 + StarCount: starCount, 82 }) 83 84 return ··· 115 116 s.notifier.DeleteStar(r.Context(), star) 117 118 + s.pages.StarBtnFragment(w, pages.StarBtnFragmentParams{ 119 IsStarred: false, 120 + SubjectAt: subjectUri, 121 + StarCount: starCount, 122 }) 123 124 return
+14 -2
appview/strings/strings.go
··· 148 showRendered = r.URL.Query().Get("code") != "true" 149 } 150 151 s.Pages.SingleString(w, pages.SingleStringParams{ 152 - LoggedInUser: s.OAuth.GetUser(r), 153 RenderToggle: renderToggle, 154 ShowRendered: showRendered, 155 - String: string, 156 Stats: string.Stats(), 157 Owner: id, 158 }) 159 }
··· 148 showRendered = r.URL.Query().Get("code") != "true" 149 } 150 151 + starCount, err := db.GetStarCount(s.Db, string.AtUri()) 152 + if err != nil { 153 + l.Error("failed to get star count", "err", err) 154 + } 155 + user := s.OAuth.GetUser(r) 156 + isStarred := false 157 + if user != nil { 158 + isStarred = db.GetStarStatus(s.Db, user.Did, string.AtUri()) 159 + } 160 + 161 s.Pages.SingleString(w, pages.SingleStringParams{ 162 + LoggedInUser: user, 163 RenderToggle: renderToggle, 164 ShowRendered: showRendered, 165 + String: &string, 166 Stats: string.Stats(), 167 + IsStarred: isStarred, 168 + StarCount: starCount, 169 Owner: id, 170 }) 171 }