forked from tangled.org/core
this repo has no description

switch to SSR lucide-icons

+36
appview/pages/funcmap.go
··· 4 "fmt" 5 "html" 6 "html/template" 7 "reflect" 8 "strings" 9 ··· 119 "list": func(args ...any) []any { 120 return args 121 }, 122 } 123 }
··· 4 "fmt" 5 "html" 6 "html/template" 7 + "log" 8 + "path/filepath" 9 "reflect" 10 "strings" 11 ··· 121 "list": func(args ...any) []any { 122 return args 123 }, 124 + "i": func(name string, classes ...string) template.HTML { 125 + data, err := icon(name, classes) 126 + if err != nil { 127 + log.Printf("icon %s does not exist", name) 128 + data, _ = icon("airplay", classes) 129 + } 130 + return template.HTML(data) 131 + }, 132 } 133 } 134 + 135 + func icon(name string, classes []string) (template.HTML, error) { 136 + iconPath := filepath.Join("static", "icons", name) 137 + 138 + if filepath.Ext(name) == "" { 139 + iconPath += ".svg" 140 + } 141 + 142 + data, err := Files.ReadFile(iconPath) 143 + if err != nil { 144 + return "", fmt.Errorf("icon %s not found: %w", name, err) 145 + } 146 + 147 + // Convert SVG data to string 148 + svgStr := string(data) 149 + 150 + svgTagEnd := strings.Index(svgStr, ">") 151 + if svgTagEnd == -1 { 152 + return "", fmt.Errorf("invalid SVG format for icon %s", name) 153 + } 154 + 155 + classTag := ` class="` + strings.Join(classes, " ") + `"` 156 + 157 + modifiedSVG := svgStr[:svgTagEnd] + classTag + svgStr[svgTagEnd:] 158 + return template.HTML(modifiedSVG), nil 159 + }
+6 -6
appview/pages/pages.go
··· 25 "github.com/sotangled/tangled/types" 26 ) 27 28 - //go:embed templates/* static/* 29 - var files embed.FS 30 31 type Pages struct { 32 t map[string]*template.Template ··· 36 templates := make(map[string]*template.Template) 37 38 // Walk through embedded templates directory and parse all .html files 39 - err := fs.WalkDir(files, "templates", func(path string, d fs.DirEntry, err error) error { 40 if err != nil { 41 return err 42 } ··· 49 if strings.HasPrefix(path, "templates/fragments/") { 50 tmpl, err := template.New(name). 51 Funcs(funcMap()). 52 - ParseFS(files, path) 53 if err != nil { 54 return fmt.Errorf("setting up fragment: %w", err) 55 } ··· 64 // Add the page template on top of the base 65 tmpl, err := template.New(name). 66 Funcs(funcMap()). 67 - ParseFS(files, "templates/layouts/*.html", "templates/fragments/*.html", path) 68 if err != nil { 69 return fmt.Errorf("setting up template: %w", err) 70 } ··· 577 } 578 579 func (p *Pages) Static() http.Handler { 580 - sub, err := fs.Sub(files, "static") 581 if err != nil { 582 log.Fatalf("no static dir found? that's crazy: %v", err) 583 }
··· 25 "github.com/sotangled/tangled/types" 26 ) 27 28 + //go:embed templates/* static 29 + var Files embed.FS 30 31 type Pages struct { 32 t map[string]*template.Template ··· 36 templates := make(map[string]*template.Template) 37 38 // Walk through embedded templates directory and parse all .html files 39 + err := fs.WalkDir(Files, "templates", func(path string, d fs.DirEntry, err error) error { 40 if err != nil { 41 return err 42 } ··· 49 if strings.HasPrefix(path, "templates/fragments/") { 50 tmpl, err := template.New(name). 51 Funcs(funcMap()). 52 + ParseFS(Files, path) 53 if err != nil { 54 return fmt.Errorf("setting up fragment: %w", err) 55 } ··· 64 // Add the page template on top of the base 65 tmpl, err := template.New(name). 66 Funcs(funcMap()). 67 + ParseFS(Files, "templates/layouts/*.html", "templates/fragments/*.html", path) 68 if err != nil { 69 return fmt.Errorf("setting up template: %w", err) 70 } ··· 577 } 578 579 func (p *Pages) Static() http.Handler { 580 + sub, err := fs.Sub(Files, "static") 581 if err != nil { 582 log.Fatalf("no static dir found? that's crazy: %v", err) 583 }
appview/pages/static/.gitkeep

This is a binary file and will not be displayed.

