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:
1 parent
0f04dbb4b1
commit
1afed741bf
13 files changed
+135
-144
No files matched your search
Executable
+79
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
# Builds artwork/banner.svg, the README's banner: the logo above the "JARL"
|
||||
# wordmark, laid out as on the web UI's login page. It reads both from the
|
||||
# web UI's own sources, so it matches the login page:
|
||||
#
|
||||
# internal/web/static/assets/logo.js the logo's paths (from scripts/logo.py)
|
||||
# internal/web/static/assets/brand.js the wordmark's letters and rule
|
||||
#
|
||||
# The letters and rule take the UI's text and accent colors, switching to
|
||||
# the dark theme's when the viewer prefers dark. Needs only Python; run from
|
||||
# the repository root after changing either file (scripts/logo.py runs it):
|
||||
#
|
||||
# python3 scripts/banner.py
|
||||
import re
|
||||
import sys
|
||||
|
||||
ASSETS = "internal/web/static/assets"
|
||||
OUT = "artwork/banner.svg"
|
||||
|
||||
# The UI's --text and --accent (style.css), light and dark.
|
||||
STYLE = (".t{fill:#1d2330}.a{fill:#2f5fb3}.l{fill:none;stroke:#2f5fb3;stroke-width:2.6}"
|
||||
".d{fill:#2f5fb3;font:700 12.5px system-ui,sans-serif;letter-spacing:.5px}"
|
||||
"@media (prefers-color-scheme:dark){.t{fill:#e3e7ee}.a,.d{fill:#6d9be8}.l{stroke:#6d9be8}}")
|
||||
CLASSES = {"fill": "a", "line": "l", "dns": "d"}
|
||||
|
||||
# The login page's sizes in pixels (style.css): a 104px logo, 10px above a
|
||||
# 220px wordmark whose viewBox is 288 units wide.
|
||||
UNIT = 288 / 220
|
||||
LOGO = round(104 * UNIT, 1)
|
||||
GAP = round(10 * UNIT, 1)
|
||||
|
||||
|
||||
def attrs(src):
|
||||
"""Turns a JS object literal's body ({ cx: 106, "text-anchor": "middle" })
|
||||
into SVG attributes."""
|
||||
out = []
|
||||
for key, val in re.findall(r'"?([\w-]+)"?:\s*("[^"]*"|[\d.]+)', src):
|
||||
val = val.strip('"')
|
||||
out.append(f'class="{CLASSES[val]}"' if key == "class" else f'{key}="{val}"')
|
||||
return " ".join(out)
|
||||
|
||||
|
||||
def main():
|
||||
logo = open(f"{ASSETS}/logo.js").read()
|
||||
view_box = re.search(r'viewBox = "([^"]*)"', logo).group(1)
|
||||
transform = re.search(r'transform = "([^"]*)"', logo).group(1)
|
||||
layers = re.findall(r'\["(#\w+)", "([^"]*)"\]', logo)
|
||||
|
||||
brand = open(f"{ASSETS}/brand.js").read()
|
||||
letters = re.findall(r'\{ x: (\d+), d: "([^"]*)" \}', brand)
|
||||
rule = brand[brand.index("const ruleG"):]
|
||||
rule = rule[:rule.index(");\n")]
|
||||
rule_at = re.search(r'class: "wordmark-rule", transform: "([^"]*)"', rule).group(1)
|
||||
shapes = re.findall(r'el\("(path|circle|text)", \{ ([^}]*) \}(?:, "([^"]*)")?\)', rule)
|
||||
mark_box = re.search(r'viewBox: "(-4 -4 288 162)"', brand).group(1)
|
||||
if len(layers) < 2 or len(letters) != 4 or len(shapes) < 5:
|
||||
sys.exit("banner.py: logo.js or brand.js no longer looks as expected; update the script")
|
||||
|
||||
width, height = 288, LOGO + GAP + 162
|
||||
svg = [f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {width} {height:g}" role="img" aria-label="Jarl">',
|
||||
f"<!-- Generated by scripts/banner.py from {ASSETS}/logo.js and brand.js. -->",
|
||||
f"<title>Jarl</title><style>{STYLE}</style>",
|
||||
f'<svg x="{(width - LOGO) / 2:g}" width="{LOGO:g}" height="{LOGO:g}" viewBox="{view_box}">'
|
||||
f'<g transform="{transform}">'
|
||||
+ "".join(f'<path fill="{fill}" d="{d}"/>' for fill, d in layers) + "</g></svg>",
|
||||
f'<svg y="{LOGO + GAP:g}" width="288" height="162" viewBox="{mark_box}">'
|
||||
'<g class="t" fill-rule="evenodd">'
|
||||
+ "".join(f'<path transform="translate({x} 0)" d="{d}"/>' for x, d in letters) + "</g>"
|
||||
f'<g transform="{rule_at}">'
|
||||
+ "".join(f"<{tag} {attrs(a)}>{text}</{tag}>" if text else f"<{tag} {attrs(a)}/>" for tag, a, text in shapes)
|
||||
+ "</g></svg>",
|
||||
"</svg>"]
|
||||
with open(OUT, "w") as f:
|
||||
f.write("\n".join(svg) + "\n")
|
||||
print(f"{OUT}: {width}x{height:g}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+5
-2
@@ -3,11 +3,13 @@
|
||||
# and white figure on a transparent background), by tracing it into vector
|
||||
# paths with potrace:
|
||||
#
|
||||
# internal/web/static/assets/logo.svg the favicon, and the README's logo
|
||||
# internal/web/static/assets/logo.svg the favicon
|
||||
# internal/web/static/assets/logo.js the same paths for the web UI, which
|
||||
# draws them inline (brand.js), so the
|
||||
# logo appears together with the page
|
||||
#
|
||||
# and then runs scripts/banner.py to rebuild the README's banner.
|
||||
#
|
||||
# Both are a few KB, where the PNG is 650 KB. Needs potrace and ImageMagick
|
||||
# (convert). Run from the repository root after changing the master:
|
||||
#
|
||||
@@ -65,7 +67,8 @@ def main():
|
||||
+ "".join(f' ["{fill}", "{d}"],\n' for fill, d in layers)
|
||||
+ "];\n")
|
||||
for name in ("logo.svg", "logo.js"):
|
||||
print(f"{OUT}/{name}: {os.path.getsize(os.path.join(OUT, name))} bytes")
|
||||
print(f"{OUT}/{name}: {os.path.getsize(os.path.join(OUT, name))} bytes", flush=True)
|
||||
subprocess.run([sys.executable, "scripts/banner.py"], check=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+1
-7
@@ -58,8 +58,7 @@ GOOS=linux GOARCH=$goarch GOARM=$goarm CGO_ENABLED=0 go build -ldflags "$LDFLAGS
|
||||
make --no-print-directory install-files DESTDIR="$root" PREFIX=/usr \
|
||||
UNITDIR=/usr/lib/systemd/system JARLD_BIN="$work/jarld" JARL_BIN="$work/jarl" >/dev/null
|
||||
|
||||
# Debian's machine-readable copyright file, from LICENSE and the bundled
|
||||
# font's licence (the font is embedded in jarld's web UI).
|
||||
# Debian's machine-readable copyright file, from LICENSE.
|
||||
indent() { sed -e 's/^$/./' -e 's/^/ /' "$1"; }
|
||||
{
|
||||
echo "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/"
|
||||
@@ -69,11 +68,6 @@ indent() { sed -e 's/^$/./' -e 's/^/ /' "$1"; }
|
||||
echo "Copyright: $(sed -n 's/^Copyright (c) //p' LICENSE)"
|
||||
echo "License: Expat"
|
||||
indent LICENSE
|
||||
echo
|
||||
echo "Files: internal/web/static/assets/fonts/*"
|
||||
echo "Copyright: 2020 The Cinzel Project Authors"
|
||||
echo "License: OFL-1.1"
|
||||
indent internal/web/static/assets/fonts/Cinzel-OFL.txt
|
||||
} > "$root/usr/share/doc/jarl/copyright"
|
||||
|
||||
for f in postinst prerm postrm; do
|
||||
|
||||
Reference in new issue
Block a user