Use the JARL wordmark in the header and as the README banner

The header now shows the login page's wordmark letters (without the rule)
instead of "Jarl" set in Cinzel, so the bundled Cinzel font, its preload
and its licence stanza in the .deb's copyright file are removed: the web
UI needs no web font.

The README opens with the login page's banner, the logo above the
wordmark (artwork/banner.svg). scripts/banner.py builds it from the web
UI's logo.js and brand.js, with light and dark colors, and logo.py runs
it after tracing the logo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-08 18:09:41 +00:00
1 parent 0f04dbb4b1
commit 1afed741bf
13 files changed
+135 -144

No files matched your search

+16 -8
View File
@@ -1,10 +1,10 @@
// The Jarl logo and the login page's wordmark, drawn as inline SVG so they
// appear together with the page instead of loading afterwards.
//
// The "JARL" wordmark for the login page: angular Norse-style letters
// drawn as paths (no font needed), over a rule with DNS nodes. The letters
// use the text color and the rule the accent color, so it follows the
// theme.
// The "JARL" wordmark: angular Norse-style letters drawn as paths (no font
// needed). The login page shows it over a rule with DNS nodes; the header
// shows the letters alone. The letters use the text color and the rule the
// accent color, so it follows the theme.
import * as logoData from "./logo.js";
const NS = "http://www.w3.org/2000/svg";
@@ -28,19 +28,27 @@ const letters = [
{ x: 220, d: "M0 0 H18 V84 H40 L58 70 L54 100 H0 Z" },
];
export function wordmark() {
// wordmark returns the login page's wordmark, letters over the rule.
// wordmark({ rule: false, height: 19, cls: "brand-name" }) returns just the
// letters, height pixels tall.
export function wordmark({ rule = true, height, cls = "wordmark" } = {}) {
const letterG = el("g", { fill: "currentColor", "fill-rule": "evenodd" },
...letters.map((l) => el("path", { d: l.d, transform: `translate(${l.x} 0)` })));
if (!rule) {
const attrs = { class: cls, viewBox: "-2 -2 282 104", role: "img", "aria-label": "Jarl" };
if (height) Object.assign(attrs, { height, width: Math.round(height * 282 / 104) });
return el("svg", attrs, el("title", null, "Jarl"), letterG);
}
// The rule: tapered lines, two nodes and a "DNS" node in the middle.
const rule = el("g", { class: "wordmark-rule", transform: "translate(0 118)" },
const ruleG = el("g", { class: "wordmark-rule", transform: "translate(0 118)" },
el("path", { d: "M2 18 L98 15.6 V20.4 Z M278 18 L182 15.6 V20.4 Z", class: "fill" }),
el("circle", { cx: 106, cy: 18, r: 4.6, class: "line" }),
el("path", { d: "M110.6 18 H122 M158 18 H169.4", class: "line" }),
el("circle", { cx: 140, cy: 18, r: 17, class: "line" }),
el("circle", { cx: 174, cy: 18, r: 4.6, class: "line" }),
el("text", { x: 140, y: 22.5, "text-anchor": "middle", class: "dns" }, "DNS"));
return el("svg", { class: "wordmark", viewBox: "-4 -4 288 162", role: "img", "aria-label": "Jarl" },
el("title", null, "Jarl"), letterG, rule);
return el("svg", { class: cls, viewBox: "-4 -4 288 162", role: "img", "aria-label": "Jarl" },
el("title", null, "Jarl"), letterG, ruleG);
}
// logo returns the Jarl logo (traced from artwork/logo.png by