Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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}}