From ed85f673f4eba477c5b3ffc39649f1e80077712a Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Sun, 5 Jul 2026 12:58:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(y2k):=20Wave=20A=20theme-fleet=20build=20?= =?UTF-8?q?=E2=80=94=2049=20overrides,=207=20templates,=20band=20persona?= =?UTF-8?q?=20(WO-TF-026)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rebuild the y2k theme to the OVERRIDE-CONTRACT (frozen cms a0f07e2ae) with the locked musician/band persona: liquid chrome, frosted-plastic bevels, gradient mesh, marquees, glitter, a webring, and a dependency-free canvas metaball hero. - All 49 mandatory builtin overrides in templates/overrides/y2k/ + manifest template_overrides; every content/provider field preserved from the frozen builtin default, only the chrome re-skinned (legacy button/card field reads already reconciled to link/style/label + text/media). - 7 page templates: default, full-width, landing, article, blog-index, contact, auth — chrome header, glitter backdrop, chrome footer. - Hero override ships a GO-BIG canvas liquid-chrome metaball showpiece (hero/landing only): lazy-init on view, prefers-reduced-motion honored, static chrome-mesh no-JS fallback, dependency-free. - Persona blocks (5): waveform_player, tracklist, tour_dates, discography, webring_badge. Duplicating theme blocks became overrides; nft_gallery DELETED per WO. - 5 dual-mode presets (frosted iMac plastic light + rave blacklight dark), all 19 tokens, mode both, tuned dark. - Bundled OFL fonts (Orbitron / Inter / Share Tech Mono) with licenses; all font-family via var(--font-heading|body|mono, fallback). Updated RECOMMENDED_FONTS/ICONS; required_icon_packs declared. - Themed email-safe wrapper (tables, inline styles, chrome header, marquee footer). Master pages + demo seed (home/about/blog x3/contact/login) in band voice; contact form wired to seeded contact_submissions + row_inserted email-admins workflow. Known platform gaps (OVERRIDE-CONTRACT §11/§12, unchanged): auth trio + page-suggestions don't dispatch overrides yet; provider-backed overrides render empty live lists until the codeless loader registers template sources. Files authored faithful to builtin field/provider names; they light up when the cms fix lands. Visual quality UNVERIFIED until Wave B. Gates: `make` exit 0 (codeless y2k-0.2.0.bnp), `ninja plugin verify` OK, check-safety exit 0. Co-Authored-By: Claude Opus 4.8 --- RECOMMENDED_FONTS.md | 66 +-- RECOMMENDED_ICONS.md | 15 + assets/fonts/LICENSES.md | 25 + assets/fonts/inter-latin.woff2 | Bin 0 -> 48256 bytes assets/fonts/orbitron-latin.woff2 | Bin 0 -> 11800 bytes assets/fonts/share-tech-mono-latin.woff2 | Bin 0 -> 13500 bytes assets/placeholder.txt | 5 - blocks/blocks.yaml | 69 +-- blocks/chrome_navbar.ninjatpl | 12 - blocks/chrome_navbar.schema.json | 29 - blocks/discography.ninjatpl | 23 + blocks/discography.sample.json | 9 + blocks/discography.schema.json | 30 + blocks/footer_chrome.ninjatpl | 7 - blocks/footer_chrome.schema.json | 30 - blocks/glitter_divider.ninjatpl | 6 - blocks/glitter_divider.schema.json | 15 - blocks/marquee.ninjatpl | 5 - blocks/marquee.schema.json | 32 - blocks/merch_card.ninjatpl | 13 - blocks/merch_card.schema.json | 41 -- blocks/metaball_hero.ninjatpl | 32 - blocks/metaball_hero.schema.json | 44 -- blocks/nft_gallery.ninjatpl | 9 - blocks/nft_gallery.schema.json | 41 -- blocks/tour_dates.ninjatpl | 23 + blocks/tour_dates.sample.json | 9 + blocks/tour_dates.schema.json | 36 ++ blocks/waveform_player.ninjatpl | 8 +- fonts.json | 29 +- manifest.yaml | 551 +++++++++++++----- master_pages.json | 26 +- plugin.mod | 5 +- presets.json | 338 +++++++---- seed/seed.json | 222 +++++++ seed/workflows.json | 19 + templates/email/y2k.ninjatpl | 2 +- .../overrides/y2k/announcement-bar.ninjatpl | 21 + templates/overrides/y2k/audio-embed.ninjatpl | 16 + templates/overrides/y2k/auth-form.ninjatpl | 77 +++ templates/overrides/y2k/auth-status.ninjatpl | 36 ++ .../overrides/y2k/author-bio-hero.ninjatpl | 22 + templates/overrides/y2k/author-bio.ninjatpl | 13 + templates/overrides/y2k/blog-hero.ninjatpl | 24 + templates/overrides/y2k/breadcrumbs.ninjatpl | 15 + templates/overrides/y2k/button.ninjatpl | 3 +- templates/overrides/y2k/card.ninjatpl | 2 + .../overrides/y2k/category-list.ninjatpl | 18 + templates/overrides/y2k/contact-card.ninjatpl | 18 + templates/overrides/y2k/contact-form.ninjatpl | 40 ++ templates/overrides/y2k/countdown.ninjatpl | 50 ++ templates/overrides/y2k/cta.ninjatpl | 16 + templates/overrides/y2k/divider.ninjatpl | 2 + templates/overrides/y2k/event-list.ninjatpl | 41 ++ templates/overrides/y2k/faq.ninjatpl | 18 + templates/overrides/y2k/feature-grid.ninjatpl | 19 + .../overrides/y2k/featured-posts.ninjatpl | 23 + templates/overrides/y2k/footer.ninjatpl | 39 ++ templates/overrides/y2k/gallery.ninjatpl | 52 ++ templates/overrides/y2k/heading.ninjatpl | 8 +- templates/overrides/y2k/hero.ninjatpl | 107 ++++ .../overrides/y2k/hours-location.ninjatpl | 31 + templates/overrides/y2k/image.ninjatpl | 3 +- templates/overrides/y2k/logo-strip.ninjatpl | 16 + templates/overrides/y2k/menu-list.ninjatpl | 30 + templates/overrides/y2k/navbar.ninjatpl | 104 ++++ .../overrides/y2k/newsletter-signup.ninjatpl | 12 + .../overrides/y2k/page-suggestions.ninjatpl | 13 + .../y2k/password-reset-form.ninjatpl | 13 + .../overrides/y2k/popular-posts.ninjatpl | 16 + templates/overrides/y2k/post-hero.ninjatpl | 23 + .../overrides/y2k/post-metadata.ninjatpl | 9 + templates/overrides/y2k/pricing.ninjatpl | 26 + templates/overrides/y2k/quote.ninjatpl | 2 + .../overrides/y2k/related-posts.ninjatpl | 17 + templates/overrides/y2k/rich-section.ninjatpl | 14 + templates/overrides/y2k/rich-text.ninjatpl | 2 + templates/overrides/y2k/sidebar-nav.ninjatpl | 15 + templates/overrides/y2k/social-links.ninjatpl | 14 + templates/overrides/y2k/stats.ninjatpl | 50 ++ templates/overrides/y2k/team.ninjatpl | 22 + templates/overrides/y2k/testimonial.ninjatpl | 27 + templates/overrides/y2k/text.ninjatpl | 3 +- templates/overrides/y2k/timeline.ninjatpl | 22 + templates/overrides/y2k/utility-bar.ninjatpl | 10 + templates/overrides/y2k/video-embed.ninjatpl | 23 + templates/y2k/article.ninjatpl | 25 +- templates/y2k/auth.ninjatpl | 14 + templates/y2k/blog-index.ninjatpl | 12 + templates/y2k/contact.ninjatpl | 12 + templates/y2k/default.ninjatpl | 17 +- templates/y2k/full-width.ninjatpl | 17 +- templates/y2k/landing.ninjatpl | 23 +- 93 files changed, 2397 insertions(+), 746 deletions(-) create mode 100644 RECOMMENDED_ICONS.md create mode 100644 assets/fonts/LICENSES.md create mode 100644 assets/fonts/inter-latin.woff2 create mode 100644 assets/fonts/orbitron-latin.woff2 create mode 100644 assets/fonts/share-tech-mono-latin.woff2 delete mode 100644 assets/placeholder.txt delete mode 100644 blocks/chrome_navbar.ninjatpl delete mode 100644 blocks/chrome_navbar.schema.json create mode 100644 blocks/discography.ninjatpl create mode 100644 blocks/discography.sample.json create mode 100644 blocks/discography.schema.json delete mode 100644 blocks/footer_chrome.ninjatpl delete mode 100644 blocks/footer_chrome.schema.json delete mode 100644 blocks/glitter_divider.ninjatpl delete mode 100644 blocks/glitter_divider.schema.json delete mode 100644 blocks/marquee.ninjatpl delete mode 100644 blocks/marquee.schema.json delete mode 100644 blocks/merch_card.ninjatpl delete mode 100644 blocks/merch_card.schema.json delete mode 100644 blocks/metaball_hero.ninjatpl delete mode 100644 blocks/metaball_hero.schema.json delete mode 100644 blocks/nft_gallery.ninjatpl delete mode 100644 blocks/nft_gallery.schema.json create mode 100644 blocks/tour_dates.ninjatpl create mode 100644 blocks/tour_dates.sample.json create mode 100644 blocks/tour_dates.schema.json create mode 100644 seed/seed.json create mode 100644 seed/workflows.json create mode 100644 templates/overrides/y2k/announcement-bar.ninjatpl create mode 100644 templates/overrides/y2k/audio-embed.ninjatpl create mode 100644 templates/overrides/y2k/auth-form.ninjatpl create mode 100644 templates/overrides/y2k/auth-status.ninjatpl create mode 100644 templates/overrides/y2k/author-bio-hero.ninjatpl create mode 100644 templates/overrides/y2k/author-bio.ninjatpl create mode 100644 templates/overrides/y2k/blog-hero.ninjatpl create mode 100644 templates/overrides/y2k/breadcrumbs.ninjatpl create mode 100644 templates/overrides/y2k/card.ninjatpl create mode 100644 templates/overrides/y2k/category-list.ninjatpl create mode 100644 templates/overrides/y2k/contact-card.ninjatpl create mode 100644 templates/overrides/y2k/contact-form.ninjatpl create mode 100644 templates/overrides/y2k/countdown.ninjatpl create mode 100644 templates/overrides/y2k/cta.ninjatpl create mode 100644 templates/overrides/y2k/divider.ninjatpl create mode 100644 templates/overrides/y2k/event-list.ninjatpl create mode 100644 templates/overrides/y2k/faq.ninjatpl create mode 100644 templates/overrides/y2k/feature-grid.ninjatpl create mode 100644 templates/overrides/y2k/featured-posts.ninjatpl create mode 100644 templates/overrides/y2k/footer.ninjatpl create mode 100644 templates/overrides/y2k/gallery.ninjatpl create mode 100644 templates/overrides/y2k/hero.ninjatpl create mode 100644 templates/overrides/y2k/hours-location.ninjatpl create mode 100644 templates/overrides/y2k/logo-strip.ninjatpl create mode 100644 templates/overrides/y2k/menu-list.ninjatpl create mode 100644 templates/overrides/y2k/navbar.ninjatpl create mode 100644 templates/overrides/y2k/newsletter-signup.ninjatpl create mode 100644 templates/overrides/y2k/page-suggestions.ninjatpl create mode 100644 templates/overrides/y2k/password-reset-form.ninjatpl create mode 100644 templates/overrides/y2k/popular-posts.ninjatpl create mode 100644 templates/overrides/y2k/post-hero.ninjatpl create mode 100644 templates/overrides/y2k/post-metadata.ninjatpl create mode 100644 templates/overrides/y2k/pricing.ninjatpl create mode 100644 templates/overrides/y2k/quote.ninjatpl create mode 100644 templates/overrides/y2k/related-posts.ninjatpl create mode 100644 templates/overrides/y2k/rich-section.ninjatpl create mode 100644 templates/overrides/y2k/rich-text.ninjatpl create mode 100644 templates/overrides/y2k/sidebar-nav.ninjatpl create mode 100644 templates/overrides/y2k/social-links.ninjatpl create mode 100644 templates/overrides/y2k/stats.ninjatpl create mode 100644 templates/overrides/y2k/team.ninjatpl create mode 100644 templates/overrides/y2k/testimonial.ninjatpl create mode 100644 templates/overrides/y2k/timeline.ninjatpl create mode 100644 templates/overrides/y2k/utility-bar.ninjatpl create mode 100644 templates/overrides/y2k/video-embed.ninjatpl create mode 100644 templates/y2k/auth.ninjatpl create mode 100644 templates/y2k/blog-index.ninjatpl create mode 100644 templates/y2k/contact.ninjatpl diff --git a/RECOMMENDED_FONTS.md b/RECOMMENDED_FONTS.md index 7d80228..3cc9d08 100644 --- a/RECOMMENDED_FONTS.md +++ b/RECOMMENDED_FONTS.md @@ -1,50 +1,36 @@ # Recommended fonts for the Y2K theme -The Y2K theme ships `fonts.json = []` per the wave-1 fonts policy -(`~/src/blockninja/themes/docs/FONTS.md`). The theme CSS consumes fonts via -the host CSS custom properties `--font-heading`, `--font-body`, `--font-mono` -with fallback stacks tuned to match the spec's intended aesthetic. +The Y2K theme **bundles** three OFL families as latin-subset woff2 (see +`assets/fonts/LICENSES.md`). They register as `source=template` rows and are +selectable in the typography picker. The theme CSS consumes fonts only through +the host CSS custom properties `--font-heading`, `--font-body`, `--font-mono`, +with fallback stacks that lead with the bundled families — so the intended look +survives before an admin assigns anything. -To get the intended Y2K look, an admin should open the typography panel and -assign the following Google Fonts (or upload the licensed picks where noted): +## Bundled (works out of the box) -## Heading (display) +| Slot | Family | Notes | +|---|---|---| +| Heading / display | **Orbitron** (OFL) | Geometric techno face for chrome-stretched headlines. | +| Body | **Inter** (OFL) | Clean neutral body. | +| Mono | **Share Tech Mono** (OFL) | Eyebrows, kickers, tabular data, the webring badge. | -- **Stretch Pro** — commercial, not in the Google Fonts curated list. - - Source: `upload:Stretch Pro` (admin must source the woff2 separately and - upload via the typography panel's Upload tab). - - Why: matches the spec's primary display face for chrome-stretched - headlines. -- **VT323** — open license, available in Google Fonts. - - Source: `google:VT323`. - - Instruction: Open the typography panel, switch to the Google Fonts tab, - search "VT323", click Add, then assign it to the Heading slot. Use this - when Stretch Pro is not licensed for the site. +Assign each to its slot in the typography panel (they appear under the bundled / +template source). Until then, the fallback stacks below apply automatically. -## Body +## Fallback stacks (declared in `manifest.yaml` CSS) -- **Inter Tight** — open license, available in Google Fonts. - - Source: `google:Inter Tight`. - - Instruction: Open the typography panel, switch to the Google Fonts tab, - search "Inter Tight", click Add, then assign it to the Body slot. +- Heading: `var(--font-heading, "Orbitron", "Michroma", system-ui, sans-serif)` +- Body: `var(--font-body, "Inter", system-ui, -apple-system, "Segoe UI", sans-serif)` +- Mono: `var(--font-mono, "Share Tech Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, monospace)` -## Mono +## Alternatives from the Google Fonts tab -- **Departure Mono** — open license, available as a single-foundry download. - - Source: `upload:Departure Mono` (sourced from - https://departuremono.com — admin uploads the woff2 via the Upload tab). - - Instruction: After uploading the woff2, assign it to the Mono slot in the - typography panel. +- **Michroma** (OFL) — wider techno display; a strong Orbitron alternative for the + Heading slot. Open the typography panel, Google Fonts tab, search "Michroma", + Add, assign to Heading. +- **Inter Tight** (OFL) — tighter body option; assign to Body the same way. -## What works out of the box - -Until an admin assigns fonts, the theme renders with the following fallback -stacks (declared in `css.go` via the host Tailwind input): - -- Headings: `var(--font-heading, "Stretch Pro", "VT323", "Courier New", monospace)` -- Body: inherited from the host `--font-body` with default - `system-ui, -apple-system, Segoe UI, Roboto, sans-serif`. -- Mono: inherited from the host `--font-mono` with default - `ui-monospace, "Departure Mono", "JetBrains Mono", monospace`. - -These keep the theme readable and on-brand even before any picker action. +The bundled subsets cover English (Latin + Latin-1 punctuation). Sites needing +extended Latin, Cyrillic, Greek, or Vietnamese should assign the full family from +the Google Fonts tab instead of relying on the bundled subset. diff --git a/RECOMMENDED_ICONS.md b/RECOMMENDED_ICONS.md new file mode 100644 index 0000000..111bb47 --- /dev/null +++ b/RECOMMENDED_ICONS.md @@ -0,0 +1,15 @@ +# Recommended icon packs for the Y2K theme + +The theme renders icons only as sprite references +(``) and declares its packs in +`plugin.mod` `required_icon_packs`. The loader does not yet auto-install packs, +so install these before activation: + +| Pack | Why | Install | +|---|---|---| +| **lucide** | Default UI glyphs used across overrides and the persona blocks (music, disc, arrow, mail, user, etc.). Bundled with the CMS. | Open `/admin/icons`, confirm Lucide is installed and enabled (it ships with the CMS). | +| **simple-icons** | Brand marks for social links and OAuth buttons (github, instagram, youtube, spotify, bandcamp, google, facebook). Bundled with the CMS. | Open `/admin/icons`, confirm Simple Icons is installed and enabled. | + +Both packs ship bundled with the CMS, so no download is normally required — just +confirm they are enabled under `/admin/icons`. Block schemas default their icon +fields to Lucide names, so the theme renders correctly out of the box. diff --git a/assets/fonts/LICENSES.md b/assets/fonts/LICENSES.md new file mode 100644 index 0000000..bb7cfca --- /dev/null +++ b/assets/fonts/LICENSES.md @@ -0,0 +1,25 @@ +# Bundled font licenses — Y2K theme + +All three families are bundled as latin-subset `.woff2` and are licensed under the +SIL Open Font License 1.1 (OFL). Redistribution inside this theme artifact is permitted. + +| File | Family | License | Source | +|---|---|---|---| +| `orbitron-latin.woff2` | Orbitron (variable, wght 500–900) | OFL 1.1 | Google Fonts (fonts.gstatic.com, v35), latin subset | +| `share-tech-mono-latin.woff2` | Share Tech Mono (400) | OFL 1.1 | Google Fonts (fonts.gstatic.com, v16), latin subset | +| `inter-latin.woff2` | Inter (variable, wght 400–700) | OFL 1.1 | Google Fonts (fonts.gstatic.com, v20), latin subset | + +OFL 1.1 full text: https://openfontlicense.org + +- Orbitron (c) The Orbitron Project Authors (Matt McInerney). +- Share Tech Mono (c) Carrois Apostrophe. +- Inter (c) The Inter Project Authors (Rasmus Andersson). + +These are the Google-hosted latin subsets (Latin + Latin-1 punctuation), chosen to keep +the bundle small (~73 KB total). They cover English content; sites needing extended Latin, +Cyrillic, Greek, or Vietnamese glyphs should assign the full family from the admin Google +Fonts picker instead. + +Orbitron is the geometric techno display face. Michroma (also OFL) is an equally good +heading alternative and is called out in the fallback stack; assign it from the Google +Fonts tab if you prefer its wider proportions. diff --git a/assets/fonts/inter-latin.woff2 b/assets/fonts/inter-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d15208de03cd1ad7c5199f0a0ce915fe841e4722 GIT binary patch literal 48256 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∾Na#*TBTU(!jF?9zmR-!C*+RdvGrd0&{`| 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 literal 0 HcmV?d00001 diff --git a/assets/placeholder.txt b/assets/placeholder.txt deleted file mode 100644 index e5324b3..0000000 --- a/assets/placeholder.txt +++ /dev/null @@ -1,5 +0,0 @@ -Y2K theme assets directory. - -This pass ships no bundled fonts or images (fonts.json = []). -Add woff2 files under fonts/ and reference them from fonts.json once font -licensing has been resolved (see RECOMMENDED_FONTS.md). diff --git a/blocks/blocks.yaml b/blocks/blocks.yaml index 40f8232..210510f 100644 --- a/blocks/blocks.yaml +++ b/blocks/blocks.yaml @@ -1,66 +1,43 @@ -# Y2K theme block definitions (codeless .bnp, WO-WZ-021). +# Y2K theme persona block definitions (codeless .bnp, WO-TF-026). # Keys are fully qualified (y2k:) because the codeless loader registers # definitions verbatim — there is no PluginBlockRegistry prefixing in the # codeless path (unlike the wasm/templ path). The qualified keys match the -# hardcoded data-block-key attributes and the master_pages.json references. +# data-block attributes and the master_pages.json / seed references. +# +# Builtin-duplicating blocks (navbar, footer, hero, divider, marquee-> +# announcement-bar, merch->pricing/card) are NOT theme blocks — they are +# template overrides in templates/overrides/y2k/. The old nft_gallery block is +# DELETED per WO-TF-026. Only true band/musician persona furniture lives here. blocks: - - key: y2k:chrome_navbar - title: Chrome Navbar - description: Beveled chrome navigation bar with hover sparkle. - category: navigation - schema: chrome_navbar.schema.json - template: chrome_navbar.ninjatpl - - key: y2k:metaball_hero - title: Metaball Hero - description: SVG metaballs on a gradient mesh canvas with headline + CTA. - category: layout - schema: metaball_hero.schema.json - template: metaball_hero.ninjatpl - key: y2k:waveform_player title: Waveform Player - description: Soundcloud-style audio player with a canvas waveform. + description: Track card with cover art, a static chrome equalizer strip, and a native audio player. category: content schema: waveform_player.schema.json template: waveform_player.ninjatpl - - key: y2k:marquee - title: Marquee Ticker - description: Scrolling text marquee with chrome edges; pauses on hover. - category: layout - schema: marquee.schema.json - template: marquee.ninjatpl - key: y2k:tracklist title: Tracklist - description: Tabular tracklist styled like a CD jewel case insert. + description: Numbered tracklist styled like a CD jewel-case insert with durations. category: content schema: tracklist.schema.json template: tracklist.ninjatpl - - key: y2k:merch_card - title: Merch Card - description: Plastic-bevel product card with a corner sticker badge. + - key: y2k:tour_dates + title: Tour Dates + description: Live dates with venue, city, sold-out state, and a ticket link. category: content - schema: merch_card.schema.json - template: merch_card.ninjatpl + schema: tour_dates.schema.json + template: tour_dates.ninjatpl + sample_data: tour_dates.sample.json + - key: y2k:discography + title: Discography + description: Grid of releases with cover art, year, and format. + category: content + schema: discography.schema.json + template: discography.ninjatpl + sample_data: discography.sample.json - key: y2k:webring_badge title: Webring Badge - description: Canonical 88x31 webring button row with prev/next/ring links. + description: Canonical 88x31 webring button row with prev / ring / next links. category: navigation schema: webring_badge.schema.json template: webring_badge.ninjatpl - - key: y2k:glitter_divider - title: Glitter Divider - description: Animated sparkle horizontal rule. - category: layout - schema: glitter_divider.schema.json - template: glitter_divider.ninjatpl - - key: y2k:footer_chrome - title: Chrome Footer - description: Beveled chrome footer strip with optional webring and copyright. - category: layout - schema: footer_chrome.schema.json - template: footer_chrome.ninjatpl - - key: y2k:nft_gallery - title: NFT Gallery - description: Holographic-foil hover gallery for NFT items (presentational only). - category: content - schema: nft_gallery.schema.json - template: nft_gallery.ninjatpl diff --git a/blocks/chrome_navbar.ninjatpl b/blocks/chrome_navbar.ninjatpl deleted file mode 100644 index 89e7fbe..0000000 --- a/blocks/chrome_navbar.ninjatpl +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/blocks/chrome_navbar.schema.json b/blocks/chrome_navbar.schema.json deleted file mode 100644 index 7c16f1b..0000000 --- a/blocks/chrome_navbar.schema.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Chrome Navbar", - "description": "Beveled chrome navigation bar with hover sparkle and brand mark.", - "type": "object", - "properties": { - "menuName": { - "type": "string", - "title": "Menu", - "description": "Menu to render as the primary nav.", - "x-editor": "menu-select", - "default": "main" - }, - "logoText": { - "type": "string", - "title": "Logo Text", - "description": "Brand wordmark (used when no logo image is set).", - "x-editor": "text", - "default": "" - }, - "logoImage": { - "type": "string", - "title": "Logo Image", - "description": "Optional brand image. Overrides logo text when set.", - "x-editor": "media", - "default": "" - } - } -} diff --git a/blocks/discography.ninjatpl b/blocks/discography.ninjatpl new file mode 100644 index 0000000..5cb7184 --- /dev/null +++ b/blocks/discography.ninjatpl @@ -0,0 +1,23 @@ +{# y2k:discography — grid of releases with cover art, year, format, and a link. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if releases %} +
+ {% for release in releases %} +
+
+ {% if release.link %}{% if release.cover %}{% img release.cover alt=release.title class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" %}{% else %}{% endif %}{% elif release.cover %}{% img release.cover alt=release.title class="h-full w-full object-cover" %}{% else %}{% endif %} +
+
+ {% if release.title %}

{% if release.link %}{{ release.title }}{% else %}{{ release.title }}{% endif %}

{% endif %} +

{% if release.year %}{{ release.year }}{% endif %}{% if release.format %}{{ release.format }}{% endif %}

+
+
+ {% endfor %} +
+ {% else %} +

No releases yet.

+ {% endif %} +
+
diff --git a/blocks/discography.sample.json b/blocks/discography.sample.json new file mode 100644 index 0000000..dc49085 --- /dev/null +++ b/blocks/discography.sample.json @@ -0,0 +1,9 @@ +{ + "heading": "Discography", + "releases": [ + { "title": "Chrome Hearts", "year": "2001", "format": "LP", "cover": "", "link": "#" }, + { "title": "Dial-Up Dreams", "year": "2000", "format": "EP", "cover": "", "link": "#" }, + { "title": "Frosted", "year": "1999", "format": "Single", "cover": "", "link": "#" }, + { "title": "Skyline Demos", "year": "1998", "format": "Cassette", "cover": "", "link": "#" } + ] +} diff --git a/blocks/discography.schema.json b/blocks/discography.schema.json new file mode 100644 index 0000000..8b55195 --- /dev/null +++ b/blocks/discography.schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Discography", + "description": "A grid of releases with cover art, year, and a link.", + "type": "object", + "properties": { + "heading": { + "type": "string", + "title": "Heading", + "x-editor": "text", + "default": "Discography" + }, + "releases": { + "type": "array", + "title": "Releases", + "x-editor": "array", + "items": { + "type": "object", + "properties": { + "title": { "type": "string", "title": "Title", "x-editor": "text" }, + "year": { "type": "string", "title": "Year", "x-editor": "text" }, + "format": { "type": "string", "title": "Format", "x-editor": "text" }, + "cover": { "type": "string", "title": "Cover art", "x-editor": "media" }, + "link": { "type": "string", "title": "Link", "x-editor": "text" } + } + }, + "default": [] + } + } +} diff --git a/blocks/footer_chrome.ninjatpl b/blocks/footer_chrome.ninjatpl deleted file mode 100644 index 3bb6d7d..0000000 --- a/blocks/footer_chrome.ninjatpl +++ /dev/null @@ -1,7 +0,0 @@ -
-
- {% if menuName %}{% endif %} - {% if showWebring != "no" and showWebring != false %}{% endif %} - {% if copyright %}{{ copyright }}{% endif %} -
-
diff --git a/blocks/footer_chrome.schema.json b/blocks/footer_chrome.schema.json deleted file mode 100644 index 8af3bfa..0000000 --- a/blocks/footer_chrome.schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Chrome Footer", - "description": "Beveled chrome strip with optional webring and copyright.", - "type": "object", - "properties": { - "menuName": { - "type": "string", - "title": "Menu", - "description": "Optional footer menu to render.", - "x-editor": "menu-select", - "default": "" - }, - "showWebring": { - "type": "string", - "title": "Show Webring", - "description": "Render the 88x31 webring badge row.", - "x-editor": "select", - "enum": ["yes", "no"], - "default": "yes" - }, - "copyright": { - "type": "string", - "title": "Copyright", - "description": "Copyright line.", - "x-editor": "text", - "default": "" - } - } -} diff --git a/blocks/glitter_divider.ninjatpl b/blocks/glitter_divider.ninjatpl deleted file mode 100644 index b1dc853..0000000 --- a/blocks/glitter_divider.ninjatpl +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/blocks/glitter_divider.schema.json b/blocks/glitter_divider.schema.json deleted file mode 100644 index c4d9dc8..0000000 --- a/blocks/glitter_divider.schema.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Glitter Divider", - "description": "Animated sparkle horizontal rule.", - "type": "object", - "properties": { - "variant": { - "type": "string", - "title": "Variant", - "x-editor": "select", - "enum": ["sparkle", "stars", "hearts", "chrome"], - "default": "sparkle" - } - } -} diff --git a/blocks/marquee.ninjatpl b/blocks/marquee.ninjatpl deleted file mode 100644 index 8847274..0000000 --- a/blocks/marquee.ninjatpl +++ /dev/null @@ -1,5 +0,0 @@ -
-
- {% if items %}{% for item in items %}*{{ item }}{% endfor %}{% for item in items %}{% endfor %}{% else %}*now playing*new drop friday*subscribe to the zine{% endif %} -
-
diff --git a/blocks/marquee.schema.json b/blocks/marquee.schema.json deleted file mode 100644 index be838e0..0000000 --- a/blocks/marquee.schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Marquee Ticker", - "description": "Scrolling text strip with chrome edges. Pauses on hover/focus.", - "type": "object", - "properties": { - "items": { - "type": "array", - "title": "Items", - "description": "Lines to scroll across the marquee.", - "x-editor": "array", - "items": { - "type": "string" - }, - "default": [] - }, - "speed": { - "type": "string", - "title": "Speed", - "x-editor": "select", - "enum": ["slow", "medium", "fast"], - "default": "medium" - }, - "direction": { - "type": "string", - "title": "Direction", - "x-editor": "select", - "enum": ["left", "right"], - "default": "left" - } - } -} diff --git a/blocks/merch_card.ninjatpl b/blocks/merch_card.ninjatpl deleted file mode 100644 index 129e6f2..0000000 --- a/blocks/merch_card.ninjatpl +++ /dev/null @@ -1,13 +0,0 @@ -
- {% if sticker %}{% if sticker == "sold-out" %}sold out{% else %}{{ sticker }}{% endif %}{% endif %} -
- {% if image %}{{ title }}{% else %}
no image
{% endif %} -
-
-

