/** * The header chrome for the browse pages. * * The chips the toolbar carries — the git branch, the change totals, the live * connection state — and the footer's live line. Everything here is pure string * building over an escaped view model: a branch name, a count, and a status word * are all text a repository can choose, so each one crosses `escapeHtml` before * it reaches the page. The page shell and the page bodies stay in `html.ts`. */ import { escapeHtml } from "../../../lib/escape.ts"; import { GLYPHS } from "../../../lib/tui/glyphs.ts"; import type { GitStatus } from "../git/git.ts"; import type { ChangeIndex } from "../live/live.ts"; /** The header's git chip: the branch, or the detached head; changes are the changes chip's job. */ export function renderGit(git: GitStatus | undefined): string { if (!git) return ""; const name = git.branch ?? git.head; if (!name) return ""; const glyph = git.branch ? GLYPHS.branch : GLYPHS.detached; const aria = git.branch ? `git branch ${git.branch}` : `git detached at ${git.head ?? ""}`; return `${escapeHtml(name)}`; } /** The live chrome a page renders: how often its stream is sent a frame. */ export interface LivePage { intervalMs: number; /** Root-relative folder the page listed; absent on a page with no listing to check. */ dir?: string; /** Revision of the names that listing drew, which the reload control compares against. */ rev?: string; } /** * The header's live controls: the connection chip, and the reload control the * client reveals once the folder the page drew has changed on disk. Both start * hidden, so a page with JS off — or with live status disabled — never shows a * state or a control it cannot keep true; the reload control is not rendered at * all when the page has no listing revision to compare. * * The chip is deliberately not a `role="status"` region: the header is where a * reader looks for the page's state, not a place to announce every change to it. */ export function renderLiveChrome(live: LivePage | undefined): string { if (!live) return ""; const rev = live.rev === undefined ? "" : ` data-dir="${escapeHtml(live.dir ?? "")}" data-rev="${escapeHtml(live.rev)}"`; const chip = ``; if (live.rev === undefined) return chip; return `${chip}`; } /** * The footer's live line, hidden until the first frame: uptime and requests are * server facts the rendered page does not know at build time. */ export function renderLiveStatus(): string { return ``; } /** * The header's changes chip, linking to the diff overview. With live status on, * a hidden shell is always rendered so the chip can appear and disappear as the * working tree changes, without the client inserting elements into the header. */ export function renderChanges(summary: ChangeIndex | undefined, live: LivePage | undefined, base: string): string { const count = summary?.count ?? 0; if (count <= 0) { return live ? `` : ""; } const label = `${count} change${count === 1 ? "" : "s"}`; const insertions = summary?.insertions ?? 0; const deletions = summary?.deletions ?? 0; const totals = insertions + deletions > 0 ? ` +${insertions} −${deletions}` : ""; const aria = `${label} against HEAD${insertions + deletions > 0 ? `, ${insertions} insertions and ${deletions} deletions` : ""}`; return `${escapeHtml(label)}${totals}`; }