Show the build in a footer, linked to its release or commit

The version moves from the header to a "Powered by Jarl" footer. A build
of a release tag (HEAD tagged v<VERSION>, no tracked changes; the release
workflow sets RELEASE_TAG) shows and links the release; any other build
shows and links its commit, marked -modified with uncommitted changes.
jarld version, jarl --version, /status and /auth/whoami report the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-09 14:48:24 +00:00
1 parent b05711b13e
commit db9ebb14dd
14 files changed
+176 -14

No files matched your search

+12 -3
View File
@@ -93,8 +93,7 @@ function layout() {
const header = h("header", { class: "top" },
h("a", { class: "brand", href: "#/", title: "Dashboard" },
logo(30),
wordmark({ rule: false, height: 19, cls: "brand-name" }),
h("span", { class: "brand-version" }, me.version)),
wordmark({ rule: false, height: 19, cls: "brand-name" })),
navEl,
h("div", { class: "spacer" }),
modeEl = h("span"),
@@ -102,7 +101,7 @@ function layout() {
h("a", { href: "#/account", class: "user", title: (me.permissions || []).join("\n") }, me.user.username),
me.admin ? h("a", { href: "#/users" }, "Users") : null,
h("button", { class: "small", onclick: logout }, "Log out"));
mount(app, header, barEl, mainEl);
mount(app, h("div", { class: "shell" }, header, barEl, mainEl, footer(me.build)));
modeHolder = modeEl;
renderNav();
renderBar();
@@ -110,6 +109,16 @@ function layout() {
let modeHolder;
// footer names the Jarl build: the release, or the commit for other
// builds, linked to it in the repository.
function footer(b) {
if (!b) return null;
const what = b.tag ? "release " + b.tag
: b.commit ? "commit " + b.commit + (b.modified ? ", with uncommitted changes" : "") : "version " + b.version;
return h("footer", { class: "site" }, "Powered by ",
h("a", { href: b.url, target: "_blank", rel: "noopener", title: "Jarl " + b.version + ", built from " + what }, "Jarl " + b.label));
}
function renderNav() {
mount(navEl, navItems.map(([key, href, label]) => h("a", { href, class: current.nav === key ? "active" : "" }, label)));
}
+7 -1
View File
@@ -97,7 +97,6 @@ header.top {
header.top .brand { display: inline-flex; align-items: center; gap: 8px; color: var(--text); text-decoration: none; }
header.top .brand .logo { display: block; transition: transform 0.15s; }
header.top .brand .brand-name { display: block; color: var(--text); }
header.top .brand .brand-version { color: var(--muted); font-size: 12px; align-self: flex-end; padding-bottom: 2px; }
header.top .brand:hover { text-decoration: none; }
header.top .brand:hover .brand-name { color: var(--accent); }
header.top .brand:hover .logo { transform: scale(1.06); }
@@ -403,3 +402,10 @@ button.chip:hover { background: var(--accent-soft); border-color: var(--accent);
.swatch.selected { box-shadow: 0 0 0 2px currentColor; }
.swatch:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
tr.selected td { background: var(--accent-soft); }
/* the page footer with the Jarl build */
.shell { min-height: 100vh; display: flex; flex-direction: column; }
.shell > main { flex: 1; width: 100%; }
footer.site { padding: 12px 16px 16px; text-align: center; font-size: 12px; color: var(--muted); }
footer.site a { color: var(--muted); text-decoration: underline; text-decoration-color: var(--border); text-underline-offset: 2px; }
footer.site a:hover { color: var(--accent); text-decoration-color: currentColor; }