From 0ec9be330e943340eddd9ce4d3cc12fa59be18f2 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Tue, 18 Aug 2026 06:36:05 +0000 Subject: [PATCH] Add the 'eyes' banner design; seed banners only on select sub pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Banner designs can now ship arbitrary markup as banner.html (canvas + style + script), taking precedence over banner.svg; the artwork is inlined in a div[data-design] wrapper either way, which the editor's live preview preserves (and never re-runs its scripts). The bundled 'eyes' design (themes/eyes/banner.html + banner.css sizing the stage) replaces the eyes canvas script that was embedded in the notes-on-urls page's own banner — the page now just picks the design. Seeds set banners only on select sub pages (the-long-read gradient, canvas-nights stars): the front page no longer gets a banner image and shows the theme's default design. Seed entries carry a banner_design field. --- AGENTS.md | 7 +- docs/design-principles.md | 8 +- frontend/src/SiteEditor.vue | 10 +- frontend/src/assets/pagerite.css | 9 + pagerite/app.py | 3 +- pagerite/seed.py | 153 ++--------- pagerite/themes/eyes/banner.css | 7 + pagerite/themes/eyes/banner.html | 423 +++++++++++++++++++++++++++++++ pagerite/views.py | 35 ++- 9 files changed, 494 insertions(+), 161 deletions(-) create mode 100644 pagerite/themes/eyes/banner.css create mode 100644 pagerite/themes/eyes/banner.html diff --git a/AGENTS.md b/AGENTS.md index 600e813..a08846c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,10 +57,11 @@ not for the public pages. See `docs/design-principles.md` for the design. AFTER the banner design's artwork, so author code (e.g. a ` + diff --git a/pagerite/views.py b/pagerite/views.py index 1bd0ea4..0f3cef4 100644 --- a/pagerite/views.py +++ b/pagerite/views.py @@ -52,11 +52,12 @@ def _theme_names() -> list[str]: def _banner_design_names() -> list[str]: - """Available banner designs: theme folders with banner.css or banner.svg.""" + """Available banner designs: theme folders with artwork and/or styles.""" return sorted( d.name for d in THEMES.iterdir() - if d.is_dir() and ((d / "banner.css").exists() or (d / "banner.svg").exists()) + if d.is_dir() + and any((d / f).exists() for f in ("banner.css", "banner.svg", "banner.html")) ) @@ -284,18 +285,26 @@ def banner_html(menu: dict[str, Node], path: str, theme: str = "") -> HTML: def _design_banner(design: str) -> HTML: - """The design's inline banner SVG (empty for none/unknown designs). + """The design's inline banner artwork (empty for none/unknown designs). - Read from disk on every request: design files are never built/cached, - so editing them on disk shows on the next page load, even in prod.""" + banner.html (arbitrary markup: canvas + style + script...) takes + precedence over banner.svg. Read from disk on every request: design + files are never built/cached, so editing them on disk shows on the + next page load, even in prod. The data-design wrapper marks the + artwork as the design's (not author code), so the site editor's live + banner preview keeps it in place. + """ if not _valid_name(design): return HTML("") - path = THEMES / design / "banner.svg" - if not path.exists(): + html = THEMES / design / "banner.html" + svg = THEMES / design / "banner.svg" + if html.exists(): + body = html.read_text() + elif svg.exists(): + body = svg.read_text() + else: return HTML("") - # data-design marks the artwork as the design's (not author code), so - # the site editor's live banner preview keeps it in place. - return HTML(path.read_text().replace("{body}') def banner_design(menu: dict[str, Node], path: str, theme: str = "") -> str: @@ -316,8 +325,10 @@ def banner_design(menu: dict[str, Node], path: str, theme: str = "") -> str: return front.banner_design if ( _valid_name(theme) - and ((THEMES / theme / "banner.css").exists() - or (THEMES / theme / "banner.svg").exists()) + and any( + (THEMES / theme / f).exists() + for f in ("banner.css", "banner.svg", "banner.html") + ) ): return theme return ""