diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-24 11:39:36 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-07-30 15:18:55 -0300 |
| commit | cb05c363045bf0e7af5858f6d7bc26f026fa9d70 (patch) | |
| tree | c3e89426ff044ffe339dd3a77e7f3b7115cba636 /vrsite/templates | |
| download | notevi-cb05c363045bf0e7af5858f6d7bc26f026fa9d70.tar.gz notevi-cb05c363045bf0e7af5858f6d7bc26f026fa9d70.zip | |
Diffstat (limited to 'vrsite/templates')
| -rw-r--r-- | vrsite/templates/frag-activity.tmpl | 34 | ||||
| -rw-r--r-- | vrsite/templates/frag-jj.tmpl | 33 | ||||
| -rw-r--r-- | vrsite/templates/frag-note.tmpl | 52 | ||||
| -rw-r--r-- | vrsite/templates/layout.tmpl | 71 | ||||
| -rw-r--r-- | vrsite/templates/page-change.tmpl | 37 | ||||
| -rw-r--r-- | vrsite/templates/page-file.tmpl | 20 | ||||
| -rw-r--r-- | vrsite/templates/page-files.tmpl | 13 | ||||
| -rw-r--r-- | vrsite/templates/page-index.tmpl | 52 | ||||
| -rw-r--r-- | vrsite/templates/page-jj.tmpl | 25 | ||||
| -rw-r--r-- | vrsite/templates/page-notes.tmpl | 43 |
10 files changed, 380 insertions, 0 deletions
diff --git a/vrsite/templates/frag-activity.tmpl b/vrsite/templates/frag-activity.tmpl new file mode 100644 index 0000000..8c15de7 --- /dev/null +++ b/vrsite/templates/frag-activity.tmpl @@ -0,0 +1,34 @@ +{{/* Who is reading the codebase right now, straight off the log tail. */}} +{{define "activity"}} +{{if .Compact}} + <div class="actlist"> + {{range .Sessions}} + <div class="act{{if .Live}} on{{end}}" title="{{.Agent}} · {{.Model}} · {{.Dir}}"> + <span class="chip am{{.Bit}}">{{.Short}}</span> + <span class="what">{{.LastOp}}</span> + <span class="when">{{.Ago}}</span> + </div> + {{end}} + {{if not .Sessions}}<p class="meta hint">nothing logged yet</p>{{end}} + </div> +{{else}} + <table class="acttable"> + <thead><tr><th>agent</th><th>model</th><th>session</th><th>last op</th><th>when</th><th>r/g/n</th><th>dir</th></tr></thead> + <tbody> + {{range .Sessions}} + <tr class="{{if .Live}}on{{end}}"> + <td><span class="chip am{{.Bit}}">{{.Short}}</span>{{if .Live}}<span class="pulse" title="active">●</span>{{end}}</td> + <td>{{.Model}}{{if .Reason}}<span class="meta">/{{.Reason}}</span>{{end}}</td> + <td><code title="{{.ID}}">{{short .ID}}</code></td> + <td class="what">{{.LastOp}}</td> + <td>{{.Ago}}</td> + <td class="meta">{{.Reads}}/{{.Greps}}/{{.Notes}}</td> + <td class="meta dir" title="{{.Dir}}">{{base .Dir}}</td> + </tr> + {{end}} + </tbody> + </table> + {{if not .Sessions}}<p class="meta hint">nothing logged yet</p>{{end}} + <p class="meta">live = active in the last {{.Window}}</p> +{{end}} +{{end}} diff --git a/vrsite/templates/frag-jj.tmpl b/vrsite/templates/frag-jj.tmpl new file mode 100644 index 0000000..b31af53 --- /dev/null +++ b/vrsite/templates/frag-jj.tmpl @@ -0,0 +1,33 @@ +{{/* jj query results. Live-only, so routes are absolute. */}} +{{define "jjrows"}} +{{if .Err}}<p class="err">{{.Err}}</p>{{end}} +{{if .Rows}} +<div class="jjlog"> + {{range .Rows}} + {{if .Blank}}<div class="jjrow blank"><span class="graph">{{.Graph}}</span></div> + {{else if .Op}} + <div class="jjrow"> + <span class="graph">{{.Graph}}</span> + <a class="id" href="/jj?at_op={{.ID}}" title="run the commit log as of this operation">{{.Short}}</a> + <span class="when">{{.When}}</span> + <span class="who">{{.Author}}</span> + <span class="desc">{{.Desc}}</span> + <span class="flags">{{.End}}</span> + </div> + {{else}} + <div class="jjrow"> + <span class="graph">{{.Graph}}</span> + <a class="id" href="/change/{{.ID}}" title="{{.ID}}">{{.Short}}</a> + <code class="commit">{{.CommitShort}}</code> + <span class="when">{{.When}}</span> + <span class="who">{{.Author}}</span> + {{if .Refs}}<span class="refs">{{.Refs}}</span>{{end}} + {{if .Flags}}<span class="flags">{{.Flags}}</span>{{end}} + <a class="desc" href="/files?rev={{.ID}}" title="browse the tree at this change">{{if .Desc}}{{.Desc}}{{else}}(no description){{end}}</a> + </div> + {{end}} + {{end}} +</div> +{{else if not .Err}}<p class="meta hint">no revisions matched</p>{{end}} +{{if .AtOp}}<p class="meta">as of operation <code>{{short .AtOp}}</code> · <a href="/jj?kind=op">back to the op log</a></p>{{end}} +{{end}} diff --git a/vrsite/templates/frag-note.tmpl b/vrsite/templates/frag-note.tmpl new file mode 100644 index 0000000..56f7a8f --- /dev/null +++ b/vrsite/templates/frag-note.tmpl @@ -0,0 +1,52 @@ +{{define "note"}}{{$n := .N}}{{$p := .P}} +<article class="note am{{$n.Agent.Bit}}" id="note-{{$n.ID}}" + data-agent="{{$n.Agent.Name}}" data-model="{{$n.Model}}" data-session="{{$n.Session}}" + data-kind="{{$n.Kind}}" data-file="{{$n.File}}" data-date="{{if not $n.At.IsZero}}{{$n.At.Format "2006-01-02"}}{{end}}"> + <header> + {{if $n.File}}<a href="{{$p.NoteHref $n}}" title="{{$n.File}}">{{base $n.File}}{{lines $n}}</a>{{end}} + {{if $n.Kind}}<em>{{$n.Kind}}</em>{{end}} + <b class="who">{{$n.Agent.Short}}</b> + </header> + <p>{{$n.Text}}</p> + <footer class="meta"> + {{if not $n.At.IsZero}}<time datetime="{{$n.At.Format "2006-01-02T15:04:05Z07:00"}}" title="{{$n.Ago}}">{{$n.When}}</time>{{end}} + {{if $n.Model}}<span class="model">{{$n.Model}}{{if $n.Reason}}/{{$n.Reason}}{{end}}</span>{{end}} + {{if $n.Session}}<code class="sess" title="{{$n.Session}}">{{short $n.Session}}</code>{{end}} + {{if $n.Change}}{{if $p.Live}}<a href="{{$p.Href "change" $n.Change}}"><code>{{short $n.Change}}</code></a>{{else}}<code>{{short $n.Change}}</code>{{end}}{{end}} + </footer> +</article> +{{end}} + +{{define "notelist"}}{{range .Notes}}{{template "note" (dict "N" . "P" $)}}{{end}}{{if not .Notes}}<p class="meta hint empty">no notes match these filters</p>{{end}}{{end}} + +{{/* htmx responses: the list plus an out-of-band count update */}} +{{define "notelist-oob"}}<span id="notecount" hx-swap-oob="true">{{len .Notes}}</span>{{template "notelist" .}}{{end}} + +{{define "note-added"}}{{if .File}}<span id="notecount" hx-swap-oob="true">{{len .File.Notes}}</span>{{end}}{{range .Notes}}{{template "note" (dict "N" . "P" $)}}{{end}}{{end}} + +{{/* the add-a-comment form; live pages only, since it writes to the log */}} +{{define "noteform"}} +<form class="notform" hx-post="{{.Href "notes"}}" hx-target="#notelist" hx-swap="afterbegin" + hx-on::after-request="if(event.detail.successful){this.reset();{{if eq .Kind "notes"}}htmx.trigger('#notefilters','change');{{end}}}" + method="post" action="{{.Href "notes"}}"> + <input type="hidden" name="rev" value="{{.Rev}}"> + <input type="hidden" name="back" value="{{if .File}}{{.Href "code" .File.Path}}{{else}}{{.Href "notes"}}{{end}}"> + <div class="row"> + {{if .File}} + <input type="hidden" name="file" value="{{.File.Path}}"> + <span class="meta on">on <code>{{base .File.Path}}</code></span> + {{else}} + <input type="search" name="file" placeholder="file (optional)" list="filelist" autocomplete="off"> + {{end}} + <input type="number" id="nstart" name="start" min="1" placeholder="from" aria-label="first line"> + <input type="number" id="nend" name="end" min="1" placeholder="to" aria-label="last line"> + <input type="text" name="kind" placeholder="kind" aria-label="kind" list="kindlist" size="6"> + </div> + <textarea name="text" rows="3" placeholder="comment… (⌘/ctrl+enter to post)" required></textarea> + <div class="row end"> + <span class="meta">as <b>{{.User}}</b> → the log</span> + <button type="submit">add note</button> + </div> +</form> +<datalist id="kindlist">{{range .Facets.Kinds}}<option value="{{.}}">{{end}}</datalist> +{{end}} diff --git a/vrsite/templates/layout.tmpl b/vrsite/templates/layout.tmpl new file mode 100644 index 0000000..c3fe250 --- /dev/null +++ b/vrsite/templates/layout.tmpl @@ -0,0 +1,71 @@ +<!doctype html> +<html lang="en"{{if .Live}} data-live="1"{{end}}> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>{{.Title}}</title> +<script> +{const d = document.documentElement, t = localStorage.getItem("vrsite-theme"); + if (t && t !== "system") d.dataset.theme = t; + d.dataset.mode = localStorage.getItem("vrsite-mode") || "trace";} +</script> +<link rel="stylesheet" href="{{.Href "asset" "style.css"}}"> +{{if .Live}}<script src="{{.Href "asset" "htmx.min.js"}}"></script>{{end}} +<script src="{{.Href "asset" "app.js"}}" defer></script> +</head> +<body{{if eq .Kind "file"}} class="with-aside"{{end}} data-kind="{{.Kind}}"> + +<nav aria-label="repository files" id="nav" data-root="{{.Root}}" data-current="{{.Current}}" data-tree="{{.Href "tree"}}"> + <header> + <a class="brand" href="{{.Href ""}}">{{.Site.Title}}</a> + <div class="modes" role="group" aria-label="focus"> + <button type="button" class="mode" data-mode="trace" title="reading coverage (t)">trace</button> + <button type="button" class="mode" data-mode="notes" title="notes and comments (t)">notes</button> + </div> + </header> + {{if and .Live .Rev}} + <p class="meta atrev">browsing <a href="{{.Href "change" .ChangeID}}"><code>{{short .ChangeID}}</code></a> · <a href="/">back to @</a></p> + {{end}} + {{if .Live}} + <div id="activity" class="activity" hx-get="/activity?compact=1" hx-trigger="load, every 3s" hx-swap="innerHTML"></div> + {{end}} + <input id="filefind" class="find" type="search" placeholder="find file…" aria-label="find file" autocomplete="off" spellcheck="false"> + <div id="tree"><p class="meta hint">loading tree…</p></div> + <footer> + <span> + <a href="{{.Href "notes"}}">notes ({{len .Site.Notes}})</a> · + <a href="{{.Href "files"}}">files</a>{{if .Live}} · + <a href="{{.Href "jj"}}">jj</a>{{end}} + </span> + <select id="themesel" aria-label="color scheme"> + <option value="system">system</option> + <option value="dark">dark</option> + <option value="light">light</option> + </select> + </footer> +</nav> + +<main> +{{if .Err}}<p class="err">{{.Err}}</p>{{end}} +{{if eq .Kind "file"}}{{template "page-file" .}} +{{else if eq .Kind "notes"}}{{template "page-notes" .}} +{{else if eq .Kind "files"}}{{template "page-files" .}} +{{else if eq .Kind "jj"}}{{template "page-jj" .}} +{{else if eq .Kind "change"}}{{template "page-change" .}} +{{else}}{{template "page-index" .}}{{end}} +</main> + +{{if eq .Kind "file"}} +<aside aria-label="notes" class="notes-only"> + <header class="asidehead"> + <b>Notes (<span id="notecount">{{len .File.Notes}}</span>)</b> + {{if .Live}}<span class="meta">click a line to attach</span>{{end}} + </header> + {{if .Live}}{{template "noteform" .}}{{end}} + <div id="notelist">{{range .File.Notes}}{{template "note" (dict "N" . "P" $)}}{{end}}</div> + {{if not .File.Notes}}<p class="meta hint">no notes on this file yet</p>{{end}} +</aside> +{{end}} + +</body> +</html> diff --git a/vrsite/templates/page-change.tmpl b/vrsite/templates/page-change.tmpl new file mode 100644 index 0000000..08310e5 --- /dev/null +++ b/vrsite/templates/page-change.tmpl @@ -0,0 +1,37 @@ +{{define "page-change"}} +{{$c := .Change}} +<header class="filehead"> + <h1>{{$c.Row.Short}} <span class="meta">{{$c.Row.Flags}}</span></h1> + <p class="meta"> + commit <code>{{$c.Row.CommitShort}}</code> · {{$c.Row.Author}} · {{$c.Row.When}} + {{if $c.Row.Refs}} · <span class="refs">{{$c.Row.Refs}}</span>{{end}} · + <a href="{{.Href "files" }}">browse the tree here</a> + </p> +</header> + +<section> + {{if $c.Desc}}<pre class="desc">{{$c.Desc}}</pre>{{else}}<p class="meta hint">(no description set)</p>{{end}} + + {{if $c.Parents}} + <p class="meta">parents: + {{range $c.Parents}}<a href="/change/{{.ID}}"><code>{{.Short}}</code></a> {{.Desc}} {{end}} + </p> + {{end}} + + <h2>Changed files <span class="meta">{{$c.Stat}}</span></h2> + {{if $c.Files}} + <table class="changed"> + <tbody> + {{range $c.Files}} + <tr><td class="st st-{{.Status}}">{{.Status}}</td> + <td><a href="/code/{{.Path}}?rev={{$c.Row.ID}}">{{.Path}}</a></td></tr> + {{end}} + </tbody> + </table> + {{else}}<p class="meta hint">no file changes</p>{{end}} + + <h2>Notes recorded at this change <span class="meta">{{len .Notes}}</span></h2> + <div class="notecols">{{range .Notes}}{{template "note" (dict "N" . "P" $)}}{{end}}</div> + {{if not .Notes}}<p class="meta hint">nothing in the log was written while this change was checked out</p>{{end}} +</section> +{{end}} diff --git a/vrsite/templates/page-file.tmpl b/vrsite/templates/page-file.tmpl new file mode 100644 index 0000000..39a8c44 --- /dev/null +++ b/vrsite/templates/page-file.tmpl @@ -0,0 +1,20 @@ +{{define "page-file"}} +<header class="filehead"> + <h1>{{.File.Path}}</h1> + <p class="meta"> + {{if .File.Traced}} + {{range .Site.Agents}}{{if band $.File.Mask .Bit}}<span class="chip am{{.Bit}}">{{.Short}}</span> {{end}}{{end}} + <span class="trace-only"><data value="{{.File.Pct}}">{{.File.Pct}}% read</data> · + {{.File.Reads}} reads · {{.File.Greps}} greps · </span> + <span class="notes-only">{{len .File.Notes}} note{{if ne (len .File.Notes) 1}}s{{end}} · </span> + {{else}}not traced · {{end}}change + {{if .Live}}<a href="{{.Href "change" .File.Change}}"><code>{{short .File.Change}}</code></a>{{else}}<code>{{short .File.Change}}</code>{{end}} + </p> + {{if .File.Patterns}}<p class="meta greps trace-only">grepped: {{range .File.Patterns}}<code>{{.}}</code> {{end}}</p>{{end}} +</header> +{{if .File.Stub}} +<p class="meta stub">{{.File.Stub}}</p> +{{else}} +<div class="codewrap">{{.File.Body}}</div> +{{end}} +{{end}} diff --git a/vrsite/templates/page-files.tmpl b/vrsite/templates/page-files.tmpl new file mode 100644 index 0000000..53757ea --- /dev/null +++ b/vrsite/templates/page-files.tmpl @@ -0,0 +1,13 @@ +{{define "page-files"}} +<header class="filehead"> + <h1>Files</h1> + <p class="meta"> + everything at change <code>{{short .ChangeID}}</code> · + <span class="trace-only">traced files carry a coverage bar</span> + <span class="notes-only">◆ marks files with notes</span> + </p> +</header> +<section class="filetree"> +{{.Tree}} +</section> +{{end}} diff --git a/vrsite/templates/page-index.tmpl b/vrsite/templates/page-index.tmpl new file mode 100644 index 0000000..2c115cc --- /dev/null +++ b/vrsite/templates/page-index.tmpl @@ -0,0 +1,52 @@ +{{define "page-index"}} +<header class="filehead"> + <h1>{{.Site.Title}}</h1> + <p class="meta"> + {{len .Site.All}} files, {{len .Site.Order}} traced · {{len .Site.Notes}} notes · + change <code>{{short .Site.Change}}</code> · theme {{.Site.Theme.Name}} + </p> +</header> + +{{if .Live}} +<section> + <h2>Live <span class="meta">— agents reading this codebase</span></h2> + <div id="activity-full" hx-get="/activity" hx-trigger="load, every 3s" hx-swap="innerHTML"> + <p class="meta hint">…</p> + </div> +</section> +{{end}} + +<section class="trace-only"> + <h2>Agents</h2> + <table> + <thead><tr><th>agent</th><th>model</th><th>effort</th><th>session</th><th>reads</th><th>greps</th><th>notes</th></tr></thead> + <tbody> + {{range .Site.Agents}} + <tr><td><span class="chip am{{.Bit}}">{{.Short}}</span></td> + <td>{{.Model}}</td><td>{{.Reason}}</td><td><code>{{short .Session}}</code></td> + <td>{{.Reads}}</td><td>{{.Greps}}</td><td>{{.Notes}}</td></tr> + {{end}} + </tbody> + </table> +</section> + +<section class="trace-only"> + <h2>Coverage</h2> + <table> + <thead><tr><th>file</th><th>read</th><th>lines</th><th>notes</th></tr></thead> + <tbody> + {{range .Site.Order}}{{with index $.Site.Files .}} + <tr><td><a href="{{$.Href "code" .Path}}">{{.Path}}</a></td> + <td><data class="bar am{{.Mask}}" value="{{.Pct}}" style="--pct:{{.Pct}}%">{{.Pct}}%</data></td> + <td>{{.Covered}}/{{.Total}}</td><td>{{len .Notes}}</td></tr> + {{end}}{{end}} + </tbody> + </table> +</section> + +<section class="notes-only"> + <h2>Latest notes <span class="meta">— <a href="{{.Href "notes"}}">all {{len .Site.Notes}}, with filters</a></span></h2> + <div class="notecols">{{range .Notes}}{{template "note" (dict "N" . "P" $)}}{{end}}</div> + {{if not .Notes}}<p class="meta hint">no notes in the log yet</p>{{end}} +</section> +{{end}} diff --git a/vrsite/templates/page-jj.tmpl b/vrsite/templates/page-jj.tmpl new file mode 100644 index 0000000..5c1381c --- /dev/null +++ b/vrsite/templates/page-jj.tmpl @@ -0,0 +1,25 @@ +{{define "page-jj"}} +<header class="filehead"> + <h1>jj</h1> + <p class="meta"> + read-only queries against the repo — <code>--ignore-working-copy</code>, inline templates, nothing written to disk + </p> +</header> + +<section class="jjpage"> + <form class="jjform" method="get" action="{{.Href "jj"}}" + hx-get="/jj/log" hx-target="#jjout" hx-swap="innerHTML" hx-indicator="#jjbusy"> + <input type="hidden" name="kind" value="log"> + <input type="search" name="revset" value="{{.JJ.Revset}}" placeholder="revset — e.g. @ | ancestors(trunk(), 10) | description(glob:'*fix*')" autocomplete="off" spellcheck="false"> + <input type="number" name="limit" value="{{.JJ.Limit}}" min="1" max="1000" aria-label="limit" title="limit"> + <button type="submit">jj log</button> + <button type="button" hx-get="/jj/op" hx-target="#jjout" hx-include="closest form" hx-indicator="#jjbusy" title="operation log">op log</button> + <span id="jjbusy" class="busy">·</span> + </form> + <p class="meta hint"> + change ids open the change · descriptions browse the tree at that change · + op ids re-run the query <code>--at-operation</code>, which is how you see the repo as it was + </p> + <div id="jjout">{{template "jjrows" .JJ}}</div> +</section> +{{end}} diff --git a/vrsite/templates/page-notes.tmpl b/vrsite/templates/page-notes.tmpl new file mode 100644 index 0000000..974dc64 --- /dev/null +++ b/vrsite/templates/page-notes.tmpl @@ -0,0 +1,43 @@ +{{define "facet"}}<select name="{{.Name}}" aria-label="{{.Label}}"> + <option value="">{{.Label}}</option> + {{range .Values}}<option value="{{.}}"{{if eq . $.Sel}} selected{{end}}>{{if $.Short}}{{short .}}…{{else}}{{.}}{{end}}</option> + {{end}}</select>{{end}} + +{{define "page-notes"}} +<header class="filehead"> + <h1>Notes</h1> + <p class="meta"> + {{len .Site.Notes}} in the log{{if .Live}} · anything you add here is appended to the log — the repo is never touched{{end}} + </p> +</header> + +<section class="notespage"> + {{if .Live}} + <details class="addnote"> + <summary>add a note</summary> + {{template "noteform" .}} + </details> + {{end}} + + <form class="filters" id="notefilters" method="get" action="{{.Href "notes"}}" + {{if .Live}}hx-get="/notes/list" hx-target="#notelist" hx-swap="innerHTML" + hx-trigger="input delay:250ms, change, search" hx-indicator="#notesbusy"{{end}}> + <input type="search" name="text" value="{{.Filter.Text}}" placeholder="search note text…" autocomplete="off"> + <input type="search" name="file" value="{{.Filter.File}}" placeholder="file path…" list="filelist" autocomplete="off"> + {{template "facet" (dict "Name" "agent" "Label" "any agent" "Values" .Facets.Agents "Sel" .Filter.Agent)}} + {{template "facet" (dict "Name" "model" "Label" "any model" "Values" .Facets.Models "Sel" .Filter.Model)}} + {{template "facet" (dict "Name" "session" "Label" "any session" "Values" .Facets.Sessions "Sel" .Filter.Session "Short" true)}} + {{template "facet" (dict "Name" "kind" "Label" "any kind" "Values" .Facets.Kinds "Sel" .Filter.Kind)}} + <span class="dates"> + <label class="datef">from <input type="date" name="from" value="{{.Filter.From}}"></label> + <label class="datef">to <input type="date" name="to" value="{{.Filter.To}}"></label> + </span> + <button type="submit" class="nohx">filter</button> + <button type="button" id="clearfilters">clear</button> + </form> + <datalist id="filelist">{{range .Facets.Files}}<option value="{{.}}">{{end}}</datalist> + + <p class="meta count"><span id="notesbusy" class="busy">·</span><span id="notecount">{{len .Notes}}</span> notes shown</p> + <div id="notelist">{{template "notelist" .}}</div> +</section> +{{end}} |