{{ title|default:"untitled" }}

-
- {{ price|default:"$--" }} - {% if buyHref %}buy{% endif %} -
-
-
diff --git a/blocks/merch_card.schema.json b/blocks/merch_card.schema.json deleted file mode 100644 index 83844c5..0000000 --- a/blocks/merch_card.schema.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Merch Card", - "description": "Plastic-bevel product card with a price sticker.", - "type": "object", - "properties": { - "title": { - "type": "string", - "title": "Product Title", - "x-editor": "text", - "default": "" - }, - "price": { - "type": "string", - "title": "Price", - "description": "Display string e.g. $24.", - "x-editor": "text", - "default": "" - }, - "image": { - "type": "string", - "title": "Image", - "x-editor": "media", - "default": "" - }, - "buyHref": { - "type": "string", - "title": "Buy Link", - "x-editor": "link", - "default": "" - }, - "sticker": { - "type": "string", - "title": "Sticker", - "description": "Corner sticker badge variant.", - "x-editor": "select", - "enum": ["", "new", "hot", "sale", "sold-out"], - "default": "" - } - } -} diff --git a/blocks/metaball_hero.ninjatpl b/blocks/metaball_hero.ninjatpl deleted file mode 100644 index d75f7f5..0000000 --- a/blocks/metaball_hero.ninjatpl +++ /dev/null @@ -1,32 +0,0 @@ -
- -
-
-

{{ headline|default:"new EP out now" }}

- {% if sub %}

{{ sub }}

{% endif %} - {% if ctaLabel %}{{ ctaLabel }}{% endif %} -
-
-
diff --git a/blocks/metaball_hero.schema.json b/blocks/metaball_hero.schema.json deleted file mode 100644 index d45a588..0000000 --- a/blocks/metaball_hero.schema.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Metaball Hero", - "description": "Hero section with SVG metaballs on a gradient mesh canvas.", - "type": "object", - "properties": { - "headline": { - "type": "string", - "title": "Headline", - "description": "Display headline.", - "x-editor": "text", - "default": "" - }, - "sub": { - "type": "string", - "title": "Sub-headline", - "description": "Supporting line under the headline.", - "x-editor": "text", - "default": "" - }, - "ctaLabel": { - "type": "string", - "title": "CTA Label", - "description": "Call-to-action button text.", - "x-editor": "text", - "default": "" - }, - "ctaHref": { - "type": "string", - "title": "CTA Link", - "description": "Where the CTA button points.", - "x-editor": "link", - "default": "" - }, - "bgPreset": { - "type": "string", - "title": "Background Preset", - "description": "Which mesh anchor palette to use.", - "x-editor": "select", - "enum": ["magenta-teal", "after-hours", "bubblegum"], - "default": "magenta-teal" - } - } -} diff --git a/blocks/nft_gallery.ninjatpl b/blocks/nft_gallery.ninjatpl deleted file mode 100644 index f3077b5..0000000 --- a/blocks/nft_gallery.ninjatpl +++ /dev/null @@ -1,9 +0,0 @@ -
- {% if not items %}

No items yet.

{% else %}{% endif %} -
diff --git a/blocks/nft_gallery.schema.json b/blocks/nft_gallery.schema.json deleted file mode 100644 index e8a1be8..0000000 --- a/blocks/nft_gallery.schema.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NFT Gallery", - "description": "Holographic-foil hover gallery of NFT items (presentational only).", - "type": "object", - "properties": { - "items": { - "type": "array", - "title": "Items", - "x-editor": "collection", - "items": { - "type": "object", - "properties": { - "title": { - "type": "string", - "title": "Title", - "x-editor": "text" - }, - "image": { - "type": "string", - "title": "Image", - "x-editor": "media" - }, - "chain": { - "type": "string", - "title": "Chain", - "x-editor": "select", - "enum": ["", "eth", "sol", "polygon", "base", "tezos"] - }, - "href": { - "type": "string", - "title": "Link", - "x-editor": "link" - } - }, - "required": ["title"] - }, - "default": [] - } - } -} diff --git a/blocks/tour_dates.ninjatpl b/blocks/tour_dates.ninjatpl new file mode 100644 index 0000000..74844b7 --- /dev/null +++ b/blocks/tour_dates.ninjatpl @@ -0,0 +1,23 @@ +{# y2k:tour_dates — live dates with venue, city, and a ticket link. Chrome-bevel rows. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} + {% if dates %} +
    + {% for show in dates %} +
  • + {% if show.date %}{{ show.date }}{% endif %} + + {% if show.venue %}{{ show.venue }}{% endif %} + {% if show.city %}{{ show.city }}{% endif %} + + {% if show.soldOut %}Sold out{% elif show.ticketUrl %}Tickets{% endif %} +
  • + {% endfor %} +
