#!/usr/bin/env python3 # Builds artwork/banner.svg, the README's banner: the logo above the # "STEWARD" wordmark and its DHCP rule, 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 shapes (from scripts/logo.py) # internal/web/static/assets/brand.js the wordmark's letters and width # # The rule is drawn here with the same numbers as wordmark() in brand.js; # keep the two in step. 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 json 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}" ".g{fill:#2f5fb3;font:700 17px system-ui,sans-serif;letter-spacing:.5px}" "@media (prefers-color-scheme:dark){.t{fill:#e3e7ee}.a,.g{fill:#6d9be8}.l{stroke:#6d9be8}}") def main(): logo = open(f"{ASSETS}/logo.js").read() view_box = re.search(r'viewBox = "([^"]*)"', logo).group(1) shapes = [json.loads(m) for m in re.findall(r"^ (\[.*\]),$", logo, re.M)] brand = open(f"{ASSETS}/brand.js").read() letters = re.findall(r'\{ x: (\d+), d: "([^"]*)" \}', brand) w = int(re.search(r"^const W = (\d+);", brand, re.M).group(1)) if len(shapes) < 5 or len(letters) != 7: sys.exit("banner.py: logo.js or brand.js no longer looks as expected; update the script") # The login page's sizes in pixels (style.css): a 104px logo, 10px above # a 290px wordmark whose viewBox is W+8 units wide. mark_w, mark_h = w + 8, 176 unit = mark_w / 290 logo_size, gap = round(104 * unit, 1), round(10 * unit, 1) height = logo_size + gap + mark_h c = w / 2 rule = (f'' f'' f'' f'' f'' f'DHCP') def shape(tag, attrs): return f"<{tag} " + " ".join(f'{k}="{v}"' for k, v in attrs.items()) + "/>" svg = [f'', f"", f"Steward", f'' + "".join(shape(t, a) for t, a in shapes) + "", f'' '' + "".join(f'' for x, d in letters) + "" f'{rule}', ""] with open(OUT, "w") as f: f.write("\n".join(svg) + "\n") print(f"{OUT}: {mark_w}x{height:g}") if __name__ == "__main__": sys.exit(main())