Monorepo for Tangled tangled.org
766
fork

Configure Feed

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

appview/repo: add ?intent=star,fork dialog on repo pages #282

open opened by alexisbouchez.com targeting master from alexisbouchez.com/core: intent-query-param

Adds support for ?intent=star and ?intent=fork on a repository page.

External sites can now drop a "Star on Tangled" or "Fork on Tangled" button that links to e.g. tangled.org/alexisbouchez.com/hypercommit?intent=star, and the repo page opens a small confirmation dialog with a primary action button.

Unauthenticated visitors are sent through /login and land back on the dialog after.

Closes #498.

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:lf4czph3nyp5o6rrclae64bx/sh.tangled.repo.pull/3mkpcweq7ms22
+156
Diff #0
+2
appview/pages/pages.go
··· 823 823 Pipelines map[string]models.Pipeline 824 824 NeedsKnotUpgrade bool 825 825 KnotUnreachable bool 826 + // Intent surfaces an action confirmation dialog when set ("star", "fork"). 827 + Intent string 826 828 types.RepoIndexResponse 827 829 } 828 830
+1
appview/pages/templates/repo/empty.html
··· 6 6 {{ end }} 7 7 8 8 {{ define "repoContent" }} 9 + {{ template "repo/fragments/intentDialog" . }} 9 10 <main> 10 11 {{ if gt (len .BranchesTrunc) 0 }} 11 12 <div class="flex flex-col items-center">
+142
appview/pages/templates/repo/fragments/intentDialog.html
··· 1 + {{ define "repo/fragments/intentDialog" }} 2 + {{/* Auto-opens when ?intent=star|fork is set; posts to /star or 3 + bounces to /<repo>/fork. Unauthenticated visitors go through /login. */}} 4 + {{ if .Intent }} 5 + {{ $popId := printf "intent-%s" .Intent }} 6 + {{ $repoFullName := .RepoInfo.FullName }} 7 + {{ $repoAt := .RepoInfo.RepoAt }} 8 + {{ $isStarred := .RepoInfo.IsStarred }} 9 + {{ $isLoggedIn := .LoggedInUser }} 10 + 11 + <div 12 + id="{{ $popId }}" 13 + popover 14 + class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 dark:text-white backdrop:bg-gray-400/50 dark:backdrop:bg-gray-800/50 w-full md:w-96 p-4 rounded drop-shadow overflow-visible" 15 + > 16 + {{ if eq .Intent "star" }} 17 + <div class="flex flex-col gap-3"> 18 + <div class="flex items-center gap-2"> 19 + {{ i "star" "size-5" }} 20 + <h3 class="font-bold uppercase text-sm">Star this repository</h3> 21 + </div> 22 + <p class="text-sm text-gray-600 dark:text-gray-400"> 23 + <span class="font-mono">{{ $repoFullName }}</span> &mdash; star to bookmark 24 + and signal support to the maintainer. 25 + </p> 26 + 27 + {{ if $isLoggedIn }} 28 + {{ if $isStarred }} 29 + <p class="text-sm text-green-600 dark:text-green-400"> 30 + You've already starred this repository. 31 + </p> 32 + <div class="flex justify-end pt-2"> 33 + <button 34 + type="button" 35 + popovertarget="{{ $popId }}" 36 + popovertargetaction="hide" 37 + class="btn" 38 + > 39 + close 40 + </button> 41 + </div> 42 + {{ else }} 43 + <div class="flex gap-2 pt-2"> 44 + <button 45 + type="button" 46 + popovertarget="{{ $popId }}" 47 + popovertargetaction="hide" 48 + class="btn w-1/2 flex items-center gap-2" 49 + > 50 + {{ i "x" "size-4" }} cancel 51 + </button> 52 + <button 53 + type="button" 54 + class="btn w-1/2 flex items-center justify-center gap-2 group" 55 + hx-post="/star?subject={{ $repoAt }}&repoName={{ .RepoInfo.Name }}" 56 + hx-swap="none" 57 + hx-disabled-elt="this" 58 + hx-on:htmx:after-request="document.getElementById('{{ $popId }}').hidePopover()" 59 + > 60 + {{ i "star" "size-4 group-[.htmx-request]:hidden" }} 61 + {{ i "loader-circle" "size-4 animate-spin hidden group-[.htmx-request]:inline" }} 62 + <span class="group-[.htmx-request]:hidden">star</span> 63 + </button> 64 + </div> 65 + {{ end }} 66 + {{ else }} 67 + <p class="text-sm text-gray-600 dark:text-gray-400"> 68 + You need to be signed in to star a repository. 69 + </p> 70 + <div class="flex gap-2 pt-2"> 71 + <button 72 + type="button" 73 + popovertarget="{{ $popId }}" 74 + popovertargetaction="hide" 75 + class="btn w-1/2 flex items-center gap-2" 76 + > 77 + {{ i "x" "size-4" }} cancel 78 + </button> 79 + <a 80 + href="/login?return_url=/{{ $repoFullName }}%3Fintent%3Dstar" 81 + class="btn w-1/2 flex items-center justify-center gap-2" 82 + > 83 + {{ i "log-in" "size-4" }} sign in 84 + </a> 85 + </div> 86 + {{ end }} 87 + </div> 88 + {{ else if eq .Intent "fork" }} 89 + <div class="flex flex-col gap-3"> 90 + <div class="flex items-center gap-2"> 91 + {{ i "git-fork" "size-5" }} 92 + <h3 class="font-bold uppercase text-sm">Fork this repository</h3> 93 + </div> 94 + <p class="text-sm text-gray-600 dark:text-gray-400"> 95 + Continue to the fork page to choose a knot and a name for your fork 96 + of <span class="font-mono">{{ $repoFullName }}</span>. 97 + </p> 98 + <div class="flex gap-2 pt-2"> 99 + <button 100 + type="button" 101 + popovertarget="{{ $popId }}" 102 + popovertargetaction="hide" 103 + class="btn w-1/2 flex items-center gap-2" 104 + > 105 + {{ i "x" "size-4" }} cancel 106 + </button> 107 + {{ if $isLoggedIn }} 108 + <a 109 + href="/{{ $repoFullName }}/fork" 110 + class="btn w-1/2 flex items-center justify-center gap-2" 111 + > 112 + {{ i "git-fork" "size-4" }} continue 113 + </a> 114 + {{ else }} 115 + <a 116 + href="/login?return_url=/{{ $repoFullName }}/fork" 117 + class="btn w-1/2 flex items-center justify-center gap-2" 118 + > 119 + {{ i "log-in" "size-4" }} sign in to fork 120 + </a> 121 + {{ end }} 122 + </div> 123 + </div> 124 + {{ end }} 125 + </div> 126 + 127 + <script> 128 + // Auto-open on first paint, then strip ?intent= from the URL so a 129 + // refresh doesn't keep re-opening the dialog. 130 + (function () { 131 + const el = document.getElementById('{{ $popId }}'); 132 + if (!el || typeof el.showPopover !== 'function') return; 133 + try { el.showPopover(); } catch (e) { /* already open */ } 134 + if (window.history && window.history.replaceState) { 135 + const u = new URL(window.location.href); 136 + u.searchParams.delete('intent'); 137 + window.history.replaceState({}, '', u.toString()); 138 + } 139 + })(); 140 + </script> 141 + {{ end }} 142 + {{ end }}
+1
appview/pages/templates/repo/index.html
··· 8 8 {{ end }} 9 9 10 10 {{ define "repoContent" }} 11 + {{ template "repo/fragments/intentDialog" . }} 11 12 <main> 12 13 {{ if .Languages }} 13 14 {{ block "repoLanguages" . }}{{ end }}
+10
appview/repo/index.go
··· 145 145 VerifiedCommits: vc, 146 146 Languages: languageInfo, 147 147 Pipelines: pipelines, 148 + Intent: normalizeIntent(r.URL.Query().Get("intent")), 148 149 }) 149 150 } 150 151 152 + func normalizeIntent(s string) string { 153 + switch s { 154 + case "star", "fork": 155 + return s 156 + default: 157 + return "" 158 + } 159 + } 160 + 151 161 func (rp *Repo) getLanguageInfo( 152 162 ctx context.Context, 153 163 l *slog.Logger,

History

1 round 0 comments
sign up or login to add to the discussion
1 commit
expand
appview/repo: add ?intent=star,fork dialog on repo pages
no conflicts, ready to merge
expand 0 comments