+ {% else %} +

No dates announced yet.

+ {% endif %} +
+
diff --git a/blocks/tour_dates.sample.json b/blocks/tour_dates.sample.json new file mode 100644 index 0000000..a8c1bf5 --- /dev/null +++ b/blocks/tour_dates.sample.json @@ -0,0 +1,9 @@ +{ + "heading": "Tour dates", + "intro": "Doors an hour before. All ages unless noted.", + "dates": [ + { "date": "Fri 12 Sep", "venue": "The Chrome Room", "city": "Melbourne", "ticketUrl": "#", "soldOut": false }, + { "date": "Sat 13 Sep", "venue": "Rollerdrome", "city": "Sydney", "ticketUrl": "#", "soldOut": true }, + { "date": "Fri 19 Sep", "venue": "Basement 88", "city": "Brisbane", "ticketUrl": "#", "soldOut": false } + ] +} diff --git a/blocks/tour_dates.schema.json b/blocks/tour_dates.schema.json new file mode 100644 index 0000000..924b162 --- /dev/null +++ b/blocks/tour_dates.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Tour Dates", + "description": "A list of live dates with venue, city, and a ticket link.", + "type": "object", + "properties": { + "heading": { + "type": "string", + "title": "Heading", + "x-editor": "text", + "default": "Tour dates" + }, + "intro": { + "type": "string", + "title": "Intro", + "x-editor": "text", + "default": "" + }, + "dates": { + "type": "array", + "title": "Dates", + "x-editor": "array", + "items": { + "type": "object", + "properties": { + "date": { "type": "string", "title": "Date", "x-editor": "text" }, + "venue": { "type": "string", "title": "Venue", "x-editor": "text" }, + "city": { "type": "string", "title": "City", "x-editor": "text" }, + "ticketUrl": { "type": "string", "title": "Ticket URL", "x-editor": "text" }, + "soldOut": { "type": "boolean", "title": "Sold out", "x-editor": "boolean", "default": false } + } + }, + "default": [] + } + } +} diff --git a/blocks/waveform_player.ninjatpl b/blocks/waveform_player.ninjatpl index ce2b81e..f57a7e4 100644 --- a/blocks/waveform_player.ninjatpl +++ b/blocks/waveform_player.ninjatpl @@ -1,13 +1,13 @@ {% if audioUrl or trackTitle %}
- {% if coverImage %}{{ trackTitle }}{% else %}{% endif %} + {% if coverImage %}{% img coverImage alt=trackTitle class="w-full h-full object-cover" %}{% else %}{% endif %}
{{ trackTitle|default:"untitled track" }} - {% if artist %}{{ artist }}{% endif %} + {% if artist %}{{ artist }}{% endif %}
- - {% if audioUrl %}{% else %}

No audio source configured.

{% endif %} + + {% if audioUrl %}{% else %}

No audio source set yet.

