vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Build out the forge web UI
f09ef39efe44de693748053a7b596ef328fcf06b · Keenan Nemetz · 15d ago · parent 70b70264
Build out the forge web UI Turn the web surface into a compact, server-rendered forge with HTMX as the progressive dynamic layer. - Split templates and assets into embedded files; add a tokenised dark theme, Lucide icons, and vendored HTMX. - Add the repository Overview page and a separate chronological Activity feed with type filters and HTMX fragment updates. - Finish the issue and change workflows: create pages, comments, close/reopen, labels and assignees, approval, discussion, line-anchored review comments, and HTMX list filters. - Add syntax-highlighted blobs, contributor/statistics derivation, branch-aware code browsing, and a repository Runs list. - Add a loopback-only development login for local write testing, with explicit configuration and listener checks. - Extend tests for the new pages, fragments, labels, assignees, anchors, and development login.
server/web/templates/overview.html +129
| @@ -0,0 +1,129 @@ | |||
| 1 | {{define "overview"}} | ||
| 2 | {{template "header" .}} | ||
| 3 | {{template "repohead" (nav .Name "overview")}} | ||
| 4 | |||
| 5 | <div class="repo-sub"> | ||
| 6 | <a class="button" href="/r/{{.Name}}/code">{{icon "code"}}Browse code</a> | ||
| 7 | <details class="clone"> | ||
| 8 | <summary>{{icon "copy"}}Clone</summary> | ||
| 9 | <div class="clone-pop"> | ||
| 10 | <p class="muted">Read only, no credentials:</p> | ||
| 11 | <code>{{.CloneURL}}</code> | ||
| 12 | <p class="muted">Write over SSH with a registered key:</p> | ||
| 13 | <code>git clone {{.SSHURL}}</code> | ||
| 14 | <p><button class="secondary" type="button" data-copy="{{.CloneURL}}">{{icon "copy"}}Copy HTTPS URL</button></p> | ||
| 15 | </div> | ||
| 16 | </details> | ||
| 17 | {{if .Site}}<a class="item" href="{{.Site}}">{{icon "external-link"}}Site</a>{{end}} | ||
| 18 | <span class="item">default branch <code>{{.Ref}}</code></span> | ||
| 19 | </div> | ||
| 20 | |||
| 21 | <div class="overview"> | ||
| 22 | <div class="overview-main"> | ||
| 23 | {{if .Readme}} | ||
| 24 | <div class="filehead"> | ||
| 25 | <span>{{.ReadmeName}}</span> | ||
| 26 | <a href="/r/{{.Name}}/blob/{{esc .Ref}}/{{.ReadmeName}}">view source</a> | ||
| 27 | </div> | ||
| 28 | <article class="md readme">{{.Readme}}</article> | ||
| 29 | {{else if not .Commit}} | ||
| 30 | <div class="card"> | ||
| 31 | <h2>Empty repository</h2> | ||
| 32 | <p class="muted">Nothing has been pushed yet. Add this repository and push a branch:</p> | ||
| 33 | <pre>git remote add origin {{.SSHURL}} | ||
| 34 | git push -u origin {{.Ref}}</pre> | ||
| 35 | </div> | ||
| 36 | {{end}} | ||
| 37 | </div> | ||
| 38 | |||
| 39 | <aside class="overview-side"> | ||
| 40 | <section> | ||
| 41 | <h2 class="with-more"><span>{{icon "git-commit-horizontal"}}Recent commits</span> <a class="more" href="/r/{{.Name}}/commits/{{esc .Ref}}">all</a></h2> | ||
| 42 | {{if .Commits}} | ||
| 43 | <div class="side-list"> | ||
| 44 | {{range .Commits}} | ||
| 45 | <a class="side-commit" href="/r/{{$.Name}}/commit/{{.SHA}}"> | ||
| 46 | <span class="side-subject">{{.Subject}}</span> | ||
| 47 | <span class="side-meta"><span class="sha">{{short .SHA}}</span><span>{{since .When}}</span></span> | ||
| 48 | </a> | ||
| 49 | {{end}} | ||
| 50 | </div> | ||
| 51 | {{else}} | ||
| 52 | <p class="muted">No commits yet.</p> | ||
| 53 | {{end}} | ||
| 54 | </section> | ||
| 55 | |||
| 56 | <section> | ||
| 57 | <h2 class="with-more"><span>{{icon "play"}}Recent runs</span> <a class="more" href="/r/{{.Name}}/runs">all</a></h2> | ||
| 58 | {{if .Runs}} | ||
| 59 | <div class="side-list"> | ||
| 60 | {{range .Runs}} | ||
| 61 | <a class="side-run" href="/r/{{$.Name}}/runs/{{.ID}}"> | ||
| 62 | <span class="side-run-top"> | ||
| 63 | <span class="status {{.Status}}">{{.Status}}</span> | ||
| 64 | <span class="side-subject">{{.Job}}</span> | ||
| 65 | </span> | ||
| 66 | <span class="side-meta">{{if .Tag}}tag {{.Tag}}{{else}}{{.Branch}}{{end}}<span>{{since .Created.Unix}}</span></span> | ||
| 67 | </a> | ||
| 68 | {{end}} | ||
| 69 | </div> | ||
| 70 | {{else}} | ||
| 71 | <p class="muted">No runs yet.</p> | ||
| 72 | {{end}} | ||
| 73 | </section> | ||
| 74 | |||
| 75 | <section> | ||
| 76 | <h2>{{icon "tag"}}Releases</h2> | ||
| 77 | {{if .Tags}} | ||
| 78 | <div class="side-list"> | ||
| 79 | {{range .Tags}} | ||
| 80 | <div class="side-row"> | ||
| 81 | <a href="/r/{{$.Name}}/releases/{{.Name}}">{{.Name}}</a> | ||
| 82 | <span class="muted">{{since .When}}{{if not .Annotated}} · lightweight{{end}}</span> | ||
| 83 | </div> | ||
| 84 | {{end}} | ||
| 85 | </div> | ||
| 86 | {{else}} | ||
| 87 | <p class="muted">No releases yet. A release is an annotated tag.</p> | ||
| 88 | {{end}} | ||
| 89 | </section> | ||
| 90 | |||
| 91 | <section id="contributors"> | ||
| 92 | <h2>{{icon "users"}}Contributors</h2> | ||
| 93 | {{if .Contributors}} | ||
| 94 | <ul class="contributors"> | ||
| 95 | {{range .Contributors}} | ||
| 96 | <li> | ||
| 97 | <span class="avatar c{{.Tone}}" aria-hidden="true">{{.Initial}}</span> | ||
| 98 | <span class="cname">{{.Name}}</span> | ||
| 99 | <span class="muted">{{.Commits}}</span> | ||
| 100 | </li> | ||
| 101 | {{end}} | ||
| 102 | </ul> | ||
| 103 | {{else}} | ||
| 104 | <p class="muted">No commits yet.</p> | ||
| 105 | {{end}} | ||
| 106 | </section> | ||
| 107 | |||
| 108 | {{if .Languages}} | ||
| 109 | <section> | ||
| 110 | <h2>{{icon "code"}}Languages</h2> | ||
| 111 | {{range .Languages}} | ||
| 112 | <div class="lang"> | ||
| 113 | <span>{{.Name}}</span> | ||
| 114 | <span class="muted">{{.Percent}}%</span> | ||
| 115 | <progress class="bar" max="100" value="{{.Percent}}">{{.Percent}}%</progress> | ||
| 116 | </div> | ||
| 117 | {{end}} | ||
| 118 | </section> | ||
| 119 | {{end}} | ||
| 120 | |||
| 121 | <section> | ||
| 122 | <h2>{{icon "list"}}Size</h2> | ||
| 123 | <p class="side-size">{{bytes .Size}}</p> | ||
| 124 | <p class="muted">on <code>{{.Ref}}</code></p> | ||
| 125 | </section> | ||
| 126 | </aside> | ||
| 127 | </div> | ||
| 128 | {{template "footer" .}} | ||
| 129 | {{end}} | ||