+4 -4
appview/pages/templates/fragments/diff.html
··· 40 <a {{if $parent}}href="/{{ $repo }}/blob/{{ $parent }}/{{ .Name.Old }}"{{end}}> 41 {{ .Name.Old }} 42 </a> 43 - <i class="w-4 h-4" data-lucide="arrow-right"></i> 44 <a {{if $this}}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.New }}"{{end}}> 45 {{ .Name.New }} 46 </a> ··· 53 54 {{ $iconstyle := "p-1 mx-1 hover:bg-gray-100 rounded" }} 55 <div id="right-side-items" class="p-2 flex items-center"> 56 - <a title="top of file" href="#file-{{ .Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-up-to-line"></i></a> 57 {{ if gt $idx 0 }} 58 {{ $prev := index $diff (sub $idx 1) }} 59 - <a title="previous file" href="#file-{{ $prev.Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-up"></i></a> 60 {{ end }} 61 62 {{ if lt $idx $last }} 63 {{ $next := index $diff (add $idx 1) }} 64 - <a title="next file" href="#file-{{ $next.Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-down"></i></a> 65 {{ end }} 66 </div> 67
··· 40 <a {{if $parent}}href="/{{ $repo }}/blob/{{ $parent }}/{{ .Name.Old }}"{{end}}> 41 {{ .Name.Old }} 42 </a> 43 + {{ i "arrow-right" "w-4 h-4" }} 44 <a {{if $this}}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.New }}"{{end}}> 45 {{ .Name.New }} 46 </a> ··· 53 54 {{ $iconstyle := "p-1 mx-1 hover:bg-gray-100 rounded" }} 55 <div id="right-side-items" class="p-2 flex items-center"> 56 + <a title="top of file" href="#file-{{ .Name.New }}" class="{{ $iconstyle }}">{{ i "arrow-up-to-line" "w-4 h-4" }}</a> 57 {{ if gt $idx 0 }} 58 {{ $prev := index $diff (sub $idx 1) }} 59 + <a title="previous file" href="#file-{{ $prev.Name.New }}" class="{{ $iconstyle }}">{{ i "arrow-up" "w-4 h-4" }}</a> 60 {{ end }} 61 62 {{ if lt $idx $last }} 63 {{ $next := index $diff (add $idx 1) }} 64 + <a title="next file" href="#file-{{ $next.Name.New }}" class="{{ $iconstyle }}">{{ i "arrow-down" "w-4 h-4" }}</a> 65 {{ end }} 66 </div> 67
+6 -6
appview/pages/templates/fragments/editRepoDescription.html
··· 1 {{ define "fragments/editRepoDescription" }} 2 - <form hx-put="/{{ .RepoInfo.FullName }}/description" hx-target="this" hx-swap="outerHTML"> 3 - <input type="text" name="description" value="{{ .RepoInfo.Description }}"> 4 - <button type="submit" class="bg-green-100 text-green-700 rounded p-1 mr-1 hover:bg-green-200 font-mono uppercase text-sm"> 5 - save 6 </button> 7 - <button type="button" class="bg-red-100 text-red-700 rounded p-1 hover:bg-red-200 font-mono uppercase text-sm" hx-get="/{{ .RepoInfo.FullName }}/description" > 8 - cancel 9 </button> 10 </form> 11 {{ end }}
··· 1 {{ define "fragments/editRepoDescription" }} 2 + <form hx-put="/{{ .RepoInfo.FullName }}/description" hx-target="this" hx-swap="outerHTML" class="flex flex-wrap gap-2"> 3 + <input type="text" class="p-1" name="description" value="{{ .RepoInfo.Description }}"> 4 + <button type="submit" class="btn p-2 flex items-center gap-2 no-underline text-sm"> 5 + save {{ i "check" "w-3 h-3" }} 6 </button> 7 + <button type="button" class="btn p-2 flex items-center gap-2 no-underline text-sm" hx-get="/{{ .RepoInfo.FullName }}/description" > 8 + cancel {{ i "x" "w-3 h-3" }} 9 </button> 10 </form> 11 {{ end }}
+3 -2
appview/pages/templates/fragments/repoDescription.html
··· 1 {{ define "fragments/repoDescription" }} 2 - <span id="repo-description" hx-target="this" hx-swap="outerHTML"> 3 {{ if .RepoInfo.Description }} 4 {{ .RepoInfo.Description }} 5 {{ else }} ··· 7 {{ end }} 8 9 {{ if .RepoInfo.Roles.IsOwner }} 10 - <button class="bg-gray-200 uppercase rounded p-1 ml-1 hover:bg-gray-400 font-mono text-sm" hx-get="/{{ .RepoInfo.FullName }}/description/edit"> 11 edit 12 </button> 13 {{ end }} 14 </span>
··· 1 {{ define "fragments/repoDescription" }} 2 + <span id="repo-description" class="flex flex-wrap items-center gap-2" hx-target="this" hx-swap="outerHTML"> 3 {{ if .RepoInfo.Description }} 4 {{ .RepoInfo.Description }} 5 {{ else }} ··· 7 {{ end }} 8 9 {{ if .RepoInfo.Roles.IsOwner }} 10 + <button class="btn p-2 flex items-center gap-2 no-underline text-sm" hx-get="/{{ .RepoInfo.FullName }}/description/edit"> 11 edit 12 + {{ i "pencil" "w-3 h-3" }} 13 </button> 14 {{ end }} 15 </span>
+2 -7
appview/pages/templates/fragments/star.html
··· 15 > 16 <div class="flex gap-2 items-center"> 17 {{ if .IsStarred }} 18 - <span class="w-3 h-3 fill-current" data-lucide="star"></span> 19 {{ else }} 20 - <span class="w-3 h-3" data-lucide="star"></span> 21 {{ end }} 22 <span> 23 {{ .Stats.StarCount }} 24 </span> 25 </div> 26 </button> 27 - <script> 28 - document.body.addEventListener('htmx:afterRequest', function (evt) { 29 - lucide.createIcons(); 30 - }); 31 - </script> 32 {{ end }} 33
··· 15 > 16 <div class="flex gap-2 items-center"> 17 {{ if .IsStarred }} 18 + {{ i "star" "w-3 h-3 fill-current" }} 19 {{ else }} 20 + {{ i "star" "w-3 h-3" }} 21 {{ end }} 22 <span> 23 {{ .Stats.StarCount }} 24 </span> 25 </div> 26 </button> 27 {{ end }} 28
-4
appview/pages/templates/layouts/base.html
··· 24 {{ template "layouts/footer" . }} 25 {{ end }} 26 </footer> 27 - <script src="/static/lucide.min.js"></script> 28 - <script> 29 - lucide.createIcons(); 30 - </script> 31 </div> 32 </body> 33 </html>
··· 24 {{ template "layouts/footer" . }} 25 {{ end }} 26 </footer> 27 </div> 28 </body> 29 </html>
+1 -1
appview/pages/templates/layouts/topbar.html
··· 9 <div id="right-items" class="flex gap-2"> 10 {{ with .LoggedInUser }} 11 <a href="/repo/new" hx-boost="true"> 12 - <i class="w-6 h-6" data-lucide="plus"></i> 13 </a> 14 {{ block "dropDown" . }} {{ end }} 15 {{ else }}
··· 9 <div id="right-items" class="flex gap-2"> 10 {{ with .LoggedInUser }} 11 <a href="/repo/new" hx-boost="true"> 12 + {{ i "plus" "w-6 h-6" }} 13 </a> 14 {{ block "dropDown" . }} {{ end }} 15 {{ else }}
+1 -1
appview/pages/templates/repo/commit.html
··· 37 <p class="flex items-center text-sm text-gray-500"> 38 <a href="/{{ $repo }}/commit/{{ $commit.This }}" class="no-underline hover:underline text-gray-500">{{ slice $commit.This 0 8 }}</a> 39 {{ if $commit.Parent }} 40 - <i class="w-3 h-3 mx-1" data-lucide="arrow-left"></i> 41 <a href="/{{ $repo }}/commit/{{ $commit.Parent }}" class="no-underline hover:underline text-gray-500">{{ slice $commit.Parent 0 8 }}</a> 42 {{ end }} 43 </p>
··· 37 <p class="flex items-center text-sm text-gray-500"> 38 <a href="/{{ $repo }}/commit/{{ $commit.This }}" class="no-underline hover:underline text-gray-500">{{ slice $commit.This 0 8 }}</a> 39 {{ if $commit.Parent }} 40 + {{ i "arrow-left" "w-3 h-3 mx-1" }} 41 <a href="/{{ $repo }}/commit/{{ $commit.Parent }}" class="no-underline hover:underline text-gray-500">{{ slice $commit.Parent 0 8 }}</a> 42 {{ end }} 43 </p>
+6 -16
appview/pages/templates/repo/index.html
··· 49 href="/{{ .RepoInfo.FullName }}/commits/{{ .Ref | urlquery }}" 50 class="ml-2 no-underline flex items-center gap-2 text-sm uppercase font-bold" 51 > 52 - <i class="w-4 h-4" data-lucide="logs"></i> 53 {{ .TotalCommits }} 54 {{ if eq .TotalCommits 1 }}commit{{ else }}commits{{ end }} 55 </a> ··· 70 class="{{ $linkstyle }}" 71 > 72 <div class="flex items-center gap-2"> 73 - <i 74 - class="w-3 h-3 fill-current" 75 - data-lucide="folder" 76 - ></i 77 - >{{ .Name }} 78 </div> 79 </a> 80 ··· 95 class="{{ $linkstyle }}" 96 > 97 <div class="flex items-center gap-2"> 98 - <i 99 - class="w-3 h-3" 100 - data-lucide="file" 101 - ></i 102 - >{{ .Name }} 103 </div> 104 </a> 105 ··· 134 class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded" 135 hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')" 136 > 137 - <i 138 - class="w-3 h-3" 139 - data-lucide="ellipsis" 140 - ></i> 141 </button> 142 {{ end }} 143 </div> ··· 182 ></div> 183 {{ end }} 184 {{ range $tagsForCommit }} 185 - <span class="text-xs rounded bg-gray-100 font-mono px-2 mx-1/2 inline-flex items-center"> 186 {{ . }} 187 </span> 188 {{ end }}
··· 49 href="/{{ .RepoInfo.FullName }}/commits/{{ .Ref | urlquery }}" 50 class="ml-2 no-underline flex items-center gap-2 text-sm uppercase font-bold" 51 > 52 + {{ i "logs" "w-4 h-4" }} 53 {{ .TotalCommits }} 54 {{ if eq .TotalCommits 1 }}commit{{ else }}commits{{ end }} 55 </a> ··· 70 class="{{ $linkstyle }}" 71 > 72 <div class="flex items-center gap-2"> 73 + {{ i "folder" "w-3 h-3 fill-current" }} 74 + {{ .Name }} 75 </div> 76 </a> 77 ··· 92 class="{{ $linkstyle }}" 93 > 94 <div class="flex items-center gap-2"> 95 + {{ i "file" "w-3 h-3" }}{{ .Name }} 96 </div> 97 </a> 98 ··· 127 class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded" 128 hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')" 129 > 130 + {{ i "ellipsis" "w-3 h-3" }} 131 </button> 132 {{ end }} 133 </div> ··· 172 ></div> 173 {{ end }} 174 {{ range $tagsForCommit }} 175 + <span class="text-xs rounded bg-gray-100 text-black font-mono px-2 mx-1/2 inline-flex items-center"> 176 {{ . }} 177 </span> 178 {{ end }}
+2 -5
appview/pages/templates/repo/issues/issue.html
··· 19 <div class="inline-flex items-center gap-2"> 20 <div id="state" 21 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }} text-sm"> 22 - <i data-lucide="{{ $icon }}" class="w-4 h-4 mr-1.5 text-white" ></i> 23 <span class="text-white">{{ .State }}</span> 24 </div> 25 <span class="text-gray-500 text-sm"> ··· 100 class="mt-8" 101 > 102 <button type="submit" class="btn hover:bg-{{ $hoverColor }}-300"> 103 - <i 104 - data-lucide="{{ $icon }}" 105 - class="w-4 h-4 mr-2 text-{{ $hoverColor }}-400" 106 - ></i> 107 <span class="text-black">{{ $action }}</span> 108 </button> 109 <div id="issue-action" class="error"></div>
··· 19 <div class="inline-flex items-center gap-2"> 20 <div id="state" 21 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }} text-sm"> 22 + {{ i $icon "w-4 h-4 mr-1.5 text-white" }} 23 <span class="text-white">{{ .State }}</span> 24 </div> 25 <span class="text-gray-500 text-sm"> ··· 100 class="mt-8" 101 > 102 <button type="submit" class="btn hover:bg-{{ $hoverColor }}-300"> 103 + {{ i $icon "w-4 h-4 mr-2" }} 104 <span class="text-black">{{ $action }}</span> 105 </button> 106 <div id="issue-action" class="error"></div>
+2 -2
appview/pages/templates/repo/issues/issues.html
··· 13 <a 14 href="/{{ .RepoInfo.FullName }}/issues/new" 15 class="btn text-sm flex items-center gap-2 no-underline hover:no-underline"> 16 - <i data-lucide="plus" class="w-5 h-5"></i> 17 <span>new issue</span> 18 </a> 19 </div> ··· 44 {{ end }} 45 46 <span class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm"> 47 - <i data-lucide="{{ $icon }}" class="w-3 h-3 mr-1.5 text-white"></i> 48 <span class="text-white">{{ $state }}</span> 49 </span> 50
··· 13 <a 14 href="/{{ .RepoInfo.FullName }}/issues/new" 15 class="btn text-sm flex items-center gap-2 no-underline hover:no-underline"> 16 + {{ i "plus" "w-4 h-4" }} 17 <span>new issue</span> 18 </a> 19 </div> ··· 44 {{ end }} 45 46 <span class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm"> 47 + {{ i $icon "w-3 h-3 mr-1.5 text-white" }} 48 <span class="text-white">{{ $state }}</span> 49 </span> 50
+3 -6
appview/pages/templates/repo/log.html
··· 75 class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded" 76 hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')" 77 > 78 - <i 79 - class="w-3 h-3" 80 - data-lucide="ellipsis" 81 - ></i> 82 </button> 83 {{ end }} 84 </div> ··· 138 hx-boost="true" 139 onclick="window.location.href = window.location.pathname + '?page={{ sub .Page 1 }}'" 140 > 141 - <i data-lucide="chevron-left" class="w-4 h-4"></i> 142 previous 143 </a> 144 {{ else }} ··· 152 onclick="window.location.href = window.location.pathname + '?page={{ add .Page 1 }}'" 153 > 154 next 155 - <i data-lucide="chevron-right" class="w-4 h-4"></i> 156 </a> 157 {{ end }} 158 </div>
··· 75 class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded" 76 hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')" 77 > 78 + {{ i "ellipsis" "w-3 h-3" }} 79 </button> 80 {{ end }} 81 </div> ··· 135 hx-boost="true" 136 onclick="window.location.href = window.location.pathname + '?page={{ sub .Page 1 }}'" 137 > 138 + {{ i "chevron-left" "w-4 h-4" }} 139 previous 140 </a> 141 {{ else }} ··· 149 onclick="window.location.href = window.location.pathname + '?page={{ add .Page 1 }}'" 150 > 151 next 152 + {{ i "chevron-right" "w-4 h-4" }} 153 </a> 154 {{ end }} 155 </div>
+2 -5
appview/pages/templates/repo/pulls/patch.html
··· 10 <header class="pb-2"> 11 <div class="flex gap-3 items-center mb-3"> 12 <a href="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/" class="flex items-center gap-2 font-medium"> 13 - <i data-lucide="arrow-left" class="w-5 h-5"></i> 14 back 15 </a> 16 <span class="select-none before:content-['\00B7']"></span> ··· 40 id="state" 41 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}" 42 > 43 - <i 44 - data-lucide="{{ $icon }}" 45 - class="w-4 h-4 mr-1.5 text-white" 46 - ></i> 47 <span class="text-white">{{ .Pull.State.String }}</span> 48 </div> 49 <span class="text-gray-500 text-sm">
··· 10 <header class="pb-2"> 11 <div class="flex gap-3 items-center mb-3"> 12 <a href="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/" class="flex items-center gap-2 font-medium"> 13 + {{ i "arrow-left" "w-5 h-5" }} 14 back 15 </a> 16 <span class="select-none before:content-['\00B7']"></span> ··· 40 id="state" 41 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}" 42 > 43 + {{ i $icon "w-4 h-4 mr-1.5 text-white" }} 44 <span class="text-white">{{ .Pull.State.String }}</span> 45 </div> 46 <span class="text-gray-500 text-sm">
+24 -20
appview/pages/templates/repo/pulls/pull.html
··· 27 id="state" 28 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}" 29 > 30 - <i 31 - data-lucide="{{ $icon }}" 32 - class="w-4 h-4 mr-1.5 text-white" 33 - ></i> 34 <span class="text-white">{{ .Pull.State.String }}</span> 35 </div> 36 <span class="text-gray-500 text-sm"> ··· 139 <div class="bg-purple-50 border border-purple-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 140 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 141 <div class="flex items-center gap-2 text-purple-500"> 142 - <i data-lucide="git-merge" class="w-4 h-4"></i> 143 <span class="font-medium">pull request successfully merged</span 144 > 145 </div> ··· 148 <div class="bg-red-50 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 149 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 150 <div class="flex items-center gap-2 text-red-500"> 151 - <i data-lucide="alert-triangle" class="w-4 h-4"></i> 152 <span class="font-medium">merge conflicts detected</span> 153 <ul class="text-sm space-y-1"> 154 {{ range .MergeCheck.Conflicts }} 155 {{ if .Filename }} 156 <li class="flex items-center"> 157 - <i 158 - data-lucide="file-warning" 159 - class="w-3 h-3 mr-1.5 text-red-500" 160 - ></i> 161 <span class="font-mono">{{ slice .Filename 0 (sub (len .Filename) 2) }}</span> 162 </li> 163 {{ end }} ··· 169 <div class="bg-green-50 border border-green-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 170 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 171 <div class="flex items-center gap-2 text-green-500"> 172 - <i data-lucide="check-circle" class="w-4 h-4"></i> 173 <span class="font-medium">no conflicts, ready to merge</span> 174 </div> 175 </div> ··· 191 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 192 <div class="flex flex-wrap gap-2"> 193 <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline"> 194 - <i data-lucide="message-square-plus" class="w-4 h-4"></i> 195 <span>comment</span> 196 </button> 197 {{ if and $isPushAllowed $isOpen }} ··· 199 {{ if $isConflicted }} 200 {{ $disabled = "disabled" }} 201 {{ end }} 202 - <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline" {{ $disabled }}> 203 - <i data-lucide="git-merge" class="w-4 h-4"></i> 204 <span>merge</span> 205 </button> 206 {{ end }} 207 208 {{ if and $isPullAuthor $isOpen }} 209 <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline"> 210 - <i data-lucide="rotate-ccw" class="w-4 h-4"></i> 211 <span>resubmit</span> 212 </button> 213 {{ end }} 214 215 {{ if and $isPullAuthor $isPushAllowed $isOpen }} 216 - <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline"> 217 - <i data-lucide="ban" class="w-4 h-4"></i> 218 <span>close</span> 219 </button> 220 {{ end }} 221 222 {{ if and $isPullAuthor $isPushAllowed $isClosed }} 223 - <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline"> 224 - <i data-lucide="circle-dot" class="w-4 h-4"></i> 225 <span>reopen</span> 226 </button> 227 {{ end }} ··· 270 class="rounded relative bg-purple-50 border border-purple-200 p-4"> 271 272 <div class="flex items-center gap-2 text-purple-500"> 273 - <i data-lucide="git-merge" class="w-4 h-4"></i> 274 <span class="font-medium" 275 >pull request successfully merged</span 276 >
··· 27 id="state" 28 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}" 29 > 30 + {{ i $icon "w-4 h-4 mr-1.5 text-white" }} 31 <span class="text-white">{{ .Pull.State.String }}</span> 32 </div> 33 <span class="text-gray-500 text-sm"> ··· 136 <div class="bg-purple-50 border border-purple-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 137 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 138 <div class="flex items-center gap-2 text-purple-500"> 139 + {{ i "git-merge" "w-4 h-4" }} 140 <span class="font-medium">pull request successfully merged</span 141 > 142 </div> ··· 145 <div class="bg-red-50 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 146 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 147 <div class="flex items-center gap-2 text-red-500"> 148 + {{ i "triangle-alert" "w-4 h-4" }} 149 <span class="font-medium">merge conflicts detected</span> 150 <ul class="text-sm space-y-1"> 151 {{ range .MergeCheck.Conflicts }} 152 {{ if .Filename }} 153 <li class="flex items-center"> 154 + {{ i "file-warning" "w-3 h-3 mr-1.5 text-red-500" }} 155 <span class="font-mono">{{ slice .Filename 0 (sub (len .Filename) 2) }}</span> 156 </li> 157 {{ end }} ··· 163 <div class="bg-green-50 border border-green-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 164 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 165 <div class="flex items-center gap-2 text-green-500"> 166 + {{ i "circle-check-big" "w-4 h-4" }} 167 <span class="font-medium">no conflicts, ready to merge</span> 168 </div> 169 </div> ··· 185 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div> 186 <div class="flex flex-wrap gap-2"> 187 <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline"> 188 + {{ i "message-square-plus" "w-4 h-4" }} 189 <span>comment</span> 190 </button> 191 {{ if and $isPushAllowed $isOpen }} ··· 193 {{ if $isConflicted }} 194 {{ $disabled = "disabled" }} 195 {{ end }} 196 + <button 197 + hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge" 198 + hx-swap="none" 199 + hx-confirm="Are you sure you want to merge this pull request?" 200 + class="btn p-2 flex items-center gap-2" {{ $disabled }}> 201 + {{ i "git-merge" "w-4 h-4" }} 202 <span>merge</span> 203 </button> 204 {{ end }} 205 206 {{ if and $isPullAuthor $isOpen }} 207 <button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline"> 208 + {{ i "rotate-ccw" "w-4 h-4" }} 209 <span>resubmit</span> 210 </button> 211 {{ end }} 212 213 {{ if and $isPullAuthor $isPushAllowed $isOpen }} 214 + <button 215 + hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/close" 216 + hx-swap="none" 217 + class="btn p-2 flex items-center gap-2"> 218 + {{ i "ban" "w-4 h-4" }} 219 <span>close</span> 220 </button> 221 {{ end }} 222 223 {{ if and $isPullAuthor $isPushAllowed $isClosed }} 224 + <button 225 + hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/reopen" 226 + hx-swap="none" 227 + class="btn p-2 flex items-center gap-2"> 228 + {{ i "circle-dot" "w-4 h-4" }} 229 <span>reopen</span> 230 </button> 231 {{ end }} ··· 274 class="rounded relative bg-purple-50 border border-purple-200 p-4"> 275 276 <div class="flex items-center gap-2 text-purple-500"> 277 + {{ i "git-merge" "w-4 h-4" }} 278 <span class="font-medium" 279 >pull request successfully merged</span 280 >
+2 -5
appview/pages/templates/repo/pulls/pulls.html
··· 24 href="/{{ .RepoInfo.FullName }}/pulls/new" 25 class="btn text-sm flex items-center gap-2 no-underline hover:no-underline" 26 > 27 - <i data-lucide="git-pull-request" class="w-5 h-5"></i> 28 <span>new pull request</span> 29 </a> 30 </div> ··· 57 <span 58 class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm" 59 > 60 - <i 61 - data-lucide="{{ $icon }}" 62 - class="w-3 h-3 mr-1.5 text-white" 63 - ></i> 64 <span class="text-white">{{ .State.String }}</span> 65 </span> 66
··· 24 href="/{{ .RepoInfo.FullName }}/pulls/new" 25 class="btn text-sm flex items-center gap-2 no-underline hover:no-underline" 26 > 27 + {{ i "git-pull-request" "w-4 h-4" }} 28 <span>new pull request</span> 29 </a> 30 </div> ··· 57 <span 58 class="inline-flex items-center rounded px-2 py-[5px] {{ $bgColor }} text-sm" 59 > 60 + {{ i $icon "w-3 h-3 mr-1.5 text-white" }} 61 <span class="text-white">{{ .State.String }}</span> 62 </span> 63
+2 -2
appview/pages/templates/repo/tree.html
··· 41 <div class="flex justify-between items-center"> 42 <a href="/{{ $.BaseTreeLink }}/{{ .Name }}" class="{{ $linkstyle }}"> 43 <div class="flex items-center gap-2"> 44 - <i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }} 45 </div> 46 </a> 47 <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time> ··· 56 <div class="flex justify-between items-center"> 57 <a href="/{{ $.BaseBlobLink }}/{{ .Name }}" class="{{ $linkstyle }}"> 58 <div class="flex items-center gap-2"> 59 - <i class="w-3 h-3" data-lucide="file"></i>{{ .Name }} 60 </div> 61 </a> 62 <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time>
··· 41 <div class="flex justify-between items-center"> 42 <a href="/{{ $.BaseTreeLink }}/{{ .Name }}" class="{{ $linkstyle }}"> 43 <div class="flex items-center gap-2"> 44 + {{ i "folder" "w-3 h-3 fill-current" }}{{ .Name }} 45 </div> 46 </a> 47 <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time> ··· 56 <div class="flex justify-between items-center"> 57 <a href="/{{ $.BaseBlobLink }}/{{ .Name }}" class="{{ $linkstyle }}"> 58 <div class="flex items-center gap-2"> 59 + {{ i "file" "w-3 h-3" }}{{ .Name }} 60 </div> 61 </a> 62 <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time>
+6 -6
appview/pages/templates/settings.html
··· 36 <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-4"> 37 <div class="flex flex-col gap-1"> 38 <div class="inline-flex items-center gap-4"> 39 - <i class="w-3 h-3" data-lucide="key"></i> 40 <p class="font-bold">{{ .Name }}</p> 41 </div> 42 <p class="text-sm text-gray-500">added {{ .Created | timeFmt }}</p> ··· 48 class="btn text-red-500 hover:text-red-700" 49 title="Delete key" 50 hx-delete="/settings/keys?name={{urlquery .Name}}&rkey={{urlquery .Rkey}}&key={{urlquery .Key}}" 51 - hx-confirm="Are you sure you wish to delete the key '{{ .Name }}'?"> 52 - <i class="w-5 h-5" data-lucide="trash-2"></i> 53 <span class="hidden md:inline">delete</span> 54 </button> 55 </div> ··· 91 <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-4"> 92 <div class="flex flex-col gap-2"> 93 <div class="inline-flex items-center gap-4"> 94 - <i class="w-3 h-3" data-lucide="mail"></i> 95 <p class="font-bold">{{ .Address }}</p> 96 <div class="inline-flex items-center gap-1"> 97 {{ if .Verified }} ··· 114 hx-swap="none" 115 href="#" 116 hx-vals='{"email": "{{ .Address }}"}'> 117 - <i class="w-5 h-5" data-lucide="rotate-cw"></i> 118 <span class="hidden md:inline">resend</span> 119 </button> 120 {{ end }} ··· 135 class="btn text-red-500 hover:text-red-700" 136 title="Delete email" 137 type="submit"> 138 - <i class="w-5 h-5" data-lucide="trash-2"></i> 139 <span class="hidden md:inline">delete</span> 140 </button> 141 </form>
··· 36 <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-4"> 37 <div class="flex flex-col gap-1"> 38 <div class="inline-flex items-center gap-4"> 39 + {{ i "key" "w-3 h-3" }} 40 <p class="font-bold">{{ .Name }}</p> 41 </div> 42 <p class="text-sm text-gray-500">added {{ .Created | timeFmt }}</p> ··· 48 class="btn text-red-500 hover:text-red-700" 49 title="Delete key" 50 hx-delete="/settings/keys?name={{urlquery .Name}}&rkey={{urlquery .Rkey}}&key={{urlquery .Key}}" 51 + hx-confirm="Are you sure you want to delete the key '{{ .Name }}'?"> 52 + {{ i "trash-2" "w-5 h-5" }} 53 <span class="hidden md:inline">delete</span> 54 </button> 55 </div> ··· 91 <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-4"> 92 <div class="flex flex-col gap-2"> 93 <div class="inline-flex items-center gap-4"> 94 + {{ i "mail" "w-3 h-3" }} 95 <p class="font-bold">{{ .Address }}</p> 96 <div class="inline-flex items-center gap-1"> 97 {{ if .Verified }} ··· 114 hx-swap="none" 115 href="#" 116 hx-vals='{"email": "{{ .Address }}"}'> 117 + {{ i "rotate-cw" "w-5 h-5" }} 118 <span class="hidden md:inline">resend</span> 119 </button> 120 {{ end }} ··· 135 class="btn text-red-500 hover:text-red-700" 136 title="Delete email" 137 type="submit"> 138 + {{ i "trash-2" "w-5 h-5" }} 139 <span class="hidden md:inline">delete</span> 140 </button> 141 </form>
+1 -1
appview/pages/templates/timeline.html
··· 22 tangled 23 </div> 24 <div class="italic text-lg"> 25 - tightly-knit social coding, <a href="/login" class="underline inline-flex gap-1 items-center">join now <i data-lucide="arrow-right" class="w-4 h-4"></i></a> 26 <p class="pt-5 px-10 text-sm text-gray-500">Join our IRC channel: <a href="https://web.libera.chat/#tangled"><code>#tangled</code> on Libera Chat</a>. 27 Read an introduction to Tangled <a href="https://blog.tangled.sh/intro">here</a>.</p> 28 </div>
··· 22 tangled 23 </div> 24 <div class="italic text-lg"> 25 + tightly-knit social coding, <a href="/login" class="underline inline-flex gap-1 items-center">join now {{ i "arrow-right" "w-4 h-4" }}</a> 26 <p class="pt-5 px-10 text-sm text-gray-500">Join our IRC channel: <a href="https://web.libera.chat/#tangled"><code>#tangled</code> on Libera Chat</a>. 27 Read an introduction to Tangled <a href="https://blog.tangled.sh/intro">here</a>.</p> 28 </div>
+2 -8
appview/pages/templates/user/profile.html
··· 62 63 {{ if .RepoStats.StarCount }} 64 <div class="flex gap-1 items-center text-sm"> 65 - <span 66 - class="w-3 h-3 fill-current" 67 - data-lucide="star" 68 - ></span> 69 <span>{{ .RepoStats.StarCount }}</span> 70 </div> 71 {{ end }} ··· 100 101 {{ if .RepoStats.StarCount }} 102 <div class="flex gap-1 items-center text-sm"> 103 - <span 104 - class="w-3 h-3 fill-current" 105 - data-lucide="star" 106 - ></span> 107 <span>{{ .RepoStats.StarCount }}</span> 108 </div> 109 {{ end }}
··· 62 63 {{ if .RepoStats.StarCount }} 64 <div class="flex gap-1 items-center text-sm"> 65 + {{ i "star" "w-3 h-3 fill-current" }} 66 <span>{{ .RepoStats.StarCount }}</span> 67 </div> 68 {{ end }} ··· 97 98 {{ if .RepoStats.StarCount }} 99 <div class="flex gap-1 items-center text-sm"> 100 + {{ i "star" "w-3 h-3 fill-current" }} 101 <span>{{ .RepoStats.StarCount }}</span> 102 </div> 103 {{ end }}
-2
appview/state/pull.go
··· 94 } 95 } 96 97 - log.Println(mergeCheckResponse) 98 - 99 s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ 100 LoggedInUser: user, 101 RepoInfo: f.RepoInfo(s, user),
··· 94 } 95 } 96 97 s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ 98 LoggedInUser: user, 99 RepoInfo: f.RepoInfo(s, user),
+6 -5
flake.lock
··· 67 "lucide-src": { 68 "flake": false, 69 "locked": { 70 - "narHash": "sha256-5ipNSxTlQ7627lGgsyZxk7vS1sr9RkrlR8/QMj2Zg6s=", 71 - "type": "file", 72 - "url": "https://unpkg.com/lucide@0.482.0" 73 }, 74 "original": { 75 - "type": "file", 76 - "url": "https://unpkg.com/lucide@0.482.0" 77 } 78 }, 79 "nixpkgs": {
··· 67 "lucide-src": { 68 "flake": false, 69 "locked": { 70 + "lastModified": 1742302029, 71 + "narHash": "sha256-OyPVtpnC4/AAmPq84Wt1r1Gcs48d9KG+UBCtZK87e9k=", 72 + "type": "tarball", 73 + "url": "https://github.com/lucide-icons/lucide/releases/download/0.483.0/lucide-icons-0.483.0.zip" 74 }, 75 "original": { 76 + "type": "tarball", 77 + "url": "https://github.com/lucide-icons/lucide/releases/download/0.483.0/lucide-icons-0.483.0.zip" 78 } 79 }, 80 "nixpkgs": {
+5 -5
flake.nix
··· 12 flake = false; 13 }; 14 lucide-src = { 15 - url = "https://unpkg.com/lucide@0.482.0"; 16 flake = false; 17 }; 18 ia-fonts-src = { ··· 71 src = gitignoreSource ./.; 72 postUnpack = '' 73 pushd source 74 cp -f ${htmx-src} appview/pages/static/htmx.min.js 75 - cp -f ${lucide-src} appview/pages/static/lucide.min.js 76 - mkdir -p appview/pages/static/fonts 77 cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ 78 cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ 79 ${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o appview/pages/static/tw.css ··· 150 pkgs.nixos-shell 151 ]; 152 shellHook = '' 153 cp -f ${htmx-src} appview/pages/static/htmx.min.js 154 - cp -f ${lucide-src} appview/pages/static/lucide.min.js 155 - mkdir -p appview/pages/static/fonts/ 156 cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ 157 cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ 158 '';
··· 12 flake = false; 13 }; 14 lucide-src = { 15 + url = "https://github.com/lucide-icons/lucide/releases/download/0.483.0/lucide-icons-0.483.0.zip"; 16 flake = false; 17 }; 18 ia-fonts-src = { ··· 71 src = gitignoreSource ./.; 72 postUnpack = '' 73 pushd source 74 + mkdir -p appview/pages/static/{fonts,icons} 75 cp -f ${htmx-src} appview/pages/static/htmx.min.js 76 + cp -rf ${lucide-src}/*.svg appview/pages/static/icons/ 77 cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ 78 cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ 79 ${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o appview/pages/static/tw.css ··· 150 pkgs.nixos-shell 151 ]; 152 shellHook = '' 153 + mkdir -p appview/pages/static/{fonts,icons} 154 cp -f ${htmx-src} appview/pages/static/htmx.min.js 155 + cp -rf ${lucide-src}/*.svg appview/pages/static/icons/ 156 cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ 157 cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ 158 '';