{% endif %}
{% endif %} diff --git a/fonts.json b/fonts.json index fe51488..b0027fd 100644 --- a/fonts.json +++ b/fonts.json @@ -1 +1,28 @@ -[] +[ + { + "name": "Orbitron", + "family": "Orbitron", + "variants": [ + { "weight": "500", "style": "normal", "file": "fonts/orbitron-latin.woff2" }, + { "weight": "700", "style": "normal", "file": "fonts/orbitron-latin.woff2" }, + { "weight": "900", "style": "normal", "file": "fonts/orbitron-latin.woff2" } + ] + }, + { + "name": "Share Tech Mono", + "family": "Share Tech Mono", + "variants": [ + { "weight": "400", "style": "normal", "file": "fonts/share-tech-mono-latin.woff2" } + ] + }, + { + "name": "Inter", + "family": "Inter", + "variants": [ + { "weight": "400", "style": "normal", "file": "fonts/inter-latin.woff2" }, + { "weight": "500", "style": "normal", "file": "fonts/inter-latin.woff2" }, + { "weight": "600", "style": "normal", "file": "fonts/inter-latin.woff2" }, + { "weight": "700", "style": "normal", "file": "fonts/inter-latin.woff2" } + ] + } +] diff --git a/manifest.yaml b/manifest.yaml index 36b6b6e..95eafb2 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -1,118 +1,362 @@ -# Y2K theme — codeless .bnp manifest (WO-WZ-021 Phase B). +# Y2K theme — codeless .bnp manifest (WO-TF-026, Wave A). # Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm). +# Persona: musician / band. Millennium-web nostalgia — liquid chrome, frosted +# iMac plastic (light) and rave blacklight (dark), marquees, glitter, a webring, +# and a dependency-free canvas metaball hero showpiece (hero/landing only). theme_presets: presets.json bundled_fonts: fonts.json master_pages: master_pages.json +required_icon_packs: ["lucide", "simple-icons"] system_templates: - key: y2k title: Y2K - description: "Liquid-chrome Y2K revival theme for indie musicians, zines, and merch shops." + description: "Millennium-web band theme — liquid-chrome bevels, frosted plastic, marquees, glitter, a webring, and a canvas metaball hero." page_templates: - system: y2k key: default title: Default - description: "Chrome navbar + content + footer." + description: "Chrome header, sparkle backdrop, plastic content column, chrome footer" + slots: [header, main, footer] + - system: y2k + key: full-width + title: Full Width + description: "Edge-to-edge showcase layout with a mesh backdrop, no max-width" slots: [header, main, footer] - system: y2k key: landing title: Landing - description: "Hero metaball + marquee + CTAs." - slots: [hero, marquee, main, cta, footer] + description: "Canvas metaball hero, chrome feature grid, glitter CTA, chrome footer" + slots: [header, main, footer] - system: y2k key: article - title: Article / Zine Page - description: "Narrow column with sidebar tracklist." + title: Article / Liner Notes + description: "Prose column with a chrome sidebar aside — liner-notes layout" slots: [header, main, aside, footer] - system: y2k - key: full-width - title: Full Width - description: "Edge-to-edge gradient mesh canvas." + key: blog-index + title: Blog Index + description: "Zine feed of chrome post cards" + slots: [header, main, footer] + - system: y2k + key: contact + title: Contact + description: "Chrome contact console — form panel plus a plastic contact card" + slots: [header, main, footer] + - system: y2k + key: auth + title: Auth + description: "Centered chrome auth panel for login / register / reset" slots: [header, main, footer] +# All 49 mandatory-tier builtin overrides (OVERRIDE-CONTRACT §1), dashed keys. template_overrides: + # Chrome (4) + - { template: y2k, block: navbar } + - { template: y2k, block: footer } + - { template: y2k, block: utility-bar } + - { template: y2k, block: announcement-bar } + # Marketing (12) + - { template: y2k, block: hero } + - { template: y2k, block: feature-grid } + - { template: y2k, block: rich-section } + - { template: y2k, block: stats } + - { template: y2k, block: testimonial } + - { template: y2k, block: logo-strip } + - { template: y2k, block: pricing } + - { template: y2k, block: team } + - { template: y2k, block: faq } + - { template: y2k, block: timeline } + - { template: y2k, block: cta } + - { template: y2k, block: countdown } + # Primitives (11) - { template: y2k, block: heading } - { template: y2k, block: text } - - { template: y2k, block: button } + - { template: y2k, block: rich-text } - { template: y2k, block: image } + - { template: y2k, block: quote } + - { template: y2k, block: divider } + - { template: y2k, block: button } + - { template: y2k, block: card } + - { template: y2k, block: gallery } + - { template: y2k, block: video-embed } + - { template: y2k, block: audio-embed } + # Commerce / local (6) + - { template: y2k, block: menu-list } + - { template: y2k, block: event-list } + - { template: y2k, block: contact-form } + - { template: y2k, block: contact-card } + - { template: y2k, block: hours-location } + - { template: y2k, block: social-links } + # Blog family (12) + - { template: y2k, block: blog-hero } + - { template: y2k, block: featured-posts } + - { template: y2k, block: related-posts } + - { template: y2k, block: popular-posts } + - { template: y2k, block: category-list } + - { template: y2k, block: post-hero } + - { template: y2k, block: post-metadata } + - { template: y2k, block: author-bio } + - { template: y2k, block: author-bio-hero } + - { template: y2k, block: newsletter-signup } + - { template: y2k, block: breadcrumbs } + - { template: y2k, block: sidebar-nav } + # Auth surface (3) + - { template: y2k, block: auth-form } + - { template: y2k, block: password-reset-form } + - { template: y2k, block: auth-status } + # System (1) + - { template: y2k, block: page-suggestions } email_wrappers: - y2k css: input_css_append: | - /* === y2k theme — chrome/bevel/mesh tokens === */ + /* ============================================================ + Y2K — millennium-web band theme (WO-TF-026). + Liquid chrome, frosted-plastic bevels, gradient mesh, marquee, + glitter/sparkle, webring badge, and a canvas metaball hero. + Light = frosted iMac plastic. Dark = rave blacklight. + Every colour resolves through the host shadcn HSL tokens via + hsl(var(--token)); the extra chrome/mesh/bevel custom properties + below are HSL triples consumed the same way. No literal hex/rgb. + ============================================================ */ + + /* --- Chrome / mesh / bevel channel tokens ----------------- */ :root { - --chrome-1: 280 30% 95%; - --chrome-2: 200 40% 75%; - --chrome-3: 320 60% 60%; - --chrome-4: 280 40% 25%; - --mesh-a: 320 95% 58%; - --mesh-b: 185 90% 60%; - --mesh-c: 60 95% 70%; + --chrome-1: 220 40% 96%; + --chrome-2: 205 45% 82%; + --chrome-3: 300 45% 78%; + --chrome-4: 240 35% 55%; + --mesh-a: 320 95% 62%; + --mesh-b: 190 90% 60%; + --mesh-c: 55 95% 68%; --bevel-light: 0 0% 100%; - --bevel-dark: 280 60% 12%; + --bevel-dark: 250 45% 22%; } .dark { - --chrome-1: 280 30% 30%; - --chrome-2: 200 40% 45%; - --chrome-3: 320 60% 50%; - --chrome-4: 280 40% 10%; - --mesh-a: 320 100% 65%; - --mesh-b: 185 95% 55%; - --mesh-c: 60 100% 65%; - --bevel-light: 0 0% 100%; - --bevel-dark: 280 80% 4%; + --chrome-1: 280 35% 24%; + --chrome-2: 250 40% 18%; + --chrome-3: 315 55% 30%; + --chrome-4: 265 45% 10%; + --mesh-a: 320 100% 66%; + --mesh-b: 150 95% 58%; + --mesh-c: 275 95% 66%; + --bevel-light: 300 60% 78%; + --bevel-dark: 270 80% 4%; } - - /* === keyframes === */ - @keyframes marquee-x { + + /* --- Keyframes -------------------------------------------- */ + @keyframes y2k-marquee-x { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-50%, 0, 0); } } - @keyframes sparkle { - 0%, 100% { opacity: 0; transform: scale(0.5) rotate(0deg); } + @keyframes y2k-sparkle { + 0%, 100% { opacity: 0; transform: scale(0.4) rotate(0deg); } 50% { opacity: 1; transform: scale(1) rotate(180deg); } } - @keyframes metaball-morph { - 0%, 100% { d: path("M 50 100 a 50 50 0 1 1 100 0 a 50 50 0 1 1 -100 0"); } - 50% { d: path("M 40 95 a 60 55 0 1 1 120 5 a 55 60 0 1 1 -120 -5"); } + @keyframes y2k-shimmer-sweep { + 0% { background-position: -150% 0; } + 100% { background-position: 250% 0; } } - - /* === chrome surface utilities === */ + @keyframes y2k-blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0; } + } + @keyframes y2k-pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.45; transform: scale(0.82); } + } + + /* --- Typography ------------------------------------------- */ + /* Families flow through the admin-bound CSS variables; the fallback + leads with the bundled OFL family so the intended look survives + before the admin assigns a slot. @font-face for the bundled + families is auto-emitted from fonts.json (source=template rows). */ + .y2k-body { + font-family: var(--font-body, "Inter", system-ui, -apple-system, "Segoe UI", sans-serif); + } + .y2k-mono, + .y2k-mono code, + pre.y2k-mono, + code.y2k-mono { + font-family: var(--font-mono, "Share Tech Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, monospace); + } + .y2k-display { + font-family: var(--font-heading, "Orbitron", "Michroma", system-ui, sans-serif); + letter-spacing: 0.02em; + } + /* Beveled chrome headline — bright top rim, dark under-shadow, coloured halo. */ + .y2k-heading, + .glitch { + font-family: var(--font-heading, "Orbitron", "Michroma", system-ui, sans-serif); + letter-spacing: 0.03em; + text-shadow: + 0 1px 0 hsl(var(--bevel-light) / 0.7), + 0 2px 0 hsl(var(--bevel-dark) / 0.35), + 0 6px 22px hsl(var(--primary) / 0.4); + } + /* Chrome shimmer sweep across big headlines (motion, reduced-motion-safe). */ + .glitch { + position: relative; + background-image: linear-gradient( + 100deg, + transparent 20%, + hsl(var(--bevel-light) / 0.65) 45%, + hsl(var(--accent) / 0.55) 50%, + transparent 60%); + background-size: 220% 100%; + background-repeat: no-repeat; + -webkit-background-clip: text; + background-clip: text; + animation: y2k-shimmer-sweep 5.5s ease-in-out infinite; + } + .y2k-prose, + .y2k-prose p, + .y2k-prose li { + font-family: var(--font-body, "Inter", system-ui, sans-serif); + line-height: 1.75; + } + .y2k-prose code { + color: hsl(var(--primary)); + background-color: hsl(var(--muted)); + padding: 0.125rem 0.375rem; + border-radius: 0.25rem; + font-family: var(--font-mono, "Share Tech Mono", ui-monospace, monospace); + font-size: 0.875em; + } + /* Eyebrow / kicker: mono, uppercase, wide-tracked chrome readout. */ + .y2k-eyebrow { + font-family: var(--font-mono, "Share Tech Mono", ui-monospace, monospace); + text-transform: uppercase; + letter-spacing: 0.22em; + font-size: 0.75rem; + color: hsl(var(--primary)); + } + + /* --- Chrome surfaces / backdrops -------------------------- */ .y2k-chrome-bg { - background-image: - linear-gradient(180deg, - hsl(var(--chrome-1)) 0%, - hsl(var(--chrome-2)) 35%, - hsl(var(--chrome-3)) 70%, - hsl(var(--chrome-4)) 100%); + background-image: linear-gradient(180deg, + hsl(var(--chrome-1)) 0%, + hsl(var(--chrome-2)) 35%, + hsl(var(--chrome-3)) 70%, + hsl(var(--chrome-4)) 100%); } .y2k-mesh-bg { background-image: - radial-gradient(at 20% 20%, hsl(var(--mesh-a) / 0.85) 0%, transparent 55%), - radial-gradient(at 80% 30%, hsl(var(--mesh-b) / 0.80) 0%, transparent 55%), - radial-gradient(at 50% 80%, hsl(var(--mesh-c) / 0.70) 0%, transparent 55%), + radial-gradient(at 18% 20%, hsl(var(--mesh-a) / 0.8) 0%, transparent 55%), + radial-gradient(at 82% 28%, hsl(var(--mesh-b) / 0.75) 0%, transparent 55%), + radial-gradient(at 50% 82%, hsl(var(--mesh-c) / 0.65) 0%, transparent 55%), linear-gradient(135deg, hsl(var(--background)) 0%, hsl(var(--card)) 100%); } - .y2k-bevel { + /* Sticky header chrome bar. */ + .y2k-chrome { + background-image: linear-gradient(180deg, + hsl(var(--chrome-1) / 0.92) 0%, + hsl(var(--chrome-2) / 0.88) 100%); + backdrop-filter: saturate(1.3) blur(6px); + box-shadow: inset 0 1px 0 hsl(var(--bevel-light) / 0.7); + } + + /* --- Bevel / frame / glow --------------------------------- */ + .y2k-bevel, + .hud-frame { + position: relative; border: 2px solid hsl(var(--border)); box-shadow: - inset 0 1px 0 hsl(var(--bevel-light) / 0.85), - inset 0 -2px 0 hsl(var(--bevel-dark) / 0.35), - 0 2px 6px hsl(var(--bevel-dark) / 0.30); + inset 0 1px 0 hsl(var(--bevel-light) / 0.8), + inset 0 -2px 0 hsl(var(--bevel-dark) / 0.3), + 0 3px 10px hsl(var(--bevel-dark) / 0.28); } - .y2k-bevel:active { + .y2k-image-frame { + border-radius: 0.75rem; + border: 2px solid hsl(var(--border)); box-shadow: - inset 0 2px 4px hsl(var(--bevel-dark) / 0.45), - inset 0 -1px 0 hsl(var(--bevel-light) / 0.40); + inset 0 1px 0 hsl(var(--bevel-light) / 0.5), + 0 4px 16px hsl(var(--bevel-dark) / 0.35); } - .y2k-glow { - box-shadow: 0 0 24px hsl(var(--primary) / 0.45); + .y2k-glow, + .neon-edge-magenta { + box-shadow: 0 0 0 1px hsl(var(--primary) / 0.4), 0 0 22px hsl(var(--primary) / 0.28); + transition: box-shadow 180ms ease, transform 180ms ease; } - - /* === marquee === */ + .y2k-glow:hover, .y2k-glow:focus-within, + .neon-edge-magenta:hover, .neon-edge-magenta:focus-within { + box-shadow: 0 0 0 1px hsl(var(--primary) / 0.85), 0 0 32px hsl(var(--primary) / 0.48); + transform: translateY(-2px); + } + .neon-edge-cyan { + box-shadow: 0 0 0 1px hsl(var(--accent) / 0.4), 0 0 22px hsl(var(--accent) / 0.28); + transition: box-shadow 180ms ease, transform 180ms ease; + } + .neon-edge-cyan:hover, .neon-edge-cyan:focus-within { + box-shadow: 0 0 0 1px hsl(var(--accent) / 0.85), 0 0 32px hsl(var(--accent) / 0.48); + transform: translateY(-2px); + } + .neon-edge-lime { + box-shadow: 0 0 0 1px hsl(var(--ring) / 0.4), 0 0 22px hsl(var(--ring) / 0.28); + transition: box-shadow 180ms ease, transform 180ms ease; + } + .neon-edge-lime:hover, .neon-edge-lime:focus-within { + box-shadow: 0 0 0 1px hsl(var(--ring) / 0.85), 0 0 32px hsl(var(--ring) / 0.48); + transform: translateY(-2px); + } + /* clip-cut renders as soft rounded plastic corners in Y2K. */ + .clip-cut { border-radius: 0.75rem; } + + /* --- Buttons ---------------------------------------------- */ + .y2k-button, + .y2k-btn, + .rgb-split { + transition: transform 90ms ease, box-shadow 90ms ease, filter 90ms ease; + } + .y2k-button { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.65rem 1.25rem; + font-weight: 600; + border: 2px solid hsl(var(--border)); + border-radius: 0.75rem; + background-image: linear-gradient(180deg, + hsl(var(--primary) / 0.96) 0%, + hsl(var(--primary)) 50%, + hsl(var(--primary) / 0.82) 100%); + color: hsl(var(--primary-foreground)); + box-shadow: + inset 0 1px 0 hsl(var(--bevel-light) / 0.7), + inset 0 -2px 0 hsl(var(--bevel-dark) / 0.3), + 0 2px 8px hsl(var(--bevel-dark) / 0.25); + } + .y2k-btn { border-radius: 0.75rem; } + .y2k-button:hover, .y2k-btn:hover, .rgb-split:hover, .rgb-split:focus-visible { + transform: translateY(-1px); + filter: brightness(1.05); + } + .y2k-button:active, .y2k-btn:active, .rgb-split:active { + transform: translateY(1px); + box-shadow: + inset 0 2px 5px hsl(var(--bevel-dark) / 0.45), + inset 0 -1px 0 hsl(var(--bevel-light) / 0.3); + } + .y2k-button:focus-visible, .y2k-btn:focus-visible, + .rgb-split:focus-visible, + button:focus-visible, a:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + } + + /* --- Cards ------------------------------------------------ */ + .y2k-card { + border-radius: 0.75rem; + box-shadow: + inset 0 1px 0 hsl(var(--bevel-light) / 0.55), + 0 4px 14px hsl(var(--bevel-dark) / 0.22); + } + + /* --- Marquee ---------------------------------------------- */ .y2k-marquee { overflow: hidden; position: relative; @@ -123,9 +367,10 @@ css: display: inline-flex; gap: 3rem; white-space: nowrap; - animation-name: marquee-x; + animation-name: y2k-marquee-x; animation-timing-function: linear; animation-iteration-count: infinite; + animation-duration: 28s; } .y2k-marquee-track[data-speed="slow"] { animation-duration: 60s; } .y2k-marquee-track[data-speed="medium"] { animation-duration: 30s; } @@ -134,131 +379,117 @@ css: .y2k-marquee:focus-within .y2k-marquee-track { animation-play-state: paused; } - - /* === sparkle decoration === */ + + /* --- Sparkle / glitter atmosphere ------------------------- */ .y2k-sparkle { pointer-events: none; - animation: sparkle 1.6s ease-in-out infinite; + animation: y2k-sparkle 1.6s ease-in-out infinite; } - - /* === metaball morph === */ - .y2k-metaball { - animation: metaball-morph 6s ease-in-out infinite; + /* scanlines (ported name) is repurposed as a faint glitter dot field. */ + .scanlines { + opacity: 0.4; + background-image: + radial-gradient(hsl(var(--primary) / 0.5) 1px, transparent 1.5px), + radial-gradient(hsl(var(--accent) / 0.4) 1px, transparent 1.5px); + background-size: 42px 42px, 68px 68px; + background-position: 0 0, 24px 30px; } - - /* === webring 88x31 badge === */ - .y2k-webring-badge { + + /* --- Status / caret -------------------------------------- */ + .y2k-status-dot { + animation: y2k-pulse 2.2s ease-in-out infinite; + } + .caret-blink { display: inline-block; + animation: y2k-blink 1.05s steps(2, end) infinite; + } + + /* --- Webring 88x31 badge ---------------------------------- */ + .y2k-webring-badge { + display: inline-flex; + align-items: center; + justify-content: center; width: 88px; height: 31px; - line-height: 31px; - text-align: center; font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; border: 1px solid hsl(var(--border)); background-image: linear-gradient(180deg, hsl(var(--chrome-1)) 0%, hsl(var(--chrome-3)) 100%); - color: hsl(var(--primaryForeground)); + color: hsl(var(--primary-foreground)); text-decoration: none; box-shadow: inset 0 1px 0 hsl(var(--bevel-light) / 0.6); } - - /* === holographic foil for NFT gallery === */ - .y2k-foil { - position: relative; - isolation: isolate; + + /* --- Static waveform strip (no canvas — motion tier) ------ */ + .y2k-waveform { + background-image: repeating-linear-gradient( + 90deg, + hsl(var(--primary) / 0.65) 0 2px, + hsl(var(--accent) / 0.4) 2px 4px, + transparent 4px 8px); + -webkit-mask-image: linear-gradient(90deg, transparent, hsl(0 0% 0%) 8%, hsl(0 0% 0%) 92%, transparent); + mask-image: linear-gradient(90deg, transparent, hsl(0 0% 0%) 8%, hsl(0 0% 0%) 92%, transparent); + border-radius: 0.25rem; } - .y2k-foil::after { - content: ""; + + /* --- Empty state / article aside -------------------------- */ + .y2k-empty { + font-family: var(--font-mono, "Share Tech Mono", ui-monospace, monospace); + letter-spacing: 0.14em; + } + .y2k-aside { border-radius: 0.75rem; } + + /* --- Canvas metaball showpiece (hero / landing only) ------ */ + /* The lazy-inits from the hero's inline script; this styles the + container plus the static no-JS chrome-mesh fallback. */ + .y2k-orb-wrap { position: absolute; inset: 0; + overflow: hidden; pointer-events: none; - opacity: 0; - transition: opacity 220ms ease; - background-image: conic-gradient( - from 0deg, - hsl(var(--mesh-a) / 0.45), - hsl(var(--mesh-b) / 0.45), - hsl(var(--mesh-c) / 0.45), - hsl(var(--mesh-a) / 0.45) - ); - mix-blend-mode: color-dodge; - filter: hue-rotate(0deg); } - .y2k-foil:hover::after, - .y2k-foil:focus-within::after { - opacity: 1; - filter: hue-rotate(45deg); + .y2k-orb-canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + opacity: 0.65; + filter: blur(2px) contrast(1.15); } - - /* === plastic button override === */ - .y2k-button { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.65rem 1.25rem; - font-weight: 600; - border: 2px solid hsl(var(--border)); - border-radius: 0.625rem; - background-image: linear-gradient(180deg, - hsl(var(--primary) / 0.95) 0%, - hsl(var(--primary)) 50%, - hsl(var(--primary) / 0.85) 100%); - color: hsl(var(--primaryForeground)); - box-shadow: - inset 0 1px 0 hsl(var(--bevel-light) / 0.7), - inset 0 -2px 0 hsl(var(--bevel-dark) / 0.3), - 0 2px 6px hsl(var(--bevel-dark) / 0.25); - transition: transform 90ms ease, box-shadow 90ms ease; + .y2k-orb-fallback { + position: absolute; + inset: 0; + background-image: + radial-gradient(60% 55% at 30% 35%, hsl(var(--mesh-a) / 0.55), transparent 60%), + radial-gradient(55% 50% at 72% 45%, hsl(var(--mesh-b) / 0.5), transparent 60%), + radial-gradient(50% 45% at 50% 80%, hsl(var(--mesh-c) / 0.45), transparent 60%), + linear-gradient(to bottom, transparent, hsl(var(--background) / 0.7)); } - .y2k-button:hover { transform: translateY(-1px); } - .y2k-button:active { - transform: translateY(1px); - box-shadow: - inset 0 2px 4px hsl(var(--bevel-dark) / 0.45), - inset 0 -1px 0 hsl(var(--bevel-light) / 0.30); - } - .y2k-button:focus-visible { - outline: 2px solid hsl(var(--ring)); - outline-offset: 2px; - } - - /* === image chrome frame === */ - .y2k-image-frame { - border-radius: 0.625rem; - border: 2px solid hsl(var(--border)); - box-shadow: - inset 0 1px 0 hsl(var(--bevel-light) / 0.5), - 0 4px 14px hsl(var(--bevel-dark) / 0.35); - } - - /* === heading chrome stroke === */ - .y2k-heading { - font-family: var(--font-heading, "Stretch Pro", "VT323", "Courier New", monospace); - letter-spacing: 0.04em; - text-shadow: - 0 1px 0 hsl(var(--bevel-light) / 0.65), - 0 2px 0 hsl(var(--bevel-dark) / 0.35), - 0 6px 22px hsl(var(--primary) / 0.45); - } - - /* === text holographic link underline === */ - .y2k-text a { - background-image: linear-gradient(90deg, - hsl(var(--mesh-a)), - hsl(var(--mesh-b)), - hsl(var(--mesh-c))); - background-size: 100% 2px; - background-repeat: no-repeat; - background-position: 0 100%; - text-decoration: none; - } - - /* === reduced motion overrides === */ + + /* --- Reduced motion: kill all motion ---------------------- */ @media (prefers-reduced-motion: reduce) { .y2k-marquee-track, .y2k-sparkle, - .y2k-metaball { + .glitch, + .caret-blink, + .y2k-status-dot, + .y2k-orb-canvas { animation: none !important; + animation-duration: 0.01ms !important; } + .glitch { + background-image: none; + -webkit-background-clip: border-box; + background-clip: border-box; + } + .y2k-orb-canvas { display: none; } + .y2k-button:hover, .y2k-btn:hover, .rgb-split:hover { transform: none; } + } + + /* --- High-contrast: drop the glitter + orbs --------------- */ + @media (prefers-contrast: more) { + .scanlines, + .y2k-orb-canvas { display: none; } } diff --git a/master_pages.json b/master_pages.json index 3a8f761..a01fcf2 100644 --- a/master_pages.json +++ b/master_pages.json @@ -1,24 +1,22 @@ [ { - "key": "y2k:default-master", - "title": "Y2K Default Master", - "page_templates": ["default", "article"], + "key": "y2k:site-master", + "title": "Y2K Site Master", + "page_templates": ["default", "full-width", "landing", "article", "blog-index", "contact"], "blocks": [ - { "block_key": "y2k:chrome_navbar", "title": "Chrome Navbar", "content": { "menuName": "main", "logoText": "y2k.fm" }, "slot": "header", "sort_order": 0 }, - { "block_key": "y2k:marquee", "title": "Top Marquee", "content": { "items": ["new drop friday", "listen on bandcamp", "subscribe to the zine"], "speed": "medium" }, "slot": "header", "sort_order": 1 }, - { "block_key": "slot", "title": "Main Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 }, - { "block_key": "y2k:footer_chrome", "title": "Chrome Footer", "content": { "showWebring": true, "copyright": "(c) y2k.fm" }, "slot": "footer", "sort_order": 0 } + { "block_key": "navbar", "title": "Chrome Navbar", "content": { "menuName": "main", "logoType": "text", "logoText": { "text": "CHROME STATIC" }, "companyName": "Chrome Static", "stickyBehavior": "sticky", "cta": { "text": "Listen", "url": "/#listen" } }, "slot": "header", "sort_order": 0 }, + { "block_key": "slot", "title": "Main Content", "content": { "slotName": "main", "placeholder": "Page content" }, "slot": "main", "sort_order": 0 }, + { "block_key": "footer", "title": "Chrome Footer", "content": { "layout": "columns", "companyName": "Chrome Static", "tagline": "A four-piece from the frosted end of the millennium.", "copyright": "Chrome Static" }, "slot": "footer", "sort_order": 0 } ] }, { - "key": "y2k:landing-master", - "title": "Y2K Landing Master", - "page_templates": ["landing", "full-width"], + "key": "y2k:auth-master", + "title": "Y2K Auth Master", + "page_templates": ["auth"], "blocks": [ - { "block_key": "y2k:metaball_hero", "title": "Metaball Hero", "content": { "headline": "new EP out now", "sub": "liquid chrome dreams", "ctaLabel": "listen" }, "slot": "hero", "sort_order": 0 }, - { "block_key": "y2k:marquee", "title": "Marquee", "content": { "items": ["* new * new * new"], "speed": "fast" }, "slot": "marquee", "sort_order": 0 }, - { "block_key": "slot", "title": "Main Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 }, - { "block_key": "y2k:footer_chrome", "title": "Chrome Footer", "content": { "showWebring": true }, "slot": "footer", "sort_order": 0 } + { "block_key": "navbar", "title": "Chrome Navbar", "content": { "menuName": "main", "logoType": "text", "logoText": { "text": "CHROME STATIC" }, "companyName": "Chrome Static" }, "slot": "header", "sort_order": 0 }, + { "block_key": "slot", "title": "Auth Panel", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 }, + { "block_key": "footer", "title": "Chrome Footer", "content": { "layout": "minimal", "companyName": "Chrome Static", "tagline": "A four-piece from the frosted end of the millennium.", "copyright": "Chrome Static" }, "slot": "footer", "sort_order": 0 } ] } ] diff --git a/plugin.mod b/plugin.mod index 69cb004..37f7a2e 100644 --- a/plugin.mod +++ b/plugin.mod @@ -3,7 +3,8 @@ name = "y2k" display_name = "Y2K" scope = "@themes" version = "0.2.0" -description = "Liquid-chrome Y2K revival theme for indie musicians, zines, and merch shops. Gradient mesh backgrounds, plastic-bevel buttons, marquee text, waveform blocks." +description = "Millennium-web band theme — liquid-chrome bevels, frosted plastic, gradient mesh, marquees, glitter, a webring, and a canvas metaball hero. Built for musicians and bands." kind = "theme" categories = ["templates"] -tags = ["retro", "chrome", "vaporwave", "pastel", "music", "creator", "nostalgia", "web3"] +tags = ["retro", "chrome", "vaporwave", "music", "band", "creator", "nostalgia", "dark"] +required_icon_packs = ["lucide", "simple-icons"] diff --git a/presets.json b/presets.json index fce2c32..bd370e7 100644 --- a/presets.json +++ b/presets.json @@ -1,109 +1,251 @@ [ { - "id": "chrome-dream", - "name": "Liquid Chrome Dream", - "description": "Magenta-to-teal mesh on tinted glass cards. Works in both light and dark modes.", + "id": "chrome-candy", + "name": "Chrome Candy", + "description": "Bondi-blue frosted plastic in light, UV magenta rave in dark — the Y2K default", "theme": { "mode": "both", "lightColors": { - "background": "300 40% 97%", - "foreground": "280 60% 12%", - "card": "300 30% 99%", - "cardForeground": "280 60% 12%", - "popover": "300 30% 99%", - "popoverForeground": "280 60% 12%", - "primary": "320 95% 58%", + "background": "205 55% 96%", + "foreground": "230 40% 14%", + "card": "205 45% 99%", + "cardForeground": "230 40% 14%", + "popover": "205 45% 99%", + "popoverForeground": "230 40% 14%", + "primary": "320 90% 55%", "primaryForeground": "0 0% 100%", - "secondary": "185 90% 60%", - "secondaryForeground": "200 80% 10%", - "muted": "300 25% 94%", - "mutedForeground": "280 25% 40%", - "accent": "60 95% 70%", - "accentForeground": "280 60% 12%", - "destructive": "0 90% 60%", - "destructiveForeground": "0 0% 100%", - "border": "300 40% 88%", - "input": "300 30% 92%", - "ring": "320 95% 58%" - }, - "darkColors": { - "background": "280 35% 6%", - "foreground": "300 30% 96%", - "card": "280 40% 10%", - "cardForeground": "300 30% 96%", - "popover": "280 40% 10%", - "popoverForeground": "300 30% 96%", - "primary": "320 100% 65%", - "primaryForeground": "280 40% 6%", - "secondary": "185 95% 55%", - "secondaryForeground": "200 80% 8%", - "muted": "280 30% 14%", - "mutedForeground": "300 20% 65%", - "accent": "60 100% 65%", - "accentForeground": "280 60% 8%", - "destructive": "0 95% 60%", - "destructiveForeground": "0 0% 100%", - "border": "300 40% 22%", - "input": "280 30% 16%", - "ring": "320 100% 65%" - } - } - }, - { - "id": "cd-rom-after-hours", - "name": "CD-ROM After Hours", - "description": "After-hours CD-ROM glow — near-black with neon pink and cyan edge leaks.", - "theme": { - "mode": "dark", - "darkColors": { - "background": "260 50% 5%", - "foreground": "180 100% 88%", - "card": "260 50% 9%", - "cardForeground": "180 100% 88%", - "popover": "260 50% 9%", - "popoverForeground": "180 100% 88%", - "primary": "285 100% 62%", - "primaryForeground": "0 0% 100%", - "secondary": "180 100% 50%", - "secondaryForeground": "260 50% 5%", - "muted": "260 30% 14%", - "mutedForeground": "260 20% 60%", - "accent": "45 100% 60%", - "accentForeground": "260 50% 5%", - "destructive": "0 90% 55%", - "destructiveForeground": "0 0% 100%", - "border": "285 60% 25%", - "input": "260 30% 16%", - "ring": "285 100% 62%" - } - } - }, - { - "id": "bubblegum-trapper", - "name": "Bubblegum Trapper", - "description": "Lisa Frank Trapper-Keeper energy — pastel candy and sour apple accents.", - "theme": { - "mode": "light", - "lightColors": { - "background": "45 100% 97%", - "foreground": "300 50% 15%", - "card": "0 0% 100%", - "cardForeground": "300 50% 15%", - "popover": "0 0% 100%", - "popoverForeground": "300 50% 15%", - "primary": "330 95% 60%", - "primaryForeground": "0 0% 100%", - "secondary": "200 90% 70%", - "secondaryForeground": "200 80% 10%", - "muted": "45 60% 92%", - "mutedForeground": "300 25% 45%", - "accent": "90 75% 60%", - "accentForeground": "90 80% 10%", + "secondary": "200 45% 90%", + "secondaryForeground": "230 40% 14%", + "muted": "205 35% 92%", + "mutedForeground": "225 20% 40%", + "accent": "190 85% 45%", + "accentForeground": "230 40% 12%", "destructive": "0 85% 55%", "destructiveForeground": "0 0% 100%", - "border": "330 50% 85%", - "input": "330 40% 90%", - "ring": "330 95% 60%" + "border": "205 35% 84%", + "input": "205 35% 84%", + "ring": "270 80% 58%" + }, + "darkColors": { + "background": "260 45% 6%", + "foreground": "300 25% 95%", + "card": "265 40% 10%", + "cardForeground": "300 25% 95%", + "popover": "265 40% 10%", + "popoverForeground": "300 25% 95%", + "primary": "320 100% 62%", + "primaryForeground": "260 45% 6%", + "secondary": "265 35% 16%", + "secondaryForeground": "300 25% 95%", + "muted": "265 30% 14%", + "mutedForeground": "285 20% 68%", + "accent": "150 95% 58%", + "accentForeground": "260 45% 6%", + "destructive": "0 95% 64%", + "destructiveForeground": "260 45% 6%", + "border": "270 40% 22%", + "input": "270 40% 20%", + "ring": "275 100% 68%" + } + } + }, + { + "id": "bubblegum", + "name": "Bubblegum", + "description": "Cotton-candy pink plastic in light, hot-pink blacklight in dark", + "theme": { + "mode": "both", + "lightColors": { + "background": "330 60% 97%", + "foreground": "320 35% 16%", + "card": "330 50% 99%", + "cardForeground": "320 35% 16%", + "popover": "330 50% 99%", + "popoverForeground": "320 35% 16%", + "primary": "330 90% 58%", + "primaryForeground": "0 0% 100%", + "secondary": "325 45% 92%", + "secondaryForeground": "320 35% 16%", + "muted": "330 35% 93%", + "mutedForeground": "320 20% 42%", + "accent": "270 80% 60%", + "accentForeground": "0 0% 100%", + "destructive": "0 85% 55%", + "destructiveForeground": "0 0% 100%", + "border": "330 35% 86%", + "input": "330 35% 86%", + "ring": "330 90% 58%" + }, + "darkColors": { + "background": "315 45% 6%", + "foreground": "330 30% 95%", + "card": "315 42% 10%", + "cardForeground": "330 30% 95%", + "popover": "315 42% 10%", + "popoverForeground": "330 30% 95%", + "primary": "330 100% 66%", + "primaryForeground": "315 45% 6%", + "secondary": "315 35% 16%", + "secondaryForeground": "330 30% 95%", + "muted": "315 30% 14%", + "mutedForeground": "325 20% 68%", + "accent": "275 100% 72%", + "accentForeground": "315 45% 6%", + "destructive": "0 95% 64%", + "destructiveForeground": "315 45% 6%", + "border": "320 40% 22%", + "input": "320 40% 20%", + "ring": "330 100% 66%" + } + } + }, + { + "id": "lime-fizz", + "name": "Lime Fizz", + "description": "Frosted lime soda in light, radioactive green rave in dark", + "theme": { + "mode": "both", + "lightColors": { + "background": "150 45% 96%", + "foreground": "170 35% 12%", + "card": "150 40% 99%", + "cardForeground": "170 35% 12%", + "popover": "150 40% 99%", + "popoverForeground": "170 35% 12%", + "primary": "150 75% 38%", + "primaryForeground": "0 0% 100%", + "secondary": "150 35% 90%", + "secondaryForeground": "170 35% 12%", + "muted": "150 28% 92%", + "mutedForeground": "170 18% 40%", + "accent": "320 85% 55%", + "accentForeground": "0 0% 100%", + "destructive": "0 85% 55%", + "destructiveForeground": "0 0% 100%", + "border": "150 28% 82%", + "input": "150 28% 82%", + "ring": "150 75% 38%" + }, + "darkColors": { + "background": "165 40% 5%", + "foreground": "140 30% 92%", + "card": "168 38% 8%", + "cardForeground": "140 30% 92%", + "popover": "168 38% 8%", + "popoverForeground": "140 30% 92%", + "primary": "145 100% 55%", + "primaryForeground": "165 40% 5%", + "secondary": "168 30% 14%", + "secondaryForeground": "140 30% 92%", + "muted": "168 26% 12%", + "mutedForeground": "150 18% 66%", + "accent": "320 100% 66%", + "accentForeground": "165 40% 5%", + "destructive": "0 95% 64%", + "destructiveForeground": "165 40% 5%", + "border": "155 35% 20%", + "input": "155 35% 18%", + "ring": "145 100% 55%" + } + } + }, + { + "id": "graphite", + "name": "Graphite", + "description": "Brushed-silver chrome in light, restrained slate blacklight in dark", + "theme": { + "mode": "both", + "lightColors": { + "background": "220 18% 95%", + "foreground": "225 25% 14%", + "card": "220 20% 99%", + "cardForeground": "225 25% 14%", + "popover": "220 20% 99%", + "popoverForeground": "225 25% 14%", + "primary": "230 30% 30%", + "primaryForeground": "0 0% 100%", + "secondary": "220 16% 89%", + "secondaryForeground": "225 25% 14%", + "muted": "220 14% 91%", + "mutedForeground": "225 14% 42%", + "accent": "265 70% 58%", + "accentForeground": "0 0% 100%", + "destructive": "0 85% 55%", + "destructiveForeground": "0 0% 100%", + "border": "220 16% 82%", + "input": "220 16% 82%", + "ring": "265 70% 58%" + }, + "darkColors": { + "background": "230 25% 6%", + "foreground": "220 18% 92%", + "card": "230 24% 9%", + "cardForeground": "220 18% 92%", + "popover": "230 24% 9%", + "popoverForeground": "220 18% 92%", + "primary": "225 30% 78%", + "primaryForeground": "230 25% 6%", + "secondary": "230 22% 15%", + "secondaryForeground": "220 18% 92%", + "muted": "230 20% 13%", + "mutedForeground": "220 14% 66%", + "accent": "270 95% 72%", + "accentForeground": "230 25% 6%", + "destructive": "0 95% 64%", + "destructiveForeground": "230 25% 6%", + "border": "230 25% 20%", + "input": "230 25% 18%", + "ring": "270 95% 72%" + } + } + }, + { + "id": "tangerine", + "name": "Tangerine", + "description": "Translucent tangerine iMac in light, sunset-orange rave in dark", + "theme": { + "mode": "both", + "lightColors": { + "background": "35 70% 96%", + "foreground": "20 40% 15%", + "card": "35 60% 99%", + "cardForeground": "20 40% 15%", + "popover": "35 60% 99%", + "popoverForeground": "20 40% 15%", + "primary": "20 90% 52%", + "primaryForeground": "0 0% 100%", + "secondary": "35 50% 90%", + "secondaryForeground": "20 40% 15%", + "muted": "35 40% 92%", + "mutedForeground": "25 22% 40%", + "accent": "180 75% 40%", + "accentForeground": "0 0% 100%", + "destructive": "0 85% 55%", + "destructiveForeground": "0 0% 100%", + "border": "35 40% 84%", + "input": "35 40% 84%", + "ring": "20 90% 52%" + }, + "darkColors": { + "background": "18 45% 6%", + "foreground": "30 35% 93%", + "card": "18 42% 9%", + "cardForeground": "30 35% 93%", + "popover": "18 42% 9%", + "popoverForeground": "30 35% 93%", + "primary": "22 100% 60%", + "primaryForeground": "18 45% 6%", + "secondary": "18 35% 15%", + "secondaryForeground": "30 35% 93%", + "muted": "18 30% 13%", + "mutedForeground": "25 22% 66%", + "accent": "175 95% 55%", + "accentForeground": "18 45% 6%", + "destructive": "0 95% 64%", + "destructiveForeground": "18 45% 6%", + "border": "20 40% 20%", + "input": "20 40% 18%", + "ring": "22 100% 60%" } } } diff --git a/seed/seed.json b/seed/seed.json new file mode 100644 index 0000000..1dfbfa5 --- /dev/null +++ b/seed/seed.json @@ -0,0 +1,222 @@ +{ + "demo": true, + "settings": { + "merge": { + "companyName": "Chrome Static", + "tagline": "A four-piece from the frosted end of the millennium." + } + }, + "data_tables": [ + { + "key": "contact_submissions", + "name": "Contact Enquiries", + "description": "Seeded contact-form submissions for the Chrome Static demo. A submission becomes a row here and emails the site admins.", + "columns": [ + { "key": "name", "label": "Name", "type": "text", "required": true }, + { "key": "email", "label": "Email", "type": "email", "required": true }, + { "key": "subject", "label": "Subject", "type": "text", "required": false }, + { "key": "message", "label": "Message", "type": "text", "required": true } + ] + } + ], + "pages": [ + { + "slug": "/", + "title": "Chrome Static", + "template_key": "landing", + "blocks": [ + { + "block_key": "hero", + "title": "Hero", + "slot": "main", + "sort_order": 1, + "content": { + "template": "centered", + "minHeight": "screen", + "eyebrow": "New EP out now", + "headline": "Chrome Static", + "subheadline": "Four tracks. Recorded live to tape.", + "description": "We are a four-piece from Melbourne. We make loud, bright pop for the end of the millennium.", + "ctaPrimary": { "text": "Listen", "url": "#listen" }, + "ctaSecondary": { "text": "See the shows", "url": "#shows" } + } + }, + { + "block_key": "y2k:waveform_player", + "title": "Now playing", + "slot": "main", + "sort_order": 2, + "content": { + "trackTitle": "Frosted", + "artist": "Chrome Static", + "audioUrl": "", + "coverImage": "" + } + }, + { + "block_key": "y2k:discography", + "title": "Records", + "slot": "main", + "sort_order": 3, + "content": { + "heading": "Records", + "releases": [ + { "title": "Chrome Hearts", "year": "2001", "format": "LP", "cover": "", "link": "#" }, + { "title": "Dial-Up Dreams", "year": "2000", "format": "EP", "cover": "", "link": "#" }, + { "title": "Frosted", "year": "1999", "format": "Single", "cover": "", "link": "#" }, + { "title": "Skyline Demos", "year": "1998", "format": "Cassette", "cover": "", "link": "#" } + ] + } + }, + { + "block_key": "y2k:tour_dates", + "title": "Shows", + "slot": "main", + "sort_order": 4, + "content": { + "heading": "Shows", + "intro": "Doors an hour before. All ages unless noted.", + "dates": [ + { "date": "Fri 12 Sep", "venue": "The Chrome Room", "city": "Melbourne", "ticketUrl": "#", "soldOut": false }, + { "date": "Sat 13 Sep", "venue": "Rollerdrome", "city": "Sydney", "ticketUrl": "#", "soldOut": true }, + { "date": "Fri 19 Sep", "venue": "Basement 88", "city": "Brisbane", "ticketUrl": "#", "soldOut": false } + ] + } + }, + { + "block_key": "cta", + "title": "CTA", + "slot": "main", + "sort_order": 5, + "content": { + "background": "band", + "heading": "Join the mailing list", + "text": "One email when a record ships or a show goes up. Nothing else.", + "primaryLabel": "Sign up", + "primaryUrl": "/contact" + } + } + ] + }, + { + "slug": "/about", + "title": "The band", + "template_key": "default", + "blocks": [ + { "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "The band", "level": 1 } }, + { "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "

Chrome Static started in a share house with a borrowed drum machine and a broken amp. We kept the sound and fixed the amp.

We record live to tape in one room. What you hear on the record is what we play on the night. Four people, no click track, one take when we can get it.

" } }, + { "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 3, "content": { "style": "pull", "quote": "Loud, bright, and done in one take.", "attribution": "Chrome Static" } }, + { "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 4, "content": { "variant": "line", "weight": "medium" } }, + { + "block_key": "y2k:tracklist", + "title": "Frosted tracklist", + "slot": "main", + "sort_order": 5, + "content": { + "tracks": [ + { "title": "Frosted", "duration": "3:12", "url": "" }, + { "title": "Dial Tone", "duration": "2:48", "url": "" }, + { "title": "Silver Static", "duration": "4:01", "url": "" }, + { "title": "Skyline", "duration": "3:35", "url": "" } + ] + } + } + ] + }, + { + "slug": "/blog", + "title": "Journal", + "template_key": "blog-index", + "blocks": [ + { "block_key": "card", "title": "Post: Tape", "slot": "main", "sort_order": 1, "content": { "layout": "vertical", "title": "Why we still track to tape", "text": "

Tape makes us commit. Here is what that costs and what we get back.

", "link": "/blog/tracking-to-tape", "linkLabel": "Read on" } }, + { "block_key": "card", "title": "Post: Tour", "slot": "main", "sort_order": 2, "content": { "layout": "vertical", "title": "Notes from the September run", "text": "

Three cities in a van. What went right and what broke.

", "link": "/blog/september-run", "linkLabel": "Read on" } }, + { "block_key": "card", "title": "Post: Gear", "slot": "main", "sort_order": 3, "content": { "layout": "vertical", "title": "The one pedal we cannot replace", "text": "

A cheap chorus pedal from 1999. It is the whole sound.

", "link": "/blog/the-chorus-pedal", "linkLabel": "Read on" } } + ] + }, + { + "slug": "/blog/tracking-to-tape", + "title": "Why we still track to tape", + "template_key": "article", + "parent_slug": "/blog", + "blocks": [ + { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Why we still track to tape", "level": 1 } }, + { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "

Tape does not let you undo. You play it, you keep it, or you play it again. That pressure shows up in the take.

It is slower and it costs more. We think the trade is worth it. The record sounds like a room, not a grid.

" } } + ] + }, + { + "slug": "/blog/september-run", + "title": "Notes from the September run", + "template_key": "article", + "parent_slug": "/blog", + "blocks": [ + { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Notes from the September run", "level": 1 } }, + { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "

Three cities, one van, four amps. The van held. One amp did not.

Sydney sold out and Brisbane nearly did. We ate too much servo food and slept in the van outside a Bunnings. We would do it again next week.

" } } + ] + }, + { + "slug": "/blog/the-chorus-pedal", + "title": "The one pedal we cannot replace", + "template_key": "article", + "parent_slug": "/blog", + "blocks": [ + { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The one pedal we cannot replace", "level": 1 } }, + { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "

It is a plastic chorus pedal from 1999. It hisses and the knob is loose. It is also the whole guitar sound.

We have tried to replace it twice. Both times the record sounded wrong, so the old one went back on the board.

" } } + ] + }, + { + "slug": "/contact", + "title": "Contact", + "template_key": "contact", + "blocks": [ + { + "block_key": "contact-form", + "title": "Contact form", + "slot": "main", + "sort_order": 1, + "content": { + "heading": "Get in touch", + "description": "Booking, press, or just to say hello. We read every message.", + "submitLabel": "Send", + "successMessage": "Thanks. We will get back to you soon.", + "fields": [ + { "name": "name", "label": "Your name", "type": "text", "required": true, "width": "half" }, + { "name": "email", "label": "Email", "type": "email", "required": true, "width": "half" }, + { "name": "subject", "label": "Subject", "type": "text", "required": false, "width": "full" }, + { "name": "message", "label": "Message", "type": "textarea", "required": true, "width": "full" } + ], + "formConfig": { "enabled": true, "captchaEnabled": false, "targetTable": "contact_submissions" } + } + }, + { + "block_key": "contact-card", + "title": "Other ways to reach us", + "slot": "main", + "sort_order": 2, + "content": { + "heading": "Other ways in", + "columns": 3, + "channels": [ + { "icon": "lucide:mail", "label": "Email", "value": "hello@chromestatic.band", "link": "mailto:hello@chromestatic.band" }, + { "icon": "simple-icons:bandcamp", "label": "Bandcamp", "value": "chromestatic.bandcamp.com", "link": "#" }, + { "icon": "simple-icons:instagram", "label": "Instagram", "value": "@chromestatic", "link": "#" } + ] + } + } + ] + }, + { + "slug": "/login", + "title": "Sign in", + "template_key": "auth", + "blocks": [ + { "block_key": "auth-form", "title": "Sign in", "slot": "main", "sort_order": 1, "content": { "default_tab": "login", "show_social": false } } + ] + } + ], + "menu_items": [ + { "menu": "main", "label": "Home", "page_slug": "/", "sort_order": 1 }, + { "menu": "main", "label": "The band", "page_slug": "/about", "sort_order": 2 }, + { "menu": "main", "label": "Journal", "page_slug": "/blog", "sort_order": 3 }, + { "menu": "main", "label": "Contact", "page_slug": "/contact", "sort_order": 4 } + ] +} diff --git a/seed/workflows.json b/seed/workflows.json new file mode 100644 index 0000000..c277456 --- /dev/null +++ b/seed/workflows.json @@ -0,0 +1,19 @@ +{ + "workflows": [ + { + "key": "contact_notify_admins", + "name": "Contact enquiry to admins", + "description": "On a contact-form submission, email the site admins.", + "enabled": true, + "trigger": { "type": "row_inserted", "table": "contact_submissions" }, + "steps": [ + { + "type": "email", + "name": "Email admins", + "template": "Form Submission Notification", + "recipients": { "mode": "admins", "scope": "all" } + } + ] + } + ] +} diff --git a/templates/email/y2k.ninjatpl b/templates/email/y2k.ninjatpl index 8f139ca..8a9fb2a 100644 --- a/templates/email/y2k.ninjatpl +++ b/templates/email/y2k.ninjatpl @@ -18,7 +18,7 @@ } - + {% if preview_text %}
{{ preview_text }}
{% endif %} diff --git a/templates/overrides/y2k/announcement-bar.ninjatpl b/templates/overrides/y2k/announcement-bar.ninjatpl new file mode 100644 index 0000000..516142a --- /dev/null +++ b/templates/overrides/y2k/announcement-bar.ninjatpl @@ -0,0 +1,21 @@ +{# announcement_bar (WO-TF-006): dismissable banner; dismissal persists in localStorage keyed by a content hash (variant + slugified message) so it reappears when the message changes; no-JS fallback is a static non-dismissable strip. Y2K override: mono broadcast readout — data-* + script preserved. #} +{% set anncls = "bg-primary/10 text-foreground" %} +{% if variant == "promo" %}{% set anncls = "bg-primary text-primary-foreground" %}{% elif variant == "alert" %}{% set anncls = "bg-destructive text-destructive-foreground" %}{% endif %} +
+
+

{{ message }}{% if linkText and linkUrl %} {{ linkText }}{% endif %}

+{% if dismissable %}{% endif %} +
+
+{% if dismissable %}{% endif %} diff --git a/templates/overrides/y2k/audio-embed.ninjatpl b/templates/overrides/y2k/audio-embed.ninjatpl new file mode 100644 index 0000000..f9bd0aa --- /dev/null +++ b/templates/overrides/y2k/audio-embed.ninjatpl @@ -0,0 +1,16 @@ +{# audio-embed y2k override: neon panel, mono meta. Facade script + data-bn-* attributes + {% img %} preserved byte-for-byte. #} +
{% if artwork %}
{% img artwork alt=title|default:"" class="h-full w-full object-cover" %}
{% endif %}
{% if title %}

{{ title }}

{% endif %}{% if artist %}

{{ artist }}

{% endif %}
{% if download %}::lucide:download:sm:: Download{% endif %}
diff --git a/templates/overrides/y2k/auth-form.ninjatpl b/templates/overrides/y2k/auth-form.ninjatpl new file mode 100644 index 0000000..42e177f --- /dev/null +++ b/templates/overrides/y2k/auth-form.ninjatpl @@ -0,0 +1,77 @@ +{# auth-form y2k override — reproduces the builtin's security-critical wiring: hardcoded HTMX endpoints /api/auth/login + /api/auth/register (target #auth-message), /forgot-password link, OAuth start URLs gated on context.site.*, and the exact Cap widget markup when captchaEnabled. Only the chrome is themed. #} +{% if context.isPublicLoggedIn %} +
+

Session active as {{ context.publicUsername }}

+ My Account +
+{% else %} +{% set loginActive = "border-primary text-primary" %} +{% set registerActive = "border-transparent text-muted-foreground" %} +{% set loginHidden = "" %} +{% set registerHidden = "hidden" %} +{% if default_tab == "register" %}{% set loginActive = "border-transparent text-muted-foreground" %}{% set registerActive = "border-primary text-primary" %}{% set loginHidden = "hidden" %}{% set registerHidden = "" %}{% endif %} +{% set tabbase = "flex-1 py-2 text-center y2k-mono text-sm font-medium uppercase tracking-wider border-b-2 transition-colors" %} +{% macro captcha() %} + + +{% endmacro %} +{% macro social() %}{% if show_social != false and (context.site.google_oauth_client_id or context.site.facebook_app_id) %}
+

or
+ {% if context.site.google_oauth_client_id %}Continue with Google{% endif %} + {% if context.site.facebook_app_id %}Continue with Facebook{% endif %} +
{% endif %}{% endmacro %} +
+
+
+ + +
+
+
+
+
+ {% if captchaEnabled %}{{ captcha() }}{% endif %} + +

Forgot password?

+ + {{ social() }} +
+
+
+
+
+
+ {% if captchaEnabled %}{{ captcha() }}{% endif %} + + + {{ social() }} +
+
+ +{% endif %} diff --git a/templates/overrides/y2k/auth-status.ninjatpl b/templates/overrides/y2k/auth-status.ninjatpl new file mode 100644 index 0000000..e1f2258 --- /dev/null +++ b/templates/overrides/y2k/auth-status.ninjatpl @@ -0,0 +1,36 @@ +{# auth-status y2k override — reproduces the builtin's hardcoded wiring: /login + /login?tab=register when logged out; /account, /account/reviews, and hx-post /api/auth/logout dropdown when logged in; hx-post /api/auth/resend-verification banner when unverified. State from context.*. #} +{% if not context.isPublicLoggedIn %} +
+ Login + Sign Up +
+{% else %} +{% if not context.publicEmailVerified %}
+ Verify your email address. +
{% endif %} +
+ + + +
+{% endif %} diff --git a/templates/overrides/y2k/author-bio-hero.ninjatpl b/templates/overrides/y2k/author-bio-hero.ninjatpl new file mode 100644 index 0000000..7ec8b04 --- /dev/null +++ b/templates/overrides/y2k/author-bio-hero.ninjatpl @@ -0,0 +1,22 @@ +{# author-bio-hero (y2k override) — author-page header from the `authors` provider. #} +{% if author %} +
+
+
+{% if showAvatar and author.avatar_url %}
{% img author.avatar_url alt=author.display_name class="h-full w-full object-cover" %}
{% endif %} +

{{ author.display_name }}

+{% if author.job_title or author.company %}

{{ author.job_title }}{% if author.job_title and author.company %} · {% endif %}{{ author.company }}

{% endif %} +{% if author.bio %}

{{ author.bio }}

{% endif %} +
+{% if showPostCount %}{{ author.post_count|default:0 }} post{% if author.post_count != 1 %}s{% endif %}{% endif %} +{% if author.location %}{{ author.location }}{% endif %} +
+{% if showSocial %}
+{% if author.website_url %}{% endif %} +{% if author.twitter_handle %}{% endif %} +{% if author.linkedin_url %}{% endif %} +{% if author.github_url %}{% endif %} +
{% endif %} +
+
+{% endif %} diff --git a/templates/overrides/y2k/author-bio.ninjatpl b/templates/overrides/y2k/author-bio.ninjatpl new file mode 100644 index 0000000..8a369ab --- /dev/null +++ b/templates/overrides/y2k/author-bio.ninjatpl @@ -0,0 +1,13 @@ +{# author-bio (y2k override) — byline card sourced from the `post` provider's author_* fields. #} +{% if post.author_name %} + +{% endif %} diff --git a/templates/overrides/y2k/blog-hero.ninjatpl b/templates/overrides/y2k/blog-hero.ninjatpl new file mode 100644 index 0000000..dc9bdbd --- /dev/null +++ b/templates/overrides/y2k/blog-hero.ninjatpl @@ -0,0 +1,24 @@ +{# blog-hero (y2k override) — blog-index header + featured posts from the `posts` provider. #} +
+
+
+
+{% if title %}

{{ title }}

{% endif %} +{% if subtitle %}

{{ subtitle }}

{% endif %} +
+{% if posts %} +
+{% for post in posts %} + +{% endfor %} +
+{% endif %} +
+
diff --git a/templates/overrides/y2k/breadcrumbs.ninjatpl b/templates/overrides/y2k/breadcrumbs.ninjatpl new file mode 100644 index 0000000..d054c37 --- /dev/null +++ b/templates/overrides/y2k/breadcrumbs.ninjatpl @@ -0,0 +1,15 @@ +{# breadcrumbs (y2k override) — trail from the `breadcrumbs` provider (page ancestry). #} +{# showHome prepends a Home link; separator is text ("/") for default or a chevron #} +{# for the arrows template. The trailing is_current item renders as plain text. #} +{% set arrows = template == "arrows" %} + diff --git a/templates/overrides/y2k/button.ninjatpl b/templates/overrides/y2k/button.ninjatpl index 61b7004..8c57c2c 100644 --- a/templates/overrides/y2k/button.ninjatpl +++ b/templates/overrides/y2k/button.ninjatpl @@ -1 +1,2 @@ -{{ text|default:"button" }} +{# y2k button — keep {% button %} tag intact; y2k chrome on hugging wrapper #} +{% with align=align|default:"left" %}
{% if newTab %}{% button style|default:"primary" text=label|default:"Learn more" href=link|default:"#" size=size|default:"md" icon=icon|default:"" icon_position=iconPosition|default:"left" target="_blank" %}{% else %}{% button style|default:"primary" text=label|default:"Learn more" href=link|default:"#" size=size|default:"md" icon=icon|default:"" icon_position=iconPosition|default:"left" %}{% endif %}
{% endwith %} diff --git a/templates/overrides/y2k/card.ninjatpl b/templates/overrides/y2k/card.ninjatpl new file mode 100644 index 0000000..028a246 --- /dev/null +++ b/templates/overrides/y2k/card.ninjatpl @@ -0,0 +1,2 @@ +{# y2k card — dashed neon panel; fields layout/link/media/title/text/linkLabel #} +{% with layout=layout|default:"vertical" %}{% endwith %} diff --git a/templates/overrides/y2k/category-list.ninjatpl b/templates/overrides/y2k/category-list.ninjatpl new file mode 100644 index 0000000..521367e --- /dev/null +++ b/templates/overrides/y2k/category-list.ninjatpl @@ -0,0 +1,18 @@ +{# category-list (y2k override) — from the `categories` provider. list or pills. #} +{% set pills = style == "pills" %} +
+{% if heading %}

{{ heading }}

{% endif %} +{% if pills %} +
+{% for cat in categories %} +{{ cat.name }}{% if showCount %}{{ cat.post_count }}{% endif %} +{% endfor %} +
+{% else %} + +{% endif %} +
diff --git a/templates/overrides/y2k/contact-card.ninjatpl b/templates/overrides/y2k/contact-card.ninjatpl new file mode 100644 index 0000000..2e9d36a --- /dev/null +++ b/templates/overrides/y2k/contact-card.ninjatpl @@ -0,0 +1,18 @@ +{# contact-card y2k override: neon channel panels. All field reads + control flow preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if description %}

{{ description }}

{% endif %} +
+ {% for channel in channels %} +
+ {% if channel.icon %}{% endif %} +
+ {% if channel.label %}
{{ channel.label }}
{% endif %} + {% if channel.value %}
{% if channel.link %}{{ channel.value }}{% else %}{{ channel.value }}{% endif %}
{% endif %} +
+
+ {% endfor %} +
+
+
diff --git a/templates/overrides/y2k/contact-form.ninjatpl b/templates/overrides/y2k/contact-form.ninjatpl new file mode 100644 index 0000000..821fb77 --- /dev/null +++ b/templates/overrides/y2k/contact-form.ninjatpl @@ -0,0 +1,40 @@ +{# contact-form y2k override: terminal console chrome. The {% form %} block, honeypot, field loop, form.submitted/errors reads and _block_id/bid submit wiring are preserved byte-for-byte — only presentational classes change. #} +{% with bid=_block_id|default:context.blockId %} +
+
+ {% if form.submitted %} +
+
+

{{ form.message|default:successMessage|default:"Thanks — your message has been sent." }}

+
+ {% else %} + {% if heading %}

{{ heading }}

{% endif %} + {% if description %}

{{ description }}

{% endif %} + {% if form.errors._form %}
{{ form.errors._form }}
{% endif %} + {% with formAction="/api/blocks/"|add:bid|add:"/submit" formTarget="#contact-form-"|add:bid %} + {% form action=formAction hx_target=formTarget hx_swap="outerHTML" class="mt-8 grid grid-cols-1 gap-5 sm:grid-cols-2" %} + {% for field in fields %} +
+ {% if field.label %}{% endif %} + {% if field.type == "textarea" %} + + {% elif field.type == "select" %} + + {% else %} + + {% endif %} +
+ {% endfor %} + +
+ +
+ {% endform %} + {% endwith %} + {% endif %} +
+
+{% endwith %} diff --git a/templates/overrides/y2k/countdown.ninjatpl b/templates/overrides/y2k/countdown.ninjatpl new file mode 100644 index 0000000..bcc4711 --- /dev/null +++ b/templates/overrides/y2k/countdown.ninjatpl @@ -0,0 +1,50 @@ +{# countdown y2k override: neon HUD digit boxes, glitch heading. Timer script + data attributes preserved byte-for-byte. #} +
+ +
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+
+
--{{ labelDays|default:"Days" }}
+
--{{ labelHours|default:"Hours" }}
+
--{{ labelMinutes|default:"Minutes" }}
+
--{{ labelSeconds|default:"Seconds" }}
+
+ +
+ +
+
+ diff --git a/templates/overrides/y2k/cta.ninjatpl b/templates/overrides/y2k/cta.ninjatpl new file mode 100644 index 0000000..325705f --- /dev/null +++ b/templates/overrides/y2k/cta.ninjatpl @@ -0,0 +1,16 @@ +{# cta y2k override: scanline overlay, glitch heading, clip-cut rgb-split CTAs. All field reads preserved. #} +
+ +
+
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if text %}

{{ text }}

{% endif %} +
+
+ {% if primaryUrl and primaryLabel %}{{ primaryLabel }}{% endif %} + {% if secondaryUrl and secondaryLabel %}{{ secondaryLabel }}{% endif %} +
+
+
+
diff --git a/templates/overrides/y2k/divider.ninjatpl b/templates/overrides/y2k/divider.ninjatpl new file mode 100644 index 0000000..23dc2f1 --- /dev/null +++ b/templates/overrides/y2k/divider.ninjatpl @@ -0,0 +1,2 @@ +{# y2k divider — neon gradient rule / primary-tinted variants #} +{% with variant=variant|default:"line" weight=weight|default:"thin" width=width|default:"full" %}{% if variant == "ornament" %}{% elif variant == "spacer-rule" %}{% else %}{% endif %}{% endwith %} diff --git a/templates/overrides/y2k/event-list.ninjatpl b/templates/overrides/y2k/event-list.ninjatpl new file mode 100644 index 0000000..acc0a1a --- /dev/null +++ b/templates/overrides/y2k/event-list.ninjatpl @@ -0,0 +1,41 @@ +{# event-list y2k override: neon cards, mono datetime. All field reads + control flow preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} + {% if layout == "cards" %} +
+ {% for event in events %}{% if not (hidePast and event.past) %} +
+ {% if event.media %}
{% img event.media alt=event.title class="h-full w-full object-cover" %}
{% endif %} +
+
{{ event.start }}{% if event.end %} – {{ event.end }}{% endif %}{% if event.timezone %} {{ event.timezone }}{% endif %}
+

{{ event.title }}

+ {% if event.venue %}

{{ event.venue }}

{% endif %} + {% if event.description %}

{{ event.description }}

{% endif %} + {% if event.link %}{{ event.linkLabel|default:"Details" }}{% endif %} +
+
+ {% endif %}{% endfor %} +
+ {% else %} +
    + {% for event in events %}{% if not (hidePast and event.past) %} +
  • +
    +
    {{ event.start }}
    + {% if event.end %}
    to {{ event.end }}
    {% endif %} + {% if event.timezone %}
    {{ event.timezone }}
    {% endif %} +
    +
    +

    {{ event.title }}

    + {% if event.venue %}

    {{ event.venue }}

    {% endif %} + {% if event.description %}

    {{ event.description }}

    {% endif %} +
    + {% if event.link %}{{ event.linkLabel|default:"Details" }}{% endif %} +
  • + {% endif %}{% endfor %} +
+ {% endif %} +
+
diff --git a/templates/overrides/y2k/faq.ninjatpl b/templates/overrides/y2k/faq.ninjatpl new file mode 100644 index 0000000..f37973b --- /dev/null +++ b/templates/overrides/y2k/faq.ninjatpl @@ -0,0 +1,18 @@ +{# faq y2k override: glitch heading, neon-tinted dividers, display questions. Chevron svg, {% for %}, and answer prose preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+ {% for item in items %} +
+ + {{ item.question }} + + +
{{ item.answer|safe }}
+
+ {% endfor %} +
+
+
diff --git a/templates/overrides/y2k/feature-grid.ninjatpl b/templates/overrides/y2k/feature-grid.ninjatpl new file mode 100644 index 0000000..e54d3e6 --- /dev/null +++ b/templates/overrides/y2k/feature-grid.ninjatpl @@ -0,0 +1,19 @@ +{# feature_grid y2k override: scanline hero overlay, mono eyebrow, glitch heading, neon HUD cards. All field reads + control flow preserved. #} +
+ +
+ {% if eyebrow %}

{{ eyebrow }}

{% endif %} + {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+ {% for item in items %} +
+ {% if item.icon %}
{% endif %} +

{% if item.linkUrl %}{{ item.title }}{% else %}{{ item.title }}{% endif %}

+ {% if item.text %}

{{ item.text }}

{% endif %} + {% if item.linkUrl and item.linkLabel %}{{ item.linkLabel }}{% endif %} +
+ {% endfor %} +
+
+
diff --git a/templates/overrides/y2k/featured-posts.ninjatpl b/templates/overrides/y2k/featured-posts.ninjatpl new file mode 100644 index 0000000..b0b09a7 --- /dev/null +++ b/templates/overrides/y2k/featured-posts.ninjatpl @@ -0,0 +1,23 @@ +{# featured-posts (y2k override) — grid of cards from the `posts` provider #} +{# (params: limit, featured=true). Neon HUD card: image, title, excerpt, meta. #} +
+
+{% if heading %}

{{ heading }}

{% endif %} +
+{% for post in posts %} +
+{% if showFeaturedImage and post.featured_image_url %}{% img post.featured_image_url alt=post.title class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" %}{% endif %} +
+

{{ post.title }}

+{% if showExcerpt and post.excerpt %}

{{ post.excerpt }}

{% endif %} +
+{% if showAuthor and post.author_name %}{{ post.author_name }}{% endif %} +{% if showDate and post.published_at %}{{ post.published_at|date:"M j, Y" }}{% endif %} +{% if post.reading_time %}{{ post.reading_time }} min read{% endif %} +
+
+
+{% endfor %} +
+
+
diff --git a/templates/overrides/y2k/footer.ninjatpl b/templates/overrides/y2k/footer.ninjatpl new file mode 100644 index 0000000..ccf1f15 --- /dev/null +++ b/templates/overrides/y2k/footer.ninjatpl @@ -0,0 +1,39 @@ +{# footer (WO-TF-006): layouts columns|minimal|centered; menu columns, legal bar, and social row from the `footer_menus` provider; newsletter section reuses the {% signup_form %} core (no duplicated form). Y2K override: mono column headers, neon top rule, display wordmark. #} +{% set fl = layout %} +{% if not fl %}{% if template == "centered" %}{% set fl = "centered" %}{% else %}{% set fl = "columns" %}{% endif %}{% endif %} +{% set fbg = backgroundColor|default:"bg-muted/50" %} +{% macro sociallinks(cls) %}{% if social_items %}{% endif %}{% endmacro %} +{% macro newsletter() %}{% if showNewsletter %}

{{ newsletterTitle|default:"Stay in the loop" }}

{% if newsletterDescription %}

{{ newsletterDescription }}

{% endif %}
{% signup_form list=newsletterListSlug|default:"main" source="footer" submit=newsletterButtonText|default:"Subscribe" %}
{% endif %}{% endmacro %} +{% macro legalbar() %}

{% if copyright %}© {{ copyright }}{% else %}© {{ companyName }}{% endif %}

{% if legal_items %}{% endif %}
{% endmacro %} +
+
+{% if fl == "minimal" %} +
+
{% if logo %}{{ companyName }}{% elif companyName %}{{ companyName }}{% endif %}{% if tagline %}{% endif %}
+{{ sociallinks("") }} +
+{{ legalbar() }} +{% elif fl == "centered" %} +
+{% if logo %}{{ companyName }}{% elif companyName %}{{ companyName }}{% endif %} +{% if tagline %}

{{ tagline }}

{% endif %} +{% if columns %}{% endif %} +{{ newsletter() }} +{{ sociallinks("justify-center") }} +
+{{ legalbar() }} +{% else %} +
+
+{% if logo %}{{ companyName }}{% elif companyName %}{{ companyName }}{% endif %} +{% if tagline %}

{{ tagline }}

{% endif %} +{% if address or email or phone %}
{% if address %}
{{ address }}
{% endif %}{% if email %}{% endif %}{% if phone %}{% endif %}
{% endif %} +{{ sociallinks("mt-5") }} +
+{% for col in columns %}

{{ col.header }}

{% endfor %} +{% if showNewsletter %}
{{ newsletter() }}
{% endif %} +
+{{ legalbar() }} +{% endif %} +
+
diff --git a/templates/overrides/y2k/gallery.ninjatpl b/templates/overrides/y2k/gallery.ninjatpl new file mode 100644 index 0000000..058cf2a --- /dev/null +++ b/templates/overrides/y2k/gallery.ninjatpl @@ -0,0 +1,52 @@ +{# gallery y2k override: neon-edged tiles. Lightbox script + data-bn-* attributes + {% img %} preserved byte-for-byte. #} +{% with layout=layout|default:"grid" gap=gap|default:"md" cols=columns|default:3 %}{% if lightbox %}{% endif %}{% endwith %} diff --git a/templates/overrides/y2k/heading.ninjatpl b/templates/overrides/y2k/heading.ninjatpl index 06b1470..27ebb29 100644 --- a/templates/overrides/y2k/heading.ninjatpl +++ b/templates/overrides/y2k/heading.ninjatpl @@ -1 +1,7 @@ -{% if level|integer == 1 %}

{{ text }}

{% elif level|integer == 3 %}

{{ text }}

{% elif level|integer == 4 %}

{{ text }}

{% elif level|integer == 5 %}
{{ text }}
{% elif level|integer == 6 %}
{{ text }}
{% else %}

{{ text }}

{% endif %} +{# y2k heading — y2k-display everywhere; glitch on h1/h2 only #} +{% if level == 1 %}

{{ text }}

+{% elif level == 3 %}

{{ text }}

+{% elif level == 4 %}

{{ text }}

+{% elif level == 5 %}
{{ text }}
+{% elif level == 6 %}
{{ text }}
+{% else %}

{{ text }}

{% endif %} diff --git a/templates/overrides/y2k/hero.ninjatpl b/templates/overrides/y2k/hero.ninjatpl new file mode 100644 index 0000000..4ce0a75 --- /dev/null +++ b/templates/overrides/y2k/hero.ninjatpl @@ -0,0 +1,107 @@ +{# hero y2k override (GO-BIG showpiece): canvas liquid-chrome metaballs behind a beveled chrome headline over a sparkle glitter field. All builtin field reads + macro + branch structure preserved from the frozen hero default. The metaball canvas shows when there is no backgroundImage; it lazy-inits on view, honors prefers-reduced-motion, degrades to a static chrome-mesh gradient with JS off, and is dependency-free (hero/landing only per motion tier). #} +{% set eyebrowText = eyebrow.text|default:eyebrow %} +{% set headlineText = headline.text|default:headline %} +{% set subText = subheadline.text|default:subheadline %} +{% set descText = description.text|default:description %} +{% set pText = ctaPrimary.text %} +{% set pUrl = ctaPrimary.url %} +{% set sText = ctaSecondary.text %} +{% set sUrl = ctaSecondary.url %} +{% set variant = template|default:"centered" %} +{% set hasImage = backgroundImage %} +{% set showOverlay = hasImage and overlayColor != "none" and overlayColor != "" %} +{% macro herocontent(align) %} +{% if eyebrowText %}{{ eyebrowText }} {% endif %} +{% if headlineText %}

{{ headlineText }}

{% endif %} +{% if subText %}

{{ subText }}

{% endif %} +{% if descText %}

{{ descText }}

{% endif %} +{% if pText or sText %}
+{% if pText and pUrl %}{{ pText }}{% endif %} +{% if sText and sUrl %}{{ sText }}{% endif %} +
{% endif %} +{% if trustLogos %}
+

Heard on

+
{% for logo in trustLogos %}{% if logo.url %}{% img logo.image alt=logo.alt class="h-8 w-auto" %}{% else %}{% img logo.image alt=logo.alt class="h-8 w-auto opacity-60" %}{% endif %}{% endfor %}
+
{% endif %} +{% endmacro %} +{% if variant == "split" %} +
+
{% if hasImage %}{% img backgroundImage alt=headlineText class="absolute inset-0 h-full w-full object-cover" layout="hero" %}{% else %}
{% endif %}
+
{{ herocontent("left") }}
+
+{% else %} +{% set align = "center" %} +{% if variant == "left-aligned" %}{% set align = "left" %}{% endif %} +
+{% if hasImage %}
{% img backgroundImage alt=headlineText class="h-full w-full object-cover" layout="hero" %}{% if showOverlay %}
{% endif %}
{% else %}
{% endif %} + +
{{ herocontent(align) }}
+
+{% endif %} + diff --git a/templates/overrides/y2k/hours-location.ninjatpl b/templates/overrides/y2k/hours-location.ninjatpl new file mode 100644 index 0000000..d7da77b --- /dev/null +++ b/templates/overrides/y2k/hours-location.ninjatpl @@ -0,0 +1,31 @@ +{# hours-location y2k override: mono readout table, neon map panel. Map lazy-load button + inline handler preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} +
+
+ {% if hours %} +
+ + {% for row in hours %} + + + + + {% endfor %} + +
{{ row.day }}{% if row.closed %}Closed{% else %}{{ row.hours }}{% endif %}
+ {% endif %} + {% if specialHoursNote %}

{{ specialHoursNote }}

{% endif %} + {% if address %}
Address
{{ address }}
{% endif %} + {% if phone %}{% endif %} + {% if directionsUrl %}Get directions{% endif %} + + {% if mapEmbedUrl %} +
+ +
+ {% endif %} + + + diff --git a/templates/overrides/y2k/image.ninjatpl b/templates/overrides/y2k/image.ninjatpl index eef295d..28a1e5a 100644 --- a/templates/overrides/y2k/image.ninjatpl +++ b/templates/overrides/y2k/image.ninjatpl @@ -1 +1,2 @@ -{% if url %}
{{ alt }}{% if caption %}
{{ caption }}
{% endif %}
{% endif %} +{# y2k image — cyan neon-edge frame, mono caption; all size/fit branches preserved #} +{% with size=size|default:"full" align=align|default:"center" aspectRatio=aspectRatio|default:"auto" objectFit=objectFit|default:"cover" rounded=rounded|default:"lg" shadow=shadow|default:"none" %}
{% if objectFit == "contain" %}{% img src alt=alt class="w-full h-full object-contain" layout=size %}{% elif objectFit == "fill" %}{% img src alt=alt class="w-full h-full object-fill" layout=size %}{% elif objectFit == "none" %}{% img src alt=alt class="w-full h-full object-none" layout=size %}{% else %}{% img src alt=alt class="w-full h-full object-cover" layout=size %}{% endif %}
{% if caption %}
{{ caption }}
{% endif %}
{% endwith %} diff --git a/templates/overrides/y2k/logo-strip.ninjatpl b/templates/overrides/y2k/logo-strip.ninjatpl new file mode 100644 index 0000000..4756bb8 --- /dev/null +++ b/templates/overrides/y2k/logo-strip.ninjatpl @@ -0,0 +1,16 @@ +{# logo_strip y2k override: mono kicker. Marquee classes, {% img %}, and keyframes {% endif %} diff --git a/templates/overrides/y2k/menu-list.ninjatpl b/templates/overrides/y2k/menu-list.ninjatpl new file mode 100644 index 0000000..3758fa8 --- /dev/null +++ b/templates/overrides/y2k/menu-list.ninjatpl @@ -0,0 +1,30 @@ +{# menu-list y2k override: mono price readouts, neon section rules. All field reads + control flow preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+ {% for section in sections %} + + {% endfor %} +
+ {% if footnote %}

{{ footnote }}

{% endif %} +
+
diff --git a/templates/overrides/y2k/navbar.ninjatpl b/templates/overrides/y2k/navbar.ninjatpl new file mode 100644 index 0000000..cc8acf0 --- /dev/null +++ b/templates/overrides/y2k/navbar.ninjatpl @@ -0,0 +1,104 @@ +{# navbar (WO-TF-005): variants standard|centered-logo|split|transparent-over-hero; sticky none|sticky|shrink-on-scroll; dependency-free off-canvas drawer (pure-CSS baseline + progressive-JS focus-trap/Escape/scroll-lock); menu data from the `menus` provider. Y2K override: mono nav links, neon dropdown panels, clip-cut CTA — drawer ids/style/script/data-bn-* preserved byte-for-byte. #} +{% set nv = variant %} +{% if not nv %}{% if template == "centered" %}{% set nv = "centered-logo" %}{% elif template == "transparent" %}{% set nv = "transparent-over-hero" %}{% else %}{% set nv = "standard" %}{% endif %}{% endif %} +{% set sb = stickyBehavior %} +{% if not sb %}{% if sticky %}{% set sb = "sticky" %}{% else %}{% set sb = "none" %}{% endif %}{% endif %} +{% set use_mega = megaMenu or template == "mega" %} +{% set is_transparent = nv == "transparent-over-hero" %} +{% set cta_text = cta.text|default:ctaLabel %} +{% set cta_url = cta.url|default:ctaUrl %} +{% set bg = backgroundColor|default:"bg-background" %} +{% macro navlink(item) %}{{ item.label }}{% endmacro %} +{% macro dropdown(item) %}
+ +{% if use_mega %} +{% else %}{% endif %} +
{% endmacro %} +{% macro brand(size) %}{% if logoType == "text" and logoText.text %}{{ logoText.text }}{% elif logo %}{{ alt|default:companyName }}{% elif companyName %}{{ companyName }}{% endif %}{% endmacro %} +{% macro ctabtn(extra) %}{% if cta_text %}{{ cta_text }}{% endif %}{% endmacro %} + + + diff --git a/templates/overrides/y2k/newsletter-signup.ninjatpl b/templates/overrides/y2k/newsletter-signup.ninjatpl new file mode 100644 index 0000000..52e7aea --- /dev/null +++ b/templates/overrides/y2k/newsletter-signup.ninjatpl @@ -0,0 +1,12 @@ +{# newsletter-signup (y2k override) — the {% signup_form %} tag carries the #} +{# untouchable subscribe wiring (/api/lists/subscribe HTMX post + honeypot); #} +{# this template supplies only the y2k chrome around it. #} +
+
+
+{% if title %}

{{ title }}

{% endif %} +{% if description %}

{{ description }}

{% endif %} +
{% signup_form list=listSlug source=source submit=submitText success_message=successMessage placeholder=placeholder %}
+
+
+
diff --git a/templates/overrides/y2k/page-suggestions.ninjatpl b/templates/overrides/y2k/page-suggestions.ninjatpl new file mode 100644 index 0000000..7e11df3 --- /dev/null +++ b/templates/overrides/y2k/page-suggestions.ninjatpl @@ -0,0 +1,13 @@ +{# page-suggestions y2k override — themed 404. NOTE: the builtin builds its "did you mean" list from a Postgres full-text query (SearchSimilarPages), which a codeless template cannot run — so this override renders the on-theme 404 console (title / message / requested path / home CTA) without the dynamic suggestion list. Recorded as a known deviation in WO-TF-015. Content fields honored: title, emptyMessage. #} +
+ +
+

Error 404

+

{{ title|default:"Signal lost" }}

+

{{ emptyMessage|default:"That route returned nothing. The page moved, shipped, or never existed." }}

+ {% if context.path %}

requested: {{ context.path }}

{% endif %} + +
+
diff --git a/templates/overrides/y2k/password-reset-form.ninjatpl b/templates/overrides/y2k/password-reset-form.ninjatpl new file mode 100644 index 0000000..c0bee42 --- /dev/null +++ b/templates/overrides/y2k/password-reset-form.ninjatpl @@ -0,0 +1,13 @@ +{# password-reset-form y2k override — reproduces the builtin's hardcoded wiring: hx-post /api/auth/request-password-reset (target #reset-message), back-to-login link /login. Only the chrome is themed. #} +
+
+
+

Reset Password

+

Enter your email address and we will send you a link to reset your password.

+
+
+ +
+

Back to login

+
+
diff --git a/templates/overrides/y2k/popular-posts.ninjatpl b/templates/overrides/y2k/popular-posts.ninjatpl new file mode 100644 index 0000000..c4ba5c2 --- /dev/null +++ b/templates/overrides/y2k/popular-posts.ninjatpl @@ -0,0 +1,16 @@ +{# popular-posts (y2k override) — compact ranked list from the `posts` provider. #} +
+{% if heading %}

{{ heading }}

{% endif %} +
    +{% for post in posts %} +
  1. +{% if showRank %}{{ forloop.Counter }}{% endif %} +{% if showThumbnail and post.featured_image_url %}{% img post.featured_image_url alt=post.title class="h-full w-full object-cover" %}{% endif %} +
    +

    {{ post.title }}

    +{% if post.published_at %}

    {{ post.published_at|date:"M j, Y" }}

    {% endif %} +
    +
  2. +{% endfor %} +
+
diff --git a/templates/overrides/y2k/post-hero.ninjatpl b/templates/overrides/y2k/post-hero.ninjatpl new file mode 100644 index 0000000..9ca5f16 --- /dev/null +++ b/templates/overrides/y2k/post-hero.ninjatpl @@ -0,0 +1,23 @@ +{# post-hero (y2k override) — current post from the `post` provider. When the post #} +{# has a featured image it becomes an overlaid banner; otherwise a clean text hero. #} +{% set center = align != "left" %} +{% if post.featured_image_url %} +
+
{% img post.featured_image_url alt=post.featured_image_alt class="h-full w-full object-cover" layout="hero" %}
+
+
+

{{ post.title }}

+{% if showExcerpt and post.excerpt %}

{{ post.excerpt }}

{% endif %} +{% if showMeta %}
{% if post.author_name %}{{ post.author_name }}{% endif %}{% if post.published_at %}{{ post.published_at|date:"F j, Y" }}{% endif %}{% if post.reading_time %}{{ post.reading_time }} min read{% endif %}
{% endif %} +
+
+{% else %} +
+
+
+

{{ post.title }}

+{% if showExcerpt and post.excerpt %}

{{ post.excerpt }}

{% endif %} +{% if showMeta %}
{% if post.author_name %}{{ post.author_name }}{% endif %}{% if post.published_at %}{{ post.published_at|date:"F j, Y" }}{% endif %}{% if post.reading_time %}{{ post.reading_time }} min read{% endif %}
{% endif %} +
+
+{% endif %} diff --git a/templates/overrides/y2k/post-metadata.ninjatpl b/templates/overrides/y2k/post-metadata.ninjatpl new file mode 100644 index 0000000..f3dc5aa --- /dev/null +++ b/templates/overrides/y2k/post-metadata.ninjatpl @@ -0,0 +1,9 @@ +{# post-metadata (y2k override) — author/date/reading-time row from the `post` provider. #} +{% if post %} +
+{% if showAuthor and post.author_name %}{% if showAvatar and post.author_avatar %}{% img post.author_avatar alt=post.author_name class="h-7 w-7 rounded-full border border-primary/40 object-cover" %}{% endif %}{{ post.author_name }}{% endif %} +{% if showDate and post.published_at %}{% endif %} +{% if showReadingTime and post.reading_time %}{{ post.reading_time }} min read{% endif %} +{% if post.categories %}{% for cat in post.categories %}{{ cat.name }}{% endfor %}{% endif %} +
+{% endif %} diff --git a/templates/overrides/y2k/pricing.ninjatpl b/templates/overrides/y2k/pricing.ninjatpl new file mode 100644 index 0000000..bb9af2f --- /dev/null +++ b/templates/overrides/y2k/pricing.ninjatpl @@ -0,0 +1,26 @@ +{# pricing y2k override: scanline overlay, glitch heading, HUD neon tier panels (magenta highlight / cyan standard), clip-cut CTAs. Field reads + control flow preserved. #} +
+ +
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+ {% for tier in tiers %} +
+ {% if tier.badge %}{{ tier.badge }}{% endif %} +

{{ tier.name }}

+

+ {% if currency %}{{ currency }}{% else %}${% endif %}{{ tier.price }} + {% if tier.period %}{{ tier.period }}{% endif %} +

+ {% if tier.description %}

{{ tier.description }}

{% endif %} + {% if tier.features %}
    + {% for feature in tier.features %}
  • {{ feature }}
  • {% endfor %} +
{% endif %} + {% if tier.ctaUrl and tier.ctaLabel %}{{ tier.ctaLabel }}{% endif %} +
+ {% endfor %} +
+ {% if billingNote %}

{{ billingNote }}

{% endif %} +
+
diff --git a/templates/overrides/y2k/quote.ninjatpl b/templates/overrides/y2k/quote.ninjatpl new file mode 100644 index 0000000..6355d8a --- /dev/null +++ b/templates/overrides/y2k/quote.ninjatpl @@ -0,0 +1,2 @@ +{# y2k quote — dashed neon left border; y2k-display for pull; mono figcaption #} +{% with style=style|default:"block" align=align|default:"left" %}
{{ quote|safe }}{% if attribution or role or cite %}
{% if attribution %}{{ attribution }}{% endif %}{% if role %}{{ role }}{% endif %}{% if cite %}Source{% endif %}
{% endif %}
{% endwith %} diff --git a/templates/overrides/y2k/related-posts.ninjatpl b/templates/overrides/y2k/related-posts.ninjatpl new file mode 100644 index 0000000..0892c7c --- /dev/null +++ b/templates/overrides/y2k/related-posts.ninjatpl @@ -0,0 +1,17 @@ +{# related-posts (y2k override) — grid from the `posts` provider. #} +{% if posts %} +
+
+

{{ heading|default:"Related posts" }}

+
+{% for post in posts %} + +{% endfor %} +
+
+
+{% endif %} diff --git a/templates/overrides/y2k/rich-section.ninjatpl b/templates/overrides/y2k/rich-section.ninjatpl new file mode 100644 index 0000000..ccd5687 --- /dev/null +++ b/templates/overrides/y2k/rich-section.ninjatpl @@ -0,0 +1,14 @@ +{# rich_section y2k override: mono eyebrow, glitch heading, HUD-framed media, clip-cut CTA. Field reads + {% img %} preserved. #} +
+
+
+ {% if eyebrow %}

{{ eyebrow }}

{% endif %} + {% if heading %}

{{ heading }}

{% endif %} + {% if body %}
{{ body|safe }}
{% endif %} + {% if ctaUrl and ctaLabel %}{{ ctaLabel }}{% endif %} +
+
+ {% if media %}
{% img media alt=mediaAlt class="w-full h-auto object-cover" %}
{% endif %} +
+
+
diff --git a/templates/overrides/y2k/rich-text.ninjatpl b/templates/overrides/y2k/rich-text.ninjatpl new file mode 100644 index 0000000..b6dbfb2 --- /dev/null +++ b/templates/overrides/y2k/rich-text.ninjatpl @@ -0,0 +1,2 @@ +{# y2k rich-text — body font via y2k-prose #} +{% if html %}
{{ html|safe }}
{% endif %} diff --git a/templates/overrides/y2k/sidebar-nav.ninjatpl b/templates/overrides/y2k/sidebar-nav.ninjatpl new file mode 100644 index 0000000..72c7cee --- /dev/null +++ b/templates/overrides/y2k/sidebar-nav.ninjatpl @@ -0,0 +1,15 @@ +{# sidebar-nav (y2k override) — vertical menu from the `menus` provider. Variants #} +{# default | compact. highlight-current carried as a progressive-enhancement #} +{# script keyed on data-bn-sidebar-link (marks the anchor matching location.pathname). #} +{% set compact = template == "compact" %} + +{% if highlightCurrent %}{% endif %} diff --git a/templates/overrides/y2k/social-links.ninjatpl b/templates/overrides/y2k/social-links.ninjatpl new file mode 100644 index 0000000..c7ae79b --- /dev/null +++ b/templates/overrides/y2k/social-links.ninjatpl @@ -0,0 +1,14 @@ +{# y2k social-links — mono label, sharp neon-bordered chips; icon sprites preserved #} + diff --git a/templates/overrides/y2k/stats.ninjatpl b/templates/overrides/y2k/stats.ninjatpl new file mode 100644 index 0000000..a1d88bf --- /dev/null +++ b/templates/overrides/y2k/stats.ninjatpl @@ -0,0 +1,50 @@ +{# stats y2k override: scanline overlay, glitch heading, HUD stat tiles, mono labels. data-stats + countUp script/attrs preserved byte-for-byte. #} +
+ +
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+ {% for item in items %} +
+
{% if item.prefix %}{{ item.prefix }}{% endif %}{{ item.value }}{% if item.suffix %}{{ item.suffix }}{% endif %}
+ {% if item.label %}
{{ item.label }}
{% endif %} +
+ {% endfor %} +
+
+
+{% if countUp %}{% endif %} diff --git a/templates/overrides/y2k/team.ninjatpl b/templates/overrides/y2k/team.ninjatpl new file mode 100644 index 0000000..13d883a --- /dev/null +++ b/templates/overrides/y2k/team.ninjatpl @@ -0,0 +1,22 @@ +{# team y2k override: glitch heading, dashed-neon HUD member panels (lime), mono roles. {% img %} + social icon svgs + control flow preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
+ {% for member in members %} +
+ {% if member.photo %}{% img member.photo alt=member.name class="h-full w-full object-cover" %}{% endif %} +
+ {% if member.name %}

{{ member.name }}

{% endif %} + {% if member.role %}

{{ member.role }}

{% endif %} + {% if member.bio %}

{{ member.bio }}

{% endif %} + {% if member.socials %}
+ {% for social in member.socials %}{% if social.url %}{% endif %}{% endfor %} +
{% endif %} +
+
+ {% endfor %} +
+
+
diff --git a/templates/overrides/y2k/testimonial.ninjatpl b/templates/overrides/y2k/testimonial.ninjatpl new file mode 100644 index 0000000..cc6635c --- /dev/null +++ b/templates/overrides/y2k/testimonial.ninjatpl @@ -0,0 +1,27 @@ +{# testimonial y2k override: glitch heading, dashed-neon HUD quote cards. Rating svgs, {% img %}, and control flow preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} +
+ {% for q in quotes %} +
+ {% if q.rating %}
+ + + + + +
{% endif %} +
{% if q.quote %}“{{ q.quote }}”{% endif %}
+
+ {% if q.avatar %}{% img q.avatar alt=q.name class="h-full w-full object-cover" %}{% endif %} + + {% if q.name %}{{ q.name }}{% endif %} + {% if q.role %}{{ q.role }}{% endif %} + +
+
+ {% endfor %} +
+
+
diff --git a/templates/overrides/y2k/text.ninjatpl b/templates/overrides/y2k/text.ninjatpl index adf7858..04e7f9b 100644 --- a/templates/overrides/y2k/text.ninjatpl +++ b/templates/overrides/y2k/text.ninjatpl @@ -1 +1,2 @@ -
{{ text|safe }}
+{# y2k text — body font via y2k-prose #} +
{{ text|safe }}
diff --git a/templates/overrides/y2k/timeline.ninjatpl b/templates/overrides/y2k/timeline.ninjatpl new file mode 100644 index 0000000..a78c39d --- /dev/null +++ b/templates/overrides/y2k/timeline.ninjatpl @@ -0,0 +1,22 @@ +{# timeline y2k override: glitch heading, mono step labels, neon markers. All field reads + control flow preserved. #} +
+
+ {% if heading %}

{{ heading }}

{% endif %} + {% if intro %}

{{ intro }}

{% endif %} +
    + {% for step in steps %} +
  1. + + {% if marker == "numbered" %}{{ forloop.counter }}{% elif marker == "dot" %}{% else %}{% endif %} + +
    + {% if step.label %}

    {{ step.label }}

    {% endif %} + {% if step.title %}

    {{ step.title }}

    {% endif %} + {% if step.text %}

    {{ step.text }}

    {% endif %} + {% if step.media %}
    {% img step.media alt=step.title class="w-full h-auto object-cover" %}
    {% endif %} +
    +
  2. + {% endfor %} +
+
+
diff --git a/templates/overrides/y2k/utility-bar.ninjatpl b/templates/overrides/y2k/utility-bar.ninjatpl new file mode 100644 index 0000000..4340e4d --- /dev/null +++ b/templates/overrides/y2k/utility-bar.ninjatpl @@ -0,0 +1,10 @@ +{# utility_bar (WO-TF-006): thin top contact strip; left/right item lists {icon,label,link}; icons render through the sprite pipeline via the ::pack:name:: shorthand. Y2K override: mono terminal readout, neon underline. #} +{% set ubcls = "bg-muted text-muted-foreground border-b border-primary/30" %} +{% if variant == "primary" %}{% set ubcls = "bg-primary text-primary-foreground" %}{% elif variant == "dark" %}{% set ubcls = "bg-foreground text-background" %}{% endif %} +{% macro ubitem(it) %}{% if it.link %}{% if it.icon %}::{{ it.icon }}::{% endif %}{% if it.label %}{{ it.label }}{% endif %}{% else %}{% if it.icon %}::{{ it.icon }}::{% endif %}{% if it.label %}{{ it.label }}{% endif %}{% endif %}{% endmacro %} +
+
+
{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}
+
{% for it in rightItems %}{{ ubitem(it) }}{% endfor %}
+
+
diff --git a/templates/overrides/y2k/video-embed.ninjatpl b/templates/overrides/y2k/video-embed.ninjatpl new file mode 100644 index 0000000..ff815c6 --- /dev/null +++ b/templates/overrides/y2k/video-embed.ninjatpl @@ -0,0 +1,23 @@ +{# video-embed y2k override: neon HUD frame, clip-cut play button. Facade script + data-bn-* attributes + {% img %} preserved byte-for-byte. #} +{% with aspect=aspect|default:"16:9" %}
{% if caption %}
{{ caption }}
{% endif %}
{% endwith %} diff --git a/templates/y2k/article.ninjatpl b/templates/y2k/article.ninjatpl index e6fc052..9dc8fce 100644 --- a/templates/y2k/article.ninjatpl +++ b/templates/y2k/article.ninjatpl @@ -1,22 +1,15 @@ - + {{ head_html|safe }} - + {{ admin_banner_html|safe }} -
- {{ slots.header|safe }} -
-
-
- {% if slots.main %}
{{ slots.main|safe }}
{% else %}

No content blocks assigned to this page.

{% endif %} -
- -
-
- {{ slots.footer|safe }} -
+ +
{{ slots.header|safe }}
+
+
{{ slots.main|safe }}
+ {% if slots.aside %}{% endif %} +
+
{{ slots.footer|safe }}
{{ body_end_html|safe }} diff --git a/templates/y2k/auth.ninjatpl b/templates/y2k/auth.ninjatpl new file mode 100644 index 0000000..5297429 --- /dev/null +++ b/templates/y2k/auth.ninjatpl @@ -0,0 +1,14 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} + +
{{ slots.header|safe }}
+
+
{% if slots.main %}{{ slots.main|safe }}{% else %}

Sign in

{% endif %}
+
+
{{ slots.footer|safe }}
+ {{ body_end_html|safe }} + + diff --git a/templates/y2k/blog-index.ninjatpl b/templates/y2k/blog-index.ninjatpl new file mode 100644 index 0000000..8d999e0 --- /dev/null +++ b/templates/y2k/blog-index.ninjatpl @@ -0,0 +1,12 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} + +
{{ slots.header|safe }}
+
{% if slots.main %}{{ slots.main|safe }}{% else %}

No posts yet

{% endif %}
+
{{ slots.footer|safe }}
+ {{ body_end_html|safe }} + + diff --git a/templates/y2k/contact.ninjatpl b/templates/y2k/contact.ninjatpl new file mode 100644 index 0000000..31efb90 --- /dev/null +++ b/templates/y2k/contact.ninjatpl @@ -0,0 +1,12 @@ + + +{{ head_html|safe }} + + {{ admin_banner_html|safe }} + +
{{ slots.header|safe }}
+
{% if slots.main %}{{ slots.main|safe }}{% else %}

Add a contact form here

{% endif %}
+
{{ slots.footer|safe }}
+ {{ body_end_html|safe }} + + diff --git a/templates/y2k/default.ninjatpl b/templates/y2k/default.ninjatpl index ed6617a..953764d 100644 --- a/templates/y2k/default.ninjatpl +++ b/templates/y2k/default.ninjatpl @@ -1,17 +1,12 @@ - + {{ head_html|safe }} - + {{ admin_banner_html|safe }} -
- {{ slots.header|safe }} -
-
- {% if slots.main %}{{ slots.main|safe }}{% else %}

No content blocks assigned to this page.

{% endif %} -
-
- {{ slots.footer|safe }} -
+ +
{{ slots.header|safe }}
+
{% if slots.main %}{{ slots.main|safe }}{% else %}

Nothing on this page yet

{% endif %}
+
{{ slots.footer|safe }}
{{ body_end_html|safe }} diff --git a/templates/y2k/full-width.ninjatpl b/templates/y2k/full-width.ninjatpl index 3d1222b..c2e1e45 100644 --- a/templates/y2k/full-width.ninjatpl +++ b/templates/y2k/full-width.ninjatpl @@ -1,17 +1,12 @@ - + {{ head_html|safe }} - + {{ admin_banner_html|safe }} -
- {{ slots.header|safe }} -
-
- {% if slots.main %}{{ slots.main|safe }}{% else %}

No content blocks assigned to this page.

{% endif %} -
-
- {{ slots.footer|safe }} -
+ +
{{ slots.header|safe }}
+
{% if slots.main %}{{ slots.main|safe }}{% else %}

Nothing on this page yet

{% endif %}
+
{{ slots.footer|safe }}
{{ body_end_html|safe }} diff --git a/templates/y2k/landing.ninjatpl b/templates/y2k/landing.ninjatpl index d53f13e..cfd7934 100644 --- a/templates/y2k/landing.ninjatpl +++ b/templates/y2k/landing.ninjatpl @@ -1,23 +1,12 @@ - + {{ head_html|safe }} - + {{ admin_banner_html|safe }} -
- {{ slots.hero|safe }} -
-
- {{ slots.marquee|safe }} -
-
- {% if slots.main %}
{{ slots.main|safe }}
{% endif %} -
-
- {{ slots.cta|safe }} -
-
- {{ slots.footer|safe }} -
+ +
{{ slots.header|safe }}
+
{% if slots.main %}{{ slots.main|safe }}{% else %}

Nothing on this page yet

{% endif %}
+ {{ body_end_html|safe }}