Compare commits
No commits in common. "3b3adfdf43e4a94255d5d77e92dabcc3f52031ed" and "a7141e39ae4436b9479fc6ca56d1f6500b8ad0a2" have entirely different histories.
3b3adfdf43
...
a7141e39ae
24
README.md
24
README.md
@ -1,24 +0,0 @@
|
||||
# Art Deco
|
||||
|
||||
A dressed-up theme in champagne gold over jet black, with ivory detailing and geometric fan motifs. Tall engraved headings sit above a slim serif body, so the whole thing carries the mood of a 1920s grand hotel lobby. It reads formal and glamorous, and it stays easy to read.
|
||||
|
||||
## Good for
|
||||
|
||||
We built Art Deco with hospitality and celebration in mind. Treat these as starting points, not limits. If the mood fits your brand, use it:
|
||||
|
||||
- Hotels and fine-dining restaurants
|
||||
- Wedding and event venues
|
||||
- Jewellers and luxury boutiques
|
||||
- Cocktail bars and supper clubs
|
||||
|
||||
## What you get
|
||||
|
||||
- Four color presets, each with a tuned light mode and a tuned dark mode: Champagne Noir, Ivory & Rose Gold, Velvet Onyx, and Emerald & Gilt.
|
||||
- Cinzel headings and Cormorant Garamond body, bundled and ready. Fonts stay admin-controlled, so you can swap them from the typography settings.
|
||||
- Four persona blocks: a reservation strip, a menu, a private-dining section, and a chef's signature.
|
||||
- A demo site that installs when you activate the theme: a home page, an about page, a short journal, and a contact page whose form emails your admins.
|
||||
- Every core block restyled to match, plus a themed login screen and a themed 404 page.
|
||||
|
||||
## Install
|
||||
|
||||
Install from the BlockNinja registry, then pick a preset and assign your fonts in the admin. Activate the demo content if you want a fully dressed starting point.
|
||||
@ -1,36 +1,53 @@
|
||||
# Recommended Fonts — Art Deco
|
||||
|
||||
This theme **bundles** its display and body families as subset woff2 files in
|
||||
`assets/fonts/` (see `fonts.json`). They install as `source=template` rows and
|
||||
are pre-selected for the theme's typography slots — no admin action is required
|
||||
for the intended look. The families below are the fallbacks baked into every
|
||||
`var(--font-heading|body|mono, …)` call, so the theme still reads correctly if
|
||||
an admin reassigns a slot.
|
||||
This theme ships `fonts.json = []` (Wave-1 policy, see `themes/docs/FONTS.md`).
|
||||
The intended typographic identity is achieved by an admin assigning the
|
||||
following Google Fonts to the theme's typography slots after install.
|
||||
|
||||
## Bundled (shipped in this theme)
|
||||
## Picker workflow
|
||||
|
||||
| Slot | Family | Weights | File(s) | License |
|
||||
|------|--------|---------|---------|---------|
|
||||
| Heading | **Cinzel** | 400, 700 | `assets/fonts/cinzel-*.woff2` | SIL OFL 1.1 |
|
||||
| Body | **Cormorant Garamond** | 400, 400 italic, 600, 700 | `assets/fonts/cormorant-garamond-*.woff2` | SIL OFL 1.1 |
|
||||
1. Sign in as an admin and open **Settings → Typography**.
|
||||
2. Switch to the **Google Fonts** tab in the font picker.
|
||||
3. Search for the family, click **Add**, then assign it to the listed slot.
|
||||
|
||||
License record and copyright attribution: `assets/fonts/OFL.txt`. The woff2s are
|
||||
Latin subsets of the upstream OFL families (subsetting is permitted by the OFL).
|
||||
## Display heading — Italiana
|
||||
|
||||
## Mono slot (not bundled — assign if needed)
|
||||
- **Source**: `google:Italiana`
|
||||
- **Slot**: Heading
|
||||
- **Why**: The spec calls for stamped Art Deco titles in tight tracking. Italiana
|
||||
is the closest curated Google Fonts match to the high-contrast 1920s display
|
||||
cuts the brief describes.
|
||||
- **Fallback already in CSS**: `var(--font-heading, "Italiana", "Cinzel", Georgia, serif)`.
|
||||
|
||||
The theme uses `var(--font-mono, "JetBrains Mono", ui-monospace, monospace)` for
|
||||
reservation IDs and tabular figures. To match the intended look, an admin can
|
||||
assign a mono family:
|
||||
### Alternative
|
||||
|
||||
1. Sign in as an admin, open **Settings → Typography**.
|
||||
2. Switch to the **Google Fonts** tab and add **JetBrains Mono**.
|
||||
3. Assign it to the **Mono** slot.
|
||||
- **Source**: `google:Cinzel` (also acceptable per spec §3)
|
||||
Pick this if Italiana feels too thin at small sizes.
|
||||
|
||||
If left unset, the CSS falls back to the system monospace stack.
|
||||
## Body — Cormorant Garamond
|
||||
|
||||
## Alternatives (optional)
|
||||
- **Source**: `google:Cormorant Garamond`
|
||||
- **Slot**: Body
|
||||
- **Why**: Classical italic and book weights for long-form prose, exactly the
|
||||
"Cormorant for long-form prose with classical italics" pairing the spec calls
|
||||
out.
|
||||
- **Fallback already in CSS**: `var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)`.
|
||||
|
||||
- Heading: `google:Italiana` — a thinner, higher-contrast display cut; already
|
||||
the second fallback in the heading `var()` list.
|
||||
- Body: the system serif stack (`Georgia, serif`) is the final fallback.
|
||||
## Mono — JetBrains Mono
|
||||
|
||||
- **Source**: `google:JetBrains Mono`
|
||||
- **Slot**: Mono
|
||||
- **Why**: Spec wants a precise monospace for reservation IDs and room numbers.
|
||||
JetBrains Mono ships across all curated Google Fonts and is the cleanest
|
||||
utilitarian option.
|
||||
- **Fallback already in CSS**: `var(--font-mono, "JetBrains Mono", ui-monospace, monospace)`.
|
||||
|
||||
## Notes for Wave-2
|
||||
|
||||
- If Italiana proves too brittle on retina at large sizes, commission a
|
||||
redistributable Art Deco display face and bundle it via `fonts.json`. The
|
||||
rest of the CSS is already variable-driven and will pick the new family up
|
||||
without further edits.
|
||||
- Body italic for the drop-cap relies on the body family having an italic
|
||||
variant; both Cormorant Garamond and Cormorant ship italics in the curated
|
||||
Google Fonts list — no extra picker action needed.
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
# Recommended Icons — Art Deco
|
||||
|
||||
This theme references icons from a single bundled pack. `plugin.mod` declares
|
||||
it in `required_icon_packs`; until the loader auto-installs declared packs, an
|
||||
admin should confirm it is enabled before activation.
|
||||
|
||||
## Required pack
|
||||
|
||||
- **lucide** — ships bundled with the CMS (v0.460). Enabled by default. No
|
||||
action needed in most installs; if icons render as empty boxes, open
|
||||
`/admin/icons` and confirm **Lucide** is installed and enabled.
|
||||
|
||||
## Icons used by the theme chrome and overrides
|
||||
|
||||
All via the sprite pipeline (`<svg><use href="/icons/lucide.svg#<name>"/></svg>`
|
||||
or the `::lucide:<name>::` shorthand):
|
||||
|
||||
`arrow-right`, `check`, `chevron-down`, `chevron-left`, `chevron-right`, `x`,
|
||||
`play`, `download`, `navigation`, `map-pin`, `diamond`, `star`, `flag`,
|
||||
`globe`.
|
||||
|
||||
Block content that stores an icon (e.g. feature-grid items, social links,
|
||||
contact channels) may reference any installed pack as a `pack:name` string;
|
||||
the schemas default to `lucide` so the theme renders without extra setup.
|
||||
@ -1,23 +0,0 @@
|
||||
Bundled fonts — license record (SIL Open Font License, Version 1.1)
|
||||
====================================================================
|
||||
|
||||
The woff2 files in this directory are subsets (Latin) of the following
|
||||
open-source families, both distributed under the SIL Open Font License 1.1
|
||||
(https://openfontlicense.org). Subsetting and format conversion (TTF to
|
||||
woff2) are expressly permitted by the OFL; the derived subsets remain under
|
||||
the same license.
|
||||
|
||||
Cinzel
|
||||
cinzel-400.woff2, cinzel-700.woff2
|
||||
Copyright (c) Natanael Gama (https://ndiscover.com), with Reserved Font
|
||||
Name "Cinzel".
|
||||
|
||||
Cormorant Garamond
|
||||
cormorant-garamond-400.woff2, cormorant-garamond-400-italic.woff2,
|
||||
cormorant-garamond-600.woff2, cormorant-garamond-700.woff2
|
||||
Copyright (c) Christian Thalmann, Catharsis Fonts
|
||||
(https://catharsisfonts.com), with Reserved Font Name "Cormorant".
|
||||
|
||||
The full SIL Open Font License 1.1 text applies to each family and is
|
||||
available at https://openfontlicense.org. This file records the license and
|
||||
copyright attribution as required for redistribution under the OFL.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -17,16 +17,6 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* deco-hero-compact — image-less hero: comfortable padding, no viewport-height balloon. */
|
||||
.deco-hero-compact { padding-top: 4rem; padding-bottom: 4rem; }
|
||||
@media (min-width: 768px) {
|
||||
.deco-hero-compact { padding-top: 6rem; padding-bottom: 6rem; }
|
||||
}
|
||||
|
||||
/* deco-stats — capacity/minimum figure row: guaranteed column gap so values never collide. */
|
||||
.deco-stats { display: flex; flex-wrap: wrap; gap: 0.75rem 3rem; }
|
||||
.deco-stats-center { justify-content: center; }
|
||||
|
||||
/* deco-frame — stepped ziggurat frame, layered borders + clipped corners. */
|
||||
.deco-frame {
|
||||
position: relative;
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
# Art Deco theme block definitions (codeless .bnp, WO-WZ-021 / WO-TF-011).
|
||||
# Only TRUE persona furniture remains as theme blocks. Everything that
|
||||
# duplicated a builtin (footer, hero/marquee, gallery, divider, pull-quote)
|
||||
# is now a template OVERRIDE of the builtin key (templates/overrides/art-deco/).
|
||||
# Keys are fully qualified (art-deco:<key>) — the codeless loader registers
|
||||
# definitions verbatim; the qualified keys match the data-block attributes,
|
||||
# master_pages.json and seed references.
|
||||
# Art Deco theme block definitions (codeless .bnp, WO-WZ-021).
|
||||
# Keys are fully qualified (art-deco:<key>) 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 attributes and the master_pages.json references.
|
||||
blocks:
|
||||
- key: art-deco:reservation
|
||||
title: Reservation Strip
|
||||
@ -14,19 +12,37 @@ blocks:
|
||||
template: reservation.ninjatpl
|
||||
- key: art-deco:menu
|
||||
title: Tasting Menu
|
||||
description: Symmetric menu card listing courses with tasting note and price.
|
||||
description: Symmetric two-column menu card listing courses with description and price.
|
||||
category: content
|
||||
schema: menu.schema.json
|
||||
template: menu.ninjatpl
|
||||
- key: art-deco:private_dining
|
||||
title: Private Dining
|
||||
description: Private dining room showcase — framed image with room details and an enquiry CTA.
|
||||
- key: art-deco:gallery_fan
|
||||
title: Fan Gallery
|
||||
description: Mirrored gallery framed by sunburst — collapses to single column under 640px.
|
||||
category: content
|
||||
schema: private_dining.schema.json
|
||||
template: private_dining.ninjatpl
|
||||
- key: art-deco:chef_signature
|
||||
title: Chef's Signature
|
||||
description: Centred signature-dish feature with a chef's note between sunburst crests.
|
||||
schema: gallery_fan.schema.json
|
||||
template: gallery_fan.ninjatpl
|
||||
- key: art-deco:divider_fan
|
||||
title: Fan Divider
|
||||
description: Pure-CSS gold geometric divider — sunburst, scallop or ziggurat.
|
||||
category: layout
|
||||
schema: divider_fan.schema.json
|
||||
template: divider_fan.ninjatpl
|
||||
- key: art-deco:footer
|
||||
title: Footer
|
||||
description: Centered Art Deco footer with gold rule, address, reservations email and optional social row.
|
||||
category: layout
|
||||
schema: footer.schema.json
|
||||
template: footer.ninjatpl
|
||||
- key: art-deco:marquee_hero
|
||||
title: Marquee Hero
|
||||
description: Wide hero with stepped ziggurat frame and sunburst overlay.
|
||||
category: content
|
||||
schema: chef_signature.schema.json
|
||||
template: chef_signature.ninjatpl
|
||||
schema: marquee_hero.schema.json
|
||||
template: marquee_hero.ninjatpl
|
||||
- key: art-deco:press_quote
|
||||
title: Press Quote
|
||||
description: Italic Cormorant pull-quote between fan dividers, optional star rating.
|
||||
category: content
|
||||
schema: press_quote.schema.json
|
||||
template: press_quote.ninjatpl
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
{# chef_signature persona block — centred signature-dish feature with sunburst crests. Media via {% img %}. #}
|
||||
<section data-block="art-deco:chef_signature" class="py-16 md:py-20 bg-background text-foreground">
|
||||
<div class="mx-auto max-w-3xl px-4 text-center">
|
||||
{% if eyebrow %}<div class="mb-4 flex items-center justify-center gap-4"><span class="deco-rule w-10"></span><span class="deco-caps text-xs" style="color:hsl(var(--primary));">{{ eyebrow }}</span><span class="deco-rule w-10"></span></div>{% endif %}
|
||||
{% if image %}<div class="deco-step mx-auto mb-8 max-w-md">{% img image alt=dish class="w-full h-auto object-cover" %}</div>{% endif %}
|
||||
<div class="h-6 w-40 mx-auto deco-sunburst" aria-hidden="true"></div>
|
||||
{% if dish %}<h2 class="deco-caps mt-6 text-3xl md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ dish }}</h2>{% endif %}
|
||||
{% if note %}<div class="mt-4 text-xl italic leading-relaxed" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ note|safe }}</div>{% endif %}
|
||||
{% if chef %}<p class="deco-caps mt-6 text-xs" style="color:hsl(var(--primary));">{{ chef }}</p>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
@ -1,39 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Chef's Signature",
|
||||
"description": "Centred signature-dish feature with a chef's note between sunburst crests.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"eyebrow": {
|
||||
"type": "string",
|
||||
"title": "Eyebrow",
|
||||
"x-editor": "text",
|
||||
"default": "Chef's signature"
|
||||
},
|
||||
"dish": {
|
||||
"type": "string",
|
||||
"title": "Dish name",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"note": {
|
||||
"type": "string",
|
||||
"title": "Chef's note",
|
||||
"description": "A short tasting note or story about the dish.",
|
||||
"x-editor": "richtext",
|
||||
"default": ""
|
||||
},
|
||||
"chef": {
|
||||
"type": "string",
|
||||
"title": "Chef name",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "Dish image",
|
||||
"x-editor": "media",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
1
blocks/divider_fan.ninjatpl
Normal file
1
blocks/divider_fan.ninjatpl
Normal file
@ -0,0 +1 @@
|
||||
{% if variant == "scallop" %}<div data-block="art-deco:divider_fan" data-variant="scallop" class="w-full py-6 flex justify-center" role="presentation" aria-hidden="true"><div class="h-10 w-full max-w-xl deco-scallop"></div></div>{% elif variant == "ziggurat" %}<div data-block="art-deco:divider_fan" data-variant="ziggurat" class="w-full py-6 flex justify-center" role="presentation" aria-hidden="true"><div class="h-10 w-full max-w-xl deco-ziggurat"></div></div>{% else %}<div data-block="art-deco:divider_fan" data-variant="sunburst" class="w-full py-6 flex justify-center" role="presentation" aria-hidden="true"><div class="h-10 w-full max-w-xl deco-sunburst"></div></div>{% endif %}
|
||||
16
blocks/divider_fan.schema.json
Normal file
16
blocks/divider_fan.schema.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Fan Divider",
|
||||
"description": "Pure-CSS geometric gold divider — sunburst, scallop or ziggurat.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"variant": {
|
||||
"type": "string",
|
||||
"title": "Variant",
|
||||
"description": "Choose the divider motif.",
|
||||
"x-editor": "select",
|
||||
"default": "sunburst",
|
||||
"enum": ["sunburst", "scallop", "ziggurat"]
|
||||
}
|
||||
}
|
||||
}
|
||||
10
blocks/footer.ninjatpl
Normal file
10
blocks/footer.ninjatpl
Normal file
@ -0,0 +1,10 @@
|
||||
<section data-block="art-deco:footer" class="py-12 deco-grain">
|
||||
<div class="max-w-3xl mx-auto px-4 text-center">
|
||||
<hr class="deco-rule mb-8">
|
||||
{% if address %}<address class="not-italic mb-4" style="color: hsl(var(--muted-foreground));">{% for line in address|lines %}<div>{{ line }}</div>{% endfor %}</address>{% endif %}
|
||||
{% if reservationsEmail %}<p class="mb-4"><a href="mailto:{{ reservationsEmail }}" class="deco-link">{{ reservationsEmail }}</a></p>{% endif %}
|
||||
{% if menuName %}<nav aria-label="Footer" class="deco-caps text-xs mb-4" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));"><span>{{ menuName }}</span></nav>{% endif %}
|
||||
{% if showSocial != "false" %}<div class="flex justify-center gap-4 mb-4" style="color: hsl(var(--primary));"><span class="deco-caps text-xs" aria-hidden="true">Instagram</span><span aria-hidden="true">·</span><span class="deco-caps text-xs" aria-hidden="true">Facebook</span><span aria-hidden="true">·</span><span class="deco-caps text-xs" aria-hidden="true">LinkedIn</span></div>{% endif %}
|
||||
<hr class="deco-rule mt-8">
|
||||
</div>
|
||||
</section>
|
||||
37
blocks/footer.schema.json
Normal file
37
blocks/footer.schema.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Footer",
|
||||
"description": "Centered Art Deco footer with gold rule, address, reservations email and optional social row.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string",
|
||||
"title": "Address",
|
||||
"description": "Multi-line postal address.",
|
||||
"x-editor": "textarea",
|
||||
"default": ""
|
||||
},
|
||||
"reservationsEmail": {
|
||||
"type": "string",
|
||||
"title": "Reservations email",
|
||||
"description": "Public email shown in the footer for reservations enquiries.",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"showSocial": {
|
||||
"type": "string",
|
||||
"title": "Show social row",
|
||||
"description": "Whether to render the social-icon row.",
|
||||
"x-editor": "select",
|
||||
"default": "true",
|
||||
"enum": ["true", "false"]
|
||||
},
|
||||
"menuName": {
|
||||
"type": "string",
|
||||
"title": "Footer menu",
|
||||
"description": "Name of the menu to render in the footer.",
|
||||
"x-editor": "menu-select",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
12
blocks/gallery_fan.ninjatpl
Normal file
12
blocks/gallery_fan.ninjatpl
Normal file
@ -0,0 +1,12 @@
|
||||
<section data-block="art-deco:gallery_fan" class="py-16">
|
||||
<div class="max-w-6xl mx-auto px-4">
|
||||
<div class="relative deco-grain">
|
||||
<div class="absolute inset-x-0 -top-2 h-12 pointer-events-none deco-sunburst" aria-hidden="true"></div>
|
||||
<div class="grid gap-4 pt-12 {% if columns|integer == 2 %}grid-cols-1 sm:grid-cols-2{% elif columns|integer == 4 %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-4{% else %}grid-cols-1 sm:grid-cols-2 lg:grid-cols-3{% endif %}">
|
||||
{% if not images %}<div class="col-span-full text-center text-sm py-12" style="color: hsl(var(--muted-foreground));">Add images to populate the fan gallery.</div>{% endif %}
|
||||
{% for img in images %}<figure class="deco-step">{% if img.src %}<img src="{{ img.src }}" alt="{{ img.caption }}" class="block w-full h-auto object-cover" style="background-color: hsl(var(--muted));">{% else %}<img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20fill%3D%22%23222%22%2F%3E%3C%2Fsvg%3E" alt="" class="block w-full h-auto" style="background-color: hsl(var(--muted));">{% endif %}{% if img.caption %}<figcaption class="mt-2 text-center italic text-sm" style="color: hsl(var(--muted-foreground));">{{ img.caption }}</figcaption>{% endif %}</figure>{% endfor %}
|
||||
</div>
|
||||
<div class="absolute inset-x-0 -bottom-2 h-12 pointer-events-none deco-sunburst rotate-180" aria-hidden="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
38
blocks/gallery_fan.schema.json
Normal file
38
blocks/gallery_fan.schema.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Fan Gallery",
|
||||
"description": "Mirrored gallery framed by sunburst rays; collapses to single column under 640px.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"images": {
|
||||
"type": "array",
|
||||
"title": "Images",
|
||||
"description": "Images to mirror across the fan.",
|
||||
"x-editor": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"src": {
|
||||
"type": "string",
|
||||
"title": "Image",
|
||||
"x-editor": "media"
|
||||
},
|
||||
"caption": {
|
||||
"type": "string",
|
||||
"title": "Caption",
|
||||
"x-editor": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"columns": {
|
||||
"type": "integer",
|
||||
"title": "Columns",
|
||||
"description": "Columns on desktop (2, 3 or 4).",
|
||||
"x-editor": "select",
|
||||
"default": 3,
|
||||
"enum": [2, 3, 4]
|
||||
}
|
||||
}
|
||||
}
|
||||
12
blocks/marquee_hero.ninjatpl
Normal file
12
blocks/marquee_hero.ninjatpl
Normal file
@ -0,0 +1,12 @@
|
||||
<section data-block="art-deco:marquee_hero" class="relative w-full overflow-hidden deco-grain" style="background-color: hsl(var(--foreground)); color: hsl(var(--background));">
|
||||
{% if image %}<div class="absolute inset-0 z-0" aria-hidden="true"><img src="{{ image }}" alt="" class="w-full h-full object-cover" style="opacity: 0.5;"><div class="absolute inset-0" style="background-color: hsl(var(--foreground) / 0.55);"></div></div>{% endif %}
|
||||
<div class="absolute inset-x-0 top-0 h-24 z-10 pointer-events-none deco-sunburst" aria-hidden="true"></div>
|
||||
<div class="relative z-20 max-w-4xl mx-auto px-4 py-32 text-center">
|
||||
<div class="deco-frame inline-block px-12 py-10" style="background-color: hsl(var(--foreground) / 0.6); border-color: hsl(var(--primary));">
|
||||
{% if eyebrow %}<p class="deco-caps mb-4 text-xs" style="color: hsl(var(--primary));">{{ eyebrow }}</p>{% endif %}
|
||||
{% if title %}<h1 class="deco-caps deco-underline mb-6 text-5xl md:text-6xl lg:text-7xl" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--background));">{{ title }}</h1>{% endif %}
|
||||
{% if subtitle %}<div class="text-lg md:text-xl mb-8 max-w-2xl mx-auto" style="color: hsl(var(--background) / 0.9);">{{ subtitle|safe }}</div>{% endif %}
|
||||
{% if ctaLabel and ctaHref %}<a href="{{ ctaHref }}" class="deco-pill" style="background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); border-color: hsl(var(--primary));">{{ ctaLabel }}</a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
47
blocks/marquee_hero.schema.json
Normal file
47
blocks/marquee_hero.schema.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Marquee Hero",
|
||||
"description": "Wide hero with stepped ziggurat frame and sunburst overlay.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"eyebrow": {
|
||||
"type": "string",
|
||||
"title": "Eyebrow",
|
||||
"description": "Small caps line above the title.",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Title",
|
||||
"description": "Display headline in Italiana caps.",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"subtitle": {
|
||||
"type": "string",
|
||||
"title": "Subtitle",
|
||||
"description": "Long-form supporting copy (rich text).",
|
||||
"x-editor": "richtext",
|
||||
"default": ""
|
||||
},
|
||||
"ctaLabel": {
|
||||
"type": "string",
|
||||
"title": "CTA label",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"ctaHref": {
|
||||
"type": "string",
|
||||
"title": "CTA URL",
|
||||
"x-editor": "link",
|
||||
"default": ""
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "Background image",
|
||||
"x-editor": "media",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
9
blocks/press_quote.ninjatpl
Normal file
9
blocks/press_quote.ninjatpl
Normal file
@ -0,0 +1,9 @@
|
||||
<section data-block="art-deco:press_quote" class="py-16">
|
||||
<div class="max-w-3xl mx-auto px-4 text-center">
|
||||
<div class="h-6 mb-6 deco-sunburst" aria-hidden="true"></div>
|
||||
<blockquote class="italic text-2xl md:text-3xl leading-snug" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); font-style: italic; color: hsl(var(--foreground));">{% if quote %}{{ quote|safe }}{% else %}<span style="color: hsl(var(--muted-foreground));">Add a press quote to populate this block.</span>{% endif %}</blockquote>
|
||||
{% if stars|integer > 0 %}<div class="mt-4 flex justify-center gap-1" aria-label="Star rating" data-stars="{{ stars|integer }}">{% if stars|integer >= 1 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 2 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 3 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 4 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}{% if stars|integer >= 5 %}<span data-deco-star="filled" aria-hidden="true" style="color: hsl(var(--primary));">★</span>{% else %}<span data-deco-star="empty" aria-hidden="true" style="color: hsl(var(--muted-foreground));">☆</span>{% endif %}</div>{% endif %}
|
||||
{% if source %}<p class="mt-6 deco-caps text-xs" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--muted-foreground));">{{ source }}</p>{% endif %}
|
||||
<div class="h-6 mt-6 deco-scallop" aria-hidden="true"></div>
|
||||
</div>
|
||||
</section>
|
||||
31
blocks/press_quote.schema.json
Normal file
31
blocks/press_quote.schema.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Press Quote",
|
||||
"description": "Italic Cormorant pull-quote between fan dividers.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"quote": {
|
||||
"type": "string",
|
||||
"title": "Quote",
|
||||
"description": "The press quotation (rich text).",
|
||||
"x-editor": "richtext",
|
||||
"default": ""
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"title": "Source",
|
||||
"description": "Attribution line — e.g. 'The Daily, March 2024'.",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"stars": {
|
||||
"type": "integer",
|
||||
"title": "Stars",
|
||||
"description": "Filled-star count, clamped to 0–5.",
|
||||
"x-editor": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
{# private_dining persona block — framed room image + gilded details panel. Media via {% img %}. With no image, collapses to a single centred column so the empty media half never balloons. #}
|
||||
{% set hasImage = image %}
|
||||
<section data-block="art-deco:private_dining" class="py-16 md:py-20 bg-background text-foreground">
|
||||
<div class="mx-auto grid items-center gap-10 px-4 {% if hasImage %}max-w-6xl md:grid-cols-2 md:gap-16{% else %}max-w-3xl{% endif %}">
|
||||
{% if hasImage %}<div class="{% if mediaPosition == "right" %}md:order-2{% else %}md:order-1{% endif %}"><div class="deco-step">{% img image alt=title class="w-full h-auto object-cover" %}</div></div>{% endif %}
|
||||
<div class="{% if hasImage %}{% if mediaPosition == "right" %}md:order-1{% else %}md:order-2{% endif %}{% else %}text-center{% endif %}">
|
||||
{% if eyebrow %}<div class="mb-3 flex items-center gap-4 {% if not hasImage %}justify-center{% endif %}"><span class="deco-rule w-10"></span><span class="deco-caps text-xs" style="color:hsl(var(--primary));">{{ eyebrow }}</span>{% if not hasImage %}<span class="deco-rule w-10"></span>{% endif %}</div>{% endif %}
|
||||
{% if title %}<h2 class="deco-caps text-3xl md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ title }}</h2>{% endif %}
|
||||
{% if description %}<div class="mt-4 space-y-4 text-lg italic {% if not hasImage %}mx-auto max-w-xl{% endif %}" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ description|safe }}</div>{% endif %}
|
||||
{% if seats or minimum %}<dl class="deco-stats mt-6 {% if not hasImage %}deco-stats-center{% endif %}">{% if seats %}<div><dt class="deco-caps text-xs" style="color:hsl(var(--primary));">Capacity</dt><dd class="mt-1">{{ seats }}</dd></div>{% endif %}{% if minimum %}<div><dt class="deco-caps text-xs" style="color:hsl(var(--primary));">Minimum</dt><dd class="mt-1">{{ minimum }}</dd></div>{% endif %}</dl>{% endif %}
|
||||
{% if enquireUrl %}<a href="{{ enquireUrl }}" class="deco-pill mt-8 inline-flex items-center gap-2">{{ enquireLabel|default:"Enquire" }}</a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,67 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Private Dining",
|
||||
"description": "Private dining room showcase — framed image with room details and an enquiry CTA.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"eyebrow": {
|
||||
"type": "string",
|
||||
"title": "Eyebrow",
|
||||
"description": "Small caps label above the heading.",
|
||||
"x-editor": "text",
|
||||
"default": "Private dining"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"title": "Room name",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"title": "Description",
|
||||
"description": "Room description and what the experience includes.",
|
||||
"x-editor": "richtext",
|
||||
"default": ""
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "Room image",
|
||||
"x-editor": "media",
|
||||
"default": ""
|
||||
},
|
||||
"seats": {
|
||||
"type": "string",
|
||||
"title": "Seats",
|
||||
"description": "e.g. 'Seats 2 to 14'.",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"minimum": {
|
||||
"type": "string",
|
||||
"title": "Minimum spend",
|
||||
"description": "e.g. 'From $2,400'.",
|
||||
"x-editor": "text",
|
||||
"default": ""
|
||||
},
|
||||
"enquireLabel": {
|
||||
"type": "string",
|
||||
"title": "Enquire label",
|
||||
"x-editor": "text",
|
||||
"default": "Enquire"
|
||||
},
|
||||
"enquireUrl": {
|
||||
"type": "string",
|
||||
"title": "Enquire URL",
|
||||
"x-editor": "link",
|
||||
"default": ""
|
||||
},
|
||||
"mediaPosition": {
|
||||
"type": "string",
|
||||
"title": "Image side",
|
||||
"enum": ["left", "right"],
|
||||
"x-editor": "select",
|
||||
"default": "left"
|
||||
}
|
||||
}
|
||||
}
|
||||
21
fonts.json
21
fonts.json
@ -1,20 +1 @@
|
||||
[
|
||||
{
|
||||
"name": "Cinzel",
|
||||
"family": "Cinzel",
|
||||
"variants": [
|
||||
{ "weight": "400", "style": "normal", "file": "fonts/cinzel-400.woff2" },
|
||||
{ "weight": "700", "style": "normal", "file": "fonts/cinzel-700.woff2" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cormorant Garamond",
|
||||
"family": "Cormorant Garamond",
|
||||
"variants": [
|
||||
{ "weight": "400", "style": "normal", "file": "fonts/cormorant-garamond-400.woff2" },
|
||||
{ "weight": "400", "style": "italic", "file": "fonts/cormorant-garamond-400-italic.woff2" },
|
||||
{ "weight": "600", "style": "normal", "file": "fonts/cormorant-garamond-600.woff2" },
|
||||
{ "weight": "700", "style": "normal", "file": "fonts/cormorant-garamond-700.woff2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
[]
|
||||
|
||||
@ -30,79 +30,12 @@ page_templates:
|
||||
title: Grand Ballroom
|
||||
description: "Edge-to-edge gallery layout for venues and lookbooks."
|
||||
slots: [header, main, footer]
|
||||
- system: art-deco
|
||||
key: blog-index
|
||||
title: Editorial Index
|
||||
description: "Blog index with gilded masthead, featured and post-grid slots."
|
||||
slots: [header, featured, main, footer]
|
||||
- system: art-deco
|
||||
key: contact
|
||||
title: Reservations
|
||||
description: "Contact layout with optional aside for hours and location."
|
||||
slots: [header, main, aside, footer]
|
||||
- system: art-deco
|
||||
key: auth
|
||||
title: Members
|
||||
description: "Centred auth shell with wordmark and sunburst crest."
|
||||
slots: [main, footer]
|
||||
|
||||
template_overrides:
|
||||
# Chrome
|
||||
- { template: art-deco, block: navbar }
|
||||
- { template: art-deco, block: footer }
|
||||
- { template: art-deco, block: utility-bar }
|
||||
- { template: art-deco, block: announcement-bar }
|
||||
# Marketing
|
||||
- { template: art-deco, block: hero }
|
||||
- { template: art-deco, block: feature-grid }
|
||||
- { template: art-deco, block: rich-section }
|
||||
- { template: art-deco, block: stats }
|
||||
- { template: art-deco, block: testimonial }
|
||||
- { template: art-deco, block: logo-strip }
|
||||
- { template: art-deco, block: pricing }
|
||||
- { template: art-deco, block: team }
|
||||
- { template: art-deco, block: faq }
|
||||
- { template: art-deco, block: timeline }
|
||||
- { template: art-deco, block: cta }
|
||||
- { template: art-deco, block: countdown }
|
||||
# Primitives
|
||||
- { template: art-deco, block: heading }
|
||||
- { template: art-deco, block: text }
|
||||
- { template: art-deco, block: rich-text }
|
||||
- { template: art-deco, block: image }
|
||||
- { template: art-deco, block: quote }
|
||||
- { template: art-deco, block: divider }
|
||||
- { template: art-deco, block: button }
|
||||
- { template: art-deco, block: card }
|
||||
- { template: art-deco, block: gallery }
|
||||
- { template: art-deco, block: video-embed }
|
||||
- { template: art-deco, block: audio-embed }
|
||||
# Commerce / local
|
||||
- { template: art-deco, block: menu-list }
|
||||
- { template: art-deco, block: event-list }
|
||||
- { template: art-deco, block: contact-form }
|
||||
- { template: art-deco, block: contact-card }
|
||||
- { template: art-deco, block: hours-location }
|
||||
- { template: art-deco, block: social-links }
|
||||
# Blog family
|
||||
- { template: art-deco, block: blog-hero }
|
||||
- { template: art-deco, block: featured-posts }
|
||||
- { template: art-deco, block: related-posts }
|
||||
- { template: art-deco, block: popular-posts }
|
||||
- { template: art-deco, block: category-list }
|
||||
- { template: art-deco, block: post-hero }
|
||||
- { template: art-deco, block: post-metadata }
|
||||
- { template: art-deco, block: author-bio }
|
||||
- { template: art-deco, block: author-bio-hero }
|
||||
- { template: art-deco, block: newsletter-signup }
|
||||
- { template: art-deco, block: breadcrumbs }
|
||||
- { template: art-deco, block: sidebar-nav }
|
||||
# Auth surface
|
||||
- { template: art-deco, block: auth-form }
|
||||
- { template: art-deco, block: password-reset-form }
|
||||
- { template: art-deco, block: auth-status }
|
||||
# System
|
||||
- { template: art-deco, block: page-suggestions }
|
||||
- { template: art-deco, block: image }
|
||||
|
||||
email_wrappers:
|
||||
- art-deco
|
||||
@ -128,16 +61,6 @@ css:
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* deco-hero-compact — image-less hero: comfortable padding, no viewport-height balloon. */
|
||||
.deco-hero-compact { padding-top: 4rem; padding-bottom: 4rem; }
|
||||
@media (min-width: 768px) {
|
||||
.deco-hero-compact { padding-top: 6rem; padding-bottom: 6rem; }
|
||||
}
|
||||
|
||||
/* deco-stats — capacity/minimum figure row: guaranteed column gap so values never collide. */
|
||||
.deco-stats { display: flex; flex-wrap: wrap; gap: 0.75rem 3rem; }
|
||||
.deco-stats-center { justify-content: center; }
|
||||
|
||||
/* deco-frame — stepped ziggurat frame, layered borders + clipped corners. */
|
||||
.deco-frame {
|
||||
position: relative;
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
{
|
||||
"key": "art-deco:default-master",
|
||||
"title": "Art Deco Default Master",
|
||||
"page_templates": ["default", "article", "blog-index", "contact"],
|
||||
"page_templates": ["default", "article"],
|
||||
"blocks": [
|
||||
{ "block_key": "navbar", "title": "Gilded Navigation", "content": { "menuName": "main", "logoType": "text", "logoText": { "text": "Maison Doré" } }, "slot": "header", "sort_order": 0 },
|
||||
{ "block_key": "divider", "title": "Header Fan Divider", "content": { "variant": "ornament", "icon": "lucide:diamond" }, "slot": "header", "sort_order": 1 },
|
||||
{ "block_key": "navbar", "title": "Brass Navigation", "content": { "menuName": "main" }, "slot": "header", "sort_order": 0 },
|
||||
{ "block_key": "art-deco:divider_fan", "title": "Header Fan Divider", "content": { "variant": "sunburst" }, "slot": "header", "sort_order": 1 },
|
||||
{ "block_key": "slot", "title": "Main Content", "content": { "slotName": "main", "placeholder": "Page content" }, "slot": "main", "sort_order": 0 },
|
||||
{ "block_key": "footer", "title": "Site Footer", "content": { "layout": "centered", "companyName": "Maison Doré", "tagline": "A supper club in the grand manner." }, "slot": "footer", "sort_order": 0 }
|
||||
{ "block_key": "art-deco:footer", "title": "Site Footer", "content": { "address": "", "reservationsEmail": "", "showSocial": "true" }, "slot": "footer", "sort_order": 0 }
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -15,11 +15,11 @@
|
||||
"title": "Art Deco Marquee Master",
|
||||
"page_templates": ["landing", "full-width"],
|
||||
"blocks": [
|
||||
{ "block_key": "navbar", "title": "Gilded Navigation", "content": { "menuName": "main", "logoType": "text", "logoText": { "text": "Maison Doré" } }, "slot": "marquee", "sort_order": 0 },
|
||||
{ "block_key": "art-deco:reservation", "title": "Reservation Strip", "content": { "phone": "+1 555 0126", "openTable": "/contact", "hours": ["Dinner Tuesday to Sunday", "6pm to late"] }, "slot": "marquee", "sort_order": 1 },
|
||||
{ "block_key": "navbar", "title": "Brass Navigation", "content": { "menuName": "main" }, "slot": "marquee", "sort_order": 0 },
|
||||
{ "block_key": "art-deco:reservation", "title": "Reservation Strip", "content": { "phone": "", "openTable": "" }, "slot": "marquee", "sort_order": 1 },
|
||||
{ "block_key": "slot", "title": "Main Content", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
|
||||
{ "block_key": "divider", "title": "CTA Fan Divider", "content": { "variant": "ornament", "icon": "lucide:diamond" }, "slot": "cta", "sort_order": 0 },
|
||||
{ "block_key": "footer", "title": "Site Footer", "content": { "layout": "centered", "companyName": "Maison Doré", "tagline": "A supper club in the grand manner." }, "slot": "footer", "sort_order": 0 }
|
||||
{ "block_key": "art-deco:divider_fan", "title": "CTA Fan Divider", "content": { "variant": "scallop" }, "slot": "cta", "sort_order": 0 },
|
||||
{ "block_key": "art-deco:footer", "title": "Site Footer", "content": { "showSocial": "true" }, "slot": "footer", "sort_order": 0 }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name = "art-deco"
|
||||
display_name = "Art Deco"
|
||||
scope = "@themes"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
description = "Luxury Art Deco theme with champagne gold gradients, jet black, ivory and geometric fan motifs for hotels, fine dining, weddings and jewellers."
|
||||
kind = "theme"
|
||||
categories = ["templates"]
|
||||
|
||||
100
presets.json
100
presets.json
@ -52,9 +52,9 @@
|
||||
{
|
||||
"id": "ivory-rose",
|
||||
"name": "Ivory & Rose Gold",
|
||||
"description": "Soft ivory by day, warm ember by night, with rose-gold flourishes for weddings and jewellers.",
|
||||
"description": "Soft ivory with rose-gold flourishes for weddings and jewellers.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"mode": "light",
|
||||
"lightColors": {
|
||||
"background": "36 40% 97%",
|
||||
"foreground": "20 15% 14%",
|
||||
@ -75,57 +75,15 @@
|
||||
"border": "25 30% 82%",
|
||||
"input": "25 25% 86%",
|
||||
"ring": "18 55% 58%"
|
||||
},
|
||||
"darkColors": {
|
||||
"background": "20 18% 8%",
|
||||
"foreground": "30 30% 92%",
|
||||
"card": "20 18% 12%",
|
||||
"cardForeground": "30 30% 92%",
|
||||
"popover": "20 18% 12%",
|
||||
"popoverForeground": "30 30% 92%",
|
||||
"primary": "18 60% 62%",
|
||||
"primaryForeground": "20 20% 8%",
|
||||
"secondary": "20 15% 16%",
|
||||
"secondaryForeground": "30 25% 88%",
|
||||
"muted": "20 12% 14%",
|
||||
"mutedForeground": "25 15% 62%",
|
||||
"accent": "15 62% 62%",
|
||||
"accentForeground": "20 20% 8%",
|
||||
"destructive": "0 72% 52%",
|
||||
"destructiveForeground": "30 30% 94%",
|
||||
"border": "20 20% 24%",
|
||||
"input": "20 18% 20%",
|
||||
"ring": "18 60% 62%"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "velvet-onyx",
|
||||
"name": "Velvet Onyx",
|
||||
"description": "Velvet-tinted ivory by day, deep onyx and gold stage-light by night, for theatre and after-dark dining.",
|
||||
"description": "Deep velvet onyx with gold and rose stage-lights for theatre and after-dark dining.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"lightColors": {
|
||||
"background": "280 15% 96%",
|
||||
"foreground": "260 20% 12%",
|
||||
"card": "280 12% 99%",
|
||||
"cardForeground": "260 20% 12%",
|
||||
"popover": "280 12% 99%",
|
||||
"popoverForeground": "260 20% 12%",
|
||||
"primary": "42 60% 48%",
|
||||
"primaryForeground": "280 20% 8%",
|
||||
"secondary": "280 15% 92%",
|
||||
"secondaryForeground": "260 20% 12%",
|
||||
"muted": "280 12% 93%",
|
||||
"mutedForeground": "260 12% 40%",
|
||||
"accent": "320 35% 52%",
|
||||
"accentForeground": "280 20% 96%",
|
||||
"destructive": "0 70% 45%",
|
||||
"destructiveForeground": "280 15% 96%",
|
||||
"border": "280 15% 82%",
|
||||
"input": "280 12% 86%",
|
||||
"ring": "42 60% 48%"
|
||||
},
|
||||
"mode": "dark",
|
||||
"darkColors": {
|
||||
"background": "260 20% 6%",
|
||||
"foreground": "42 40% 92%",
|
||||
@ -148,55 +106,5 @@
|
||||
"ring": "42 70% 60%"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "emerald-gilt",
|
||||
"name": "Emerald & Gilt",
|
||||
"description": "Deco emerald and gilt — parchment and jade by day, emerald lacquer and gold by night.",
|
||||
"theme": {
|
||||
"mode": "both",
|
||||
"lightColors": {
|
||||
"background": "45 35% 95%",
|
||||
"foreground": "160 25% 12%",
|
||||
"card": "45 30% 98%",
|
||||
"cardForeground": "160 25% 12%",
|
||||
"popover": "45 30% 98%",
|
||||
"popoverForeground": "160 25% 12%",
|
||||
"primary": "42 55% 48%",
|
||||
"primaryForeground": "160 25% 8%",
|
||||
"secondary": "150 15% 88%",
|
||||
"secondaryForeground": "160 25% 12%",
|
||||
"muted": "150 12% 91%",
|
||||
"mutedForeground": "160 12% 38%",
|
||||
"accent": "160 40% 30%",
|
||||
"accentForeground": "45 35% 95%",
|
||||
"destructive": "0 70% 45%",
|
||||
"destructiveForeground": "45 35% 95%",
|
||||
"border": "150 20% 78%",
|
||||
"input": "150 18% 83%",
|
||||
"ring": "42 55% 48%"
|
||||
},
|
||||
"darkColors": {
|
||||
"background": "162 25% 6%",
|
||||
"foreground": "45 35% 92%",
|
||||
"card": "162 22% 9%",
|
||||
"cardForeground": "45 35% 92%",
|
||||
"popover": "162 22% 9%",
|
||||
"popoverForeground": "45 35% 92%",
|
||||
"primary": "42 68% 58%",
|
||||
"primaryForeground": "162 25% 8%",
|
||||
"secondary": "162 18% 13%",
|
||||
"secondaryForeground": "45 30% 88%",
|
||||
"muted": "162 15% 11%",
|
||||
"mutedForeground": "45 15% 62%",
|
||||
"accent": "158 45% 45%",
|
||||
"accentForeground": "162 25% 6%",
|
||||
"destructive": "0 72% 52%",
|
||||
"destructiveForeground": "45 35% 95%",
|
||||
"border": "162 20% 20%",
|
||||
"input": "162 18% 16%",
|
||||
"ring": "42 68% 58%"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
200
seed/seed.json
200
seed/seed.json
@ -1,200 +0,0 @@
|
||||
{
|
||||
"demo": true,
|
||||
"settings": {
|
||||
"merge": {
|
||||
"companyName": "Maison Doré",
|
||||
"tagline": "A supper club in the grand manner."
|
||||
}
|
||||
},
|
||||
"data_tables": [
|
||||
{
|
||||
"key": "contact_submissions",
|
||||
"name": "Reservation Enquiries",
|
||||
"description": "Seeded contact-form submissions for the Maison Doré 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": "party", "label": "Party size", "type": "text", "required": false },
|
||||
{ "key": "message", "label": "Message", "type": "text", "required": true }
|
||||
]
|
||||
}
|
||||
],
|
||||
"pages": [
|
||||
{
|
||||
"slug": "/",
|
||||
"title": "Maison Doré",
|
||||
"template_key": "landing",
|
||||
"blocks": [
|
||||
{
|
||||
"block_key": "hero",
|
||||
"title": "Hero",
|
||||
"slot": "main",
|
||||
"sort_order": 1,
|
||||
"content": {
|
||||
"template": "centered",
|
||||
"eyebrow": "Established 1926",
|
||||
"headline": "Maison Doré",
|
||||
"subheadline": "A supper club in the grand manner.",
|
||||
"description": "Dinner and late suppers, served under gilded ceilings. A short tasting menu, a long cellar, and a room built for the evening.",
|
||||
"ctaPrimary": { "text": "Reserve a table", "url": "/contact" },
|
||||
"ctaSecondary": { "text": "Read the menu", "url": "#tasting" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"block_key": "art-deco:chef_signature",
|
||||
"title": "Chef's Signature",
|
||||
"slot": "main",
|
||||
"sort_order": 2,
|
||||
"content": {
|
||||
"eyebrow": "Chef's signature",
|
||||
"dish": "Gold-leaf oyster, champagne mignonette",
|
||||
"note": "The dish that opened the room in 1926. We still serve it the same way, on ice, one at a time.",
|
||||
"chef": "Elise Marchand, Head Chef"
|
||||
}
|
||||
},
|
||||
{
|
||||
"block_key": "art-deco:menu",
|
||||
"title": "Tasting Menu",
|
||||
"slot": "main",
|
||||
"sort_order": 3,
|
||||
"content": {
|
||||
"title": "Chef's Tasting",
|
||||
"courses": [
|
||||
{ "name": "Oysters, champagne mignonette", "description": "Half a dozen, on ice.", "price": "$32" },
|
||||
{ "name": "Consommé doré", "description": "Clarified beef broth, tarragon, gold leaf.", "price": "$24" },
|
||||
{ "name": "Turbot, beurre blanc", "description": "Line-caught, roasted on the bone.", "price": "$58" },
|
||||
{ "name": "Crown of lamb", "description": "Herbs, salt-baked roots, jus.", "price": "$62" },
|
||||
{ "name": "Grand Marnier soufflé", "description": "To finish. Order at the start.", "price": "$28" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"block_key": "art-deco:private_dining",
|
||||
"title": "Private Dining",
|
||||
"slot": "main",
|
||||
"sort_order": 4,
|
||||
"content": {
|
||||
"eyebrow": "Private dining",
|
||||
"title": "The Gold Room",
|
||||
"description": "A room of your own behind the main floor. One long table, a dedicated maître d', and the full cellar. We write the menu with you.",
|
||||
"seats": "Seats 2 to 14",
|
||||
"minimum": "From $2,400",
|
||||
"enquireLabel": "Enquire",
|
||||
"enquireUrl": "/contact",
|
||||
"mediaPosition": "left"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/about",
|
||||
"title": "The House",
|
||||
"template_key": "default",
|
||||
"blocks": [
|
||||
{ "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "The House", "level": 1 } },
|
||||
{ "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "<p>Maison Doré opened on a narrow street in 1926 and has kept its hours ever since. We take reservations for dinner and hold a few tables back for late suppers.</p><p>The kitchen runs a short tasting menu that changes with the season. The cellar runs long. The room stays the same, which is the point.</p>" } },
|
||||
{ "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 3, "content": { "variant": "ornament", "icon": "lucide:diamond" } },
|
||||
{ "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 4, "content": { "style": "block", "align": "center", "quote": "Come for dinner, stay for the last pour.", "attribution": "The House" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/blog",
|
||||
"title": "From the Floor",
|
||||
"template_key": "blog-index",
|
||||
"blocks": [
|
||||
{ "block_key": "card", "title": "Post: Gold Standard", "slot": "main", "sort_order": 1, "content": { "layout": "vertical", "title": "The gold standard", "text": "<p>Why one oyster, served one at a time, still opens every table.</p>", "link": "/blog/the-gold-standard", "linkLabel": "Read on" } },
|
||||
{ "block_key": "card", "title": "Post: A Night", "slot": "main", "sort_order": 2, "content": { "layout": "vertical", "title": "A night at the club", "text": "<p>From the first cocktail to the last soufflé. How an evening unfolds.</p>", "link": "/blog/a-night-at-the-club", "linkLabel": "Read on" } },
|
||||
{ "block_key": "card", "title": "Post: Cellar", "slot": "main", "sort_order": 3, "content": { "layout": "vertical", "title": "Notes from the cellar", "text": "<p>What we pour and why. A short walk through the list.</p>", "link": "/blog/notes-from-the-cellar", "linkLabel": "Read on" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/blog/the-gold-standard",
|
||||
"title": "The gold standard",
|
||||
"template_key": "article",
|
||||
"parent_slug": "/blog",
|
||||
"blocks": [
|
||||
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The gold standard", "level": 1 } },
|
||||
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>The oyster came first, in 1926, and it has not left the menu since. We serve it on ice, one at a time, with a champagne mignonette and a single leaf of gold.</p><p>The point is restraint. One oyster, done right, sets the tone for the meal that follows.</p>" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/blog/a-night-at-the-club",
|
||||
"title": "A night at the club",
|
||||
"template_key": "article",
|
||||
"parent_slug": "/blog",
|
||||
"blocks": [
|
||||
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "A night at the club", "level": 1 } },
|
||||
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Doors open at six. The first cocktail arrives before the menu. Dinner runs five courses, unhurried, and the soufflé is ordered at the start.</p><p>The band plays after nine. Late suppers run until the last table is ready to leave.</p>" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/blog/notes-from-the-cellar",
|
||||
"title": "Notes from the cellar",
|
||||
"template_key": "article",
|
||||
"parent_slug": "/blog",
|
||||
"blocks": [
|
||||
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Notes from the cellar", "level": 1 } },
|
||||
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>The list is long and the choices are few, by design. We pour champagne by the glass, keep a deep bench of burgundy, and hold a small shelf of older bottles for the ones who ask.</p><p>Tell the sommelier what you are eating. The rest takes care of itself.</p>" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/contact",
|
||||
"title": "Reservations",
|
||||
"template_key": "contact",
|
||||
"blocks": [
|
||||
{
|
||||
"block_key": "contact-form",
|
||||
"title": "Reservation Enquiry",
|
||||
"slot": "main",
|
||||
"sort_order": 1,
|
||||
"content": {
|
||||
"heading": "Request a table",
|
||||
"description": "Tell us the date, the hour and the party. We will confirm by email.",
|
||||
"submitLabel": "Request a table",
|
||||
"successMessage": "Thank you. Your table request has been received. We will confirm by email.",
|
||||
"fields": [
|
||||
{ "name": "name", "label": "Your name", "type": "text", "required": true, "width": "half" },
|
||||
{ "name": "email", "label": "Email", "type": "email", "required": true, "width": "half" },
|
||||
{ "name": "party", "label": "Party size", "type": "text", "required": false, "width": "half" },
|
||||
{ "name": "message", "label": "Date, time and any notes", "type": "textarea", "required": true, "width": "full" }
|
||||
],
|
||||
"formConfig": { "enabled": true, "captchaEnabled": false, "targetTable": "contact_submissions" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"block_key": "hours-location",
|
||||
"title": "Hours & Location",
|
||||
"slot": "aside",
|
||||
"sort_order": 1,
|
||||
"content": {
|
||||
"heading": "Hours",
|
||||
"hours": [
|
||||
{ "day": "Tuesday to Thursday", "hours": "6pm to late" },
|
||||
{ "day": "Friday to Saturday", "hours": "5pm to late" },
|
||||
{ "day": "Sunday", "hours": "5pm to 10pm" },
|
||||
{ "day": "Monday", "closed": true }
|
||||
],
|
||||
"specialHoursNote": "Late suppers from 10pm, Friday and Saturday.",
|
||||
"address": "12 Gilt Lane\nThe Old Quarter",
|
||||
"phone": "+1 555 0126"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "/login",
|
||||
"title": "Members",
|
||||
"template_key": "auth",
|
||||
"blocks": [
|
||||
{ "block_key": "auth-form", "title": "Sign in", "slot": "main", "sort_order": 1, "content": { "default_tab": "login", "show_social": false } },
|
||||
{ "block_key": "text", "title": "Foot", "slot": "footer", "sort_order": 1, "content": { "text": "<p>Members book priority tables and private-room dates.</p>" } }
|
||||
]
|
||||
}
|
||||
],
|
||||
"menu_items": [
|
||||
{ "menu": "main", "label": "Home", "page_slug": "/", "sort_order": 1 },
|
||||
{ "menu": "main", "label": "The House", "page_slug": "/about", "sort_order": 2 },
|
||||
{ "menu": "main", "label": "From the Floor", "page_slug": "/blog", "sort_order": 3 },
|
||||
{ "menu": "main", "label": "Reservations", "page_slug": "/contact", "sort_order": 4 }
|
||||
]
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
{
|
||||
"workflows": [
|
||||
{
|
||||
"key": "contact_notify_admins",
|
||||
"name": "Reservation enquiry to admins",
|
||||
"description": "On a reservation-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" }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -3,14 +3,18 @@
|
||||
{{ head_html|safe }}
|
||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||
{{ admin_banner_html|safe }}
|
||||
<header class="w-full">{{ slots.header|safe }}</header>
|
||||
<header class="w-full">
|
||||
<div class="max-w-3xl mx-auto px-4">{{ slots.header|safe }}</div>
|
||||
</header>
|
||||
<div class="flex-grow grid gap-12 max-w-5xl mx-auto w-full px-4 py-12 md:grid-cols-[2fr_1fr]">
|
||||
<main class="prose max-w-none">
|
||||
{% if slots.main %}<article class="deco-dropcap" data-deco-dropcap="true">{{ slots.main|safe }}</article>{% else %}<div class="py-20 text-center"><p class="text-muted-foreground">No content blocks assigned to this page.</p></div>{% endif %}
|
||||
</main>
|
||||
<aside class="w-full">{{ slots.aside|safe }}</aside>
|
||||
</div>
|
||||
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||
<footer class="w-full mt-auto">
|
||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
||||
</footer>
|
||||
{{ body_end_html|safe }}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||
{{ head_html|safe }}
|
||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col deco-grain" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||
{{ admin_banner_html|safe }}
|
||||
<main class="flex-grow w-full flex flex-col items-center justify-center px-4 py-12">
|
||||
<div class="w-full max-w-md">
|
||||
<a href="/" class="block text-center" aria-label="{{ site_settings.Title }} home">
|
||||
{% if site_settings.Logo %}<img src="{{ site_settings.Logo }}" alt="{{ site_settings.LogoAlt }}" class="mx-auto h-12 w-auto">{% else %}<span class="deco-caps text-2xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ site_settings.Title|default:"BlockNinja" }}</span>{% endif %}
|
||||
</a>
|
||||
<div class="mx-auto mt-4 mb-6 h-6 w-32 deco-sunburst" aria-hidden="true"></div>
|
||||
<div>{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20 text-center"><p class="italic" style="color:hsl(var(--muted-foreground));">No form assigned to this page.</p></div>{% endif %}</div>
|
||||
{% if slots.footer %}<div class="mt-6 text-center text-sm" style="color:hsl(var(--muted-foreground));">{{ slots.footer|safe }}</div>{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
{{ body_end_html|safe }}
|
||||
</body>
|
||||
</html>
|
||||
@ -1,23 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||
{{ head_html|safe }}
|
||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||
{{ admin_banner_html|safe }}
|
||||
{% if slots.header %}<header class="w-full">{{ slots.header|safe }}</header>{% endif %}
|
||||
<main class="flex-grow w-full">
|
||||
<div class="max-w-6xl mx-auto px-4 py-12 md:py-16">
|
||||
{% if title %}
|
||||
<div class="text-center">
|
||||
<h1 class="deco-caps deco-underline mx-auto w-fit text-4xl md:text-5xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);">{{ title }}</h1>
|
||||
{% if page_meta.MetaDescription %}<p class="mt-4 text-lg italic" style="color:hsl(var(--muted-foreground));">{{ page_meta.MetaDescription }}</p>{% endif %}
|
||||
<div class="mx-auto mt-6 h-6 w-40 deco-sunburst" aria-hidden="true"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if slots.featured %}<section class="mt-12">{{ slots.featured|safe }}</section>{% endif %}
|
||||
{% if slots.main %}<section class="mt-12">{{ slots.main|safe }}</section>{% else %}<div class="py-20 text-center"><p class="italic" style="color:hsl(var(--muted-foreground));">No posts published yet.</p></div>{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
{% if slots.footer %}<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>{% endif %}
|
||||
{{ body_end_html|safe }}
|
||||
</body>
|
||||
</html>
|
||||
@ -1,22 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" class="{% if theme_mode == "dark" %}dark{% endif %}">
|
||||
{{ head_html|safe }}
|
||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||
{{ admin_banner_html|safe }}
|
||||
{% if slots.header %}<header class="w-full">{{ slots.header|safe }}</header>{% endif %}
|
||||
<main class="flex-grow w-full">
|
||||
<div class="max-w-6xl mx-auto px-4 py-12 md:py-16">
|
||||
{% if slots.aside %}
|
||||
<div class="grid gap-12 md:grid-cols-[2fr_1fr]">
|
||||
<div>{% if slots.main %}{{ slots.main|safe }}{% endif %}</div>
|
||||
<aside class="w-full md:border-l md:border-[hsl(var(--primary)/0.3)] md:pl-10">{{ slots.aside|safe }}</aside>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="max-w-3xl mx-auto">{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20 text-center"><p class="italic" style="color:hsl(var(--muted-foreground));">No content blocks assigned to this page.</p></div>{% endif %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
{% if slots.footer %}<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>{% endif %}
|
||||
{{ body_end_html|safe }}
|
||||
</body>
|
||||
</html>
|
||||
@ -3,11 +3,15 @@
|
||||
{{ head_html|safe }}
|
||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||
{{ admin_banner_html|safe }}
|
||||
<header class="w-full">{{ slots.header|safe }}</header>
|
||||
<header class="w-full">
|
||||
<div class="max-w-5xl mx-auto px-4">{{ slots.header|safe }}</div>
|
||||
</header>
|
||||
<main class="flex-grow max-w-3xl mx-auto w-full px-4 py-12 text-center">
|
||||
{% if slots.main %}{{ slots.main|safe }}{% else %}<div class="py-20"><p class="text-muted-foreground">No content blocks assigned to this page.</p></div>{% endif %}
|
||||
</main>
|
||||
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||
<footer class="w-full mt-auto">
|
||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
||||
</footer>
|
||||
{{ body_end_html|safe }}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -4,11 +4,13 @@
|
||||
<body class="bg-background text-foreground antialiased min-h-screen flex flex-col" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif);">
|
||||
{{ admin_banner_html|safe }}
|
||||
<section class="w-full">{{ slots.marquee|safe }}</section>
|
||||
<main class="flex-grow w-full">
|
||||
{% if slots.main %}{{ slots.main|safe }}{% endif %}
|
||||
<main class="flex-grow">
|
||||
{% if slots.main %}<div class="max-w-5xl mx-auto px-4 py-16 text-center">{{ slots.main|safe }}</div>{% endif %}
|
||||
</main>
|
||||
<section class="w-full">{{ slots.cta|safe }}</section>
|
||||
<footer class="w-full mt-auto">{{ slots.footer|safe }}</footer>
|
||||
<footer class="w-full mt-auto">
|
||||
<div class="max-w-5xl mx-auto px-4">{{ slots.footer|safe }}</div>
|
||||
</footer>
|
||||
{{ body_end_html|safe }}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
{# announcement-bar override — gilded banner. Dismiss <script>, data-bn-annkey and localStorage keying preserved verbatim. Fields mirror builtin: variant, message, linkText, linkUrl, dismissable. #}
|
||||
{% set anncls = "bg-primary/15 text-foreground" %}
|
||||
{% if variant == "promo" %}{% set anncls = "bg-primary text-primary-foreground" %}{% elif variant == "alert" %}{% set anncls = "bg-destructive text-destructive-foreground" %}{% endif %}
|
||||
<div data-block-override="art-deco:announcement-bar" data-bn-announcement data-bn-annkey="{{ variant|default:'info' }}:{{ message|slugify }}" class="bn-announcement w-full border-b border-[hsl(var(--primary)/0.4)] {{ anncls }} {{ class }}">
|
||||
<div class="max-w-7xl mx-auto px-10 py-2 relative flex items-center justify-center gap-2 text-sm text-center">
|
||||
<p class="deco-caps text-xs">{{ message }}{% if linkText and linkUrl %} <a href="{{ linkUrl }}" class="underline underline-offset-2 hover:opacity-80">{{ linkText }}</a>{% endif %}</p>
|
||||
{% if dismissable %}<button type="button" data-bn-ann-dismiss aria-label="Dismiss announcement" class="absolute right-3 top-1/2 -translate-y-1/2 inline-flex items-center justify-center p-1 rounded hover:bg-black/10 transition-colors"><svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></button>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if dismissable %}<script>
|
||||
(function(){
|
||||
var bars=document.querySelectorAll('[data-bn-announcement]:not([data-bn-ann-wired])');
|
||||
bars.forEach(function(bar){
|
||||
bar.setAttribute('data-bn-ann-wired','1');
|
||||
var key='bnann:'+bar.getAttribute('data-bn-annkey');
|
||||
try{if(localStorage.getItem(key)==='1'){bar.style.display='none';return;}}catch(e){}
|
||||
var btn=bar.querySelector('[data-bn-ann-dismiss]');
|
||||
if(btn)btn.addEventListener('click',function(){bar.style.display='none';try{localStorage.setItem(key,'1');}catch(e){}});
|
||||
});
|
||||
})();
|
||||
</script>{% endif %}
|
||||
@ -1,16 +0,0 @@
|
||||
{# audio-embed override — gold-framed player card. Fields + facade JS mirror builtin verbatim: url, media, artwork, title, artist, download. #}
|
||||
<figure data-block-override="art-deco:audio-embed" class="bn-audio deco-frame my-8 overflow-hidden bg-card text-card-foreground{% if class %} {{ class }}{% endif %}" data-bn-audio data-audio-url="{{ url|default:"" }}" data-audio-media="{% if media %}{{ media|mediaURL }}{% endif %}"><div class="flex items-center gap-4 p-4">{% if artwork %}<div class="deco-step h-16 w-16 shrink-0 overflow-hidden bg-muted">{% img artwork alt=title|default:"" class="h-full w-full object-cover" %}</div>{% endif %}<div class="min-w-0 flex-1">{% if title %}<p class="deco-caps truncate text-sm" style="font-family:var(--font-heading, 'Cinzel', Georgia, serif);color:hsl(var(--foreground));">{{ title }}</p>{% endif %}{% if artist %}<p class="truncate text-sm italic" style="color:hsl(var(--muted-foreground));">{{ artist }}</p>{% endif %}<div class="mt-2 flex items-center gap-3" data-bn-audio-slot><button type="button" data-bn-audio-play class="deco-pill inline-flex items-center gap-2 text-sm" aria-label="Play{% if title %}: {{ title }}{% endif %}">::lucide:play:sm:: Play</button>{% if download %}<a href="{% if media %}{{ media|mediaURL }}{% else %}{{ url }}{% endif %}" download class="deco-link inline-flex items-center gap-1 text-sm">::lucide:download:sm:: Download</a>{% endif %}</div></div></div></figure><script>
|
||||
(function(){
|
||||
if(window.__bnAudioFacade)return;window.__bnAudioFacade=true;
|
||||
document.addEventListener('click',function(e){
|
||||
var btn=e.target.closest('[data-bn-audio-play]');if(!btn)return;
|
||||
var fig=btn.closest('[data-bn-audio]');if(!fig)return;
|
||||
e.preventDefault();
|
||||
var src=fig.getAttribute('data-audio-media')||fig.getAttribute('data-audio-url')||'';
|
||||
if(!src)return;
|
||||
var slot=btn.closest('[data-bn-audio-slot]');
|
||||
var a=document.createElement('audio');a.src=src;a.controls=true;a.autoplay=true;a.preload='none';a.style.cssText='width:100%;min-width:12rem;height:2.25rem;';
|
||||
btn.remove();slot.insertBefore(a,slot.firstChild);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@ -1,33 +0,0 @@
|
||||
{# auth-form override — gilded login/register. Wiring is UNTOUCHABLE and reproduced exactly from builtin auth_blocks.go: single shared #auth-message, /api/auth/login (email,password) and /api/auth/register (username,email,password), hx-target #auth-message. Captcha widget injected from _captcha_widget when captchaEnabled (server enforces). Fields: default_tab, show_social (social omitted — needs Go/site config; graceful). #}
|
||||
{% if context.isPublicLoggedIn %}
|
||||
<div data-block-override="art-deco:auth-form" class="auth-form-logged-in mx-auto max-w-md text-center py-8">
|
||||
<p class="italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">You are signed in as <strong style="color:hsl(var(--foreground));">{{ context.publicUsername }}</strong></p>
|
||||
<a href="/account" class="deco-link mt-3 inline-block">My account</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div data-block-override="art-deco:auth-form" class="auth-form deco-frame mx-auto max-w-md bg-card p-8">
|
||||
<div id="auth-message"></div>
|
||||
<div class="mb-6 flex border-b border-[hsl(var(--primary)/0.3)]">
|
||||
<button type="button" onclick="document.getElementById('login-panel').classList.remove('hidden');document.getElementById('register-panel').classList.add('hidden');this.setAttribute('data-active','1');this.nextElementSibling.removeAttribute('data-active');" data-auth-tab {% if default_tab != "register" %}data-active="1"{% endif %} class="deco-caps flex-1 py-2 text-center text-xs border-b-2 border-transparent data-[active]:border-[hsl(var(--primary))] data-[active]:text-primary">Sign in</button>
|
||||
<button type="button" onclick="document.getElementById('register-panel').classList.remove('hidden');document.getElementById('login-panel').classList.add('hidden');this.setAttribute('data-active','1');this.previousElementSibling.removeAttribute('data-active');" data-auth-tab {% if default_tab == "register" %}data-active="1"{% endif %} class="deco-caps flex-1 py-2 text-center text-xs border-b-2 border-transparent data-[active]:border-[hsl(var(--primary))] data-[active]:text-primary">Register</button>
|
||||
</div>
|
||||
<div id="login-panel" class="{% if default_tab == "register" %}hidden{% endif %}">
|
||||
<form hx-post="/api/auth/login" hx-target="#auth-message" hx-swap="innerHTML">
|
||||
<div class="mb-3"><label class="deco-caps block text-xs mb-1" style="color:hsl(var(--primary));">Email</label><input type="email" name="email" required class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring" /></div>
|
||||
<div class="mb-4"><label class="deco-caps block text-xs mb-1" style="color:hsl(var(--primary));">Password</label><input type="password" name="password" required class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring" /></div>
|
||||
{% if _captcha_widget %}{{ _captcha_widget|safe }}{% endif %}
|
||||
<button type="submit" class="deco-pill w-full" hx-disabled-elt="this">Sign in</button>
|
||||
<p class="text-center mt-3 text-sm"><a href="/forgot-password" class="deco-link">Forgot password?</a></p>
|
||||
</form>
|
||||
</div>
|
||||
<div id="register-panel" class="{% if default_tab != "register" %}hidden{% endif %}">
|
||||
<form hx-post="/api/auth/register" hx-target="#auth-message" hx-swap="innerHTML">
|
||||
<div class="mb-3"><label class="deco-caps block text-xs mb-1" style="color:hsl(var(--primary));">Username</label><input type="text" name="username" required pattern="[a-zA-Z0-9_-]{3,30}" class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring" /></div>
|
||||
<div class="mb-3"><label class="deco-caps block text-xs mb-1" style="color:hsl(var(--primary));">Email</label><input type="email" name="email" required class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring" /></div>
|
||||
<div class="mb-4"><label class="deco-caps block text-xs mb-1" style="color:hsl(var(--primary));">Password</label><input type="password" name="password" required minlength="8" class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring" /></div>
|
||||
{% if _captcha_widget %}{{ _captcha_widget|safe }}{% endif %}
|
||||
<button type="submit" class="deco-pill w-full" hx-disabled-elt="this">Create account</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -1,31 +0,0 @@
|
||||
{# auth-status override — header login state. Logged-out: Sign in / Reserve links. Logged-in: gold monogram + dropdown (logout posts /api/auth/logout). Driven by context.isPublicLoggedIn / context.publicDisplayName / context.publicUsername. #}
|
||||
{% if context.isPublicLoggedIn %}
|
||||
<div data-block-override="art-deco:auth-status" class="auth-status relative">
|
||||
<button type="button" onclick="this.nextElementSibling.classList.toggle('hidden')" class="deco-caps flex items-center gap-2 text-xs opacity-90 hover:opacity-100 px-3 py-1.5 transition-colors">
|
||||
<span class="inline-flex h-7 w-7 items-center justify-center rounded-full text-[0.7rem] font-bold" style="background-color:hsl(var(--primary));color:hsl(var(--primary-foreground));">{{ context.publicDisplayName|default:context.publicUsername|first|upper }}</span>
|
||||
<span>{{ context.publicDisplayName|default:context.publicUsername }}</span>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
|
||||
</button>
|
||||
<div id="auth-dropdown-menu" class="hidden absolute right-0 top-full mt-1 w-48 deco-frame bg-card py-1 z-50">
|
||||
<a href="/account" class="block px-4 py-2 text-sm text-foreground hover:bg-accent">My profile</a>
|
||||
<a href="/account/reviews" class="block px-4 py-2 text-sm text-foreground hover:bg-accent">My reviews</a>
|
||||
<hr class="my-1 deco-rule"/>
|
||||
<button hx-post="/api/auth/logout" hx-swap="none" class="block w-full text-left px-4 py-2 text-sm text-destructive hover:bg-accent">Sign out</button>
|
||||
</div>
|
||||
<script>
|
||||
(function(){
|
||||
document.addEventListener('click', function(e) {
|
||||
var menu = document.getElementById('auth-dropdown-menu');
|
||||
var btn = document.querySelector('.auth-status > button');
|
||||
if (!menu || !btn) return;
|
||||
if (!btn.contains(e.target) && !menu.contains(e.target)) { menu.classList.add('hidden'); }
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
{% else %}
|
||||
<div data-block-override="art-deco:auth-status" class="auth-status flex items-center gap-2">
|
||||
<a href="/login" class="deco-caps text-xs px-3 py-1.5 opacity-80 hover:opacity-100 hover:text-primary transition-colors">Sign in</a>
|
||||
<a href="/login?tab=register" class="deco-pill text-xs">Reserve</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -1,22 +0,0 @@
|
||||
{# author-bio-hero (art-deco) — author-page header from the `authors` provider. #}
|
||||
{% if author %}
|
||||
<section data-block-override="art-deco:author-bio-hero" class="deco-rule-thick bg-background py-12 text-foreground md:py-16{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto flex max-w-3xl flex-col items-center px-4 text-center">
|
||||
{% if showAvatar and author.avatar_url %}<div class="mb-6 h-24 w-24 overflow-hidden rounded-full bg-muted ring-2 ring-primary">{% img author.avatar_url alt=author.display_name class="h-full w-full object-cover" %}</div>{% endif %}
|
||||
<div class="mb-4 flex items-center justify-center gap-4"><span class="deco-rule w-12"></span><span class="deco-rule w-12"></span></div>
|
||||
<h1 class="deco-caps text-3xl md:text-4xl text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ author.display_name }}</h1>
|
||||
{% if author.job_title or author.company %}<p class="deco-caps mt-2 text-sm text-primary">{{ author.job_title }}{% if author.job_title and author.company %} · {% endif %}{{ author.company }}</p>{% endif %}
|
||||
{% if author.bio %}<p class="mt-5 max-w-2xl leading-relaxed text-muted-foreground" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ author.bio }}</p>{% endif %}
|
||||
<div class="mt-6 flex flex-wrap items-center justify-center gap-4 text-sm text-muted-foreground">
|
||||
{% if showPostCount %}<span>{{ author.post_count|default:0 }} post{% if author.post_count != 1 %}s{% endif %}</span>{% endif %}
|
||||
{% if author.location %}<span>{{ author.location }}</span>{% endif %}
|
||||
</div>
|
||||
{% if showSocial %}<div class="mt-6 flex items-center justify-center gap-4">
|
||||
{% if author.website_url %}<a href="{{ author.website_url }}" target="_blank" rel="noopener noreferrer" class="text-muted-foreground transition-colors hover:text-primary" title="Website"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/lucide.svg#globe"></use></svg></a>{% endif %}
|
||||
{% if author.twitter_handle %}<a href="https://twitter.com/{{ author.twitter_handle|cut:"@" }}" target="_blank" rel="noopener noreferrer" class="text-muted-foreground transition-colors hover:text-primary" title="Twitter"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#x"></use></svg></a>{% endif %}
|
||||
{% if author.linkedin_url %}<a href="{{ author.linkedin_url }}" target="_blank" rel="noopener noreferrer" class="text-muted-foreground transition-colors hover:text-primary" title="LinkedIn"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#linkedin"></use></svg></a>{% endif %}
|
||||
{% if author.github_url %}<a href="{{ author.github_url }}" target="_blank" rel="noopener noreferrer" class="text-muted-foreground transition-colors hover:text-primary" title="GitHub"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#github"></use></svg></a>{% endif %}
|
||||
</div>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
@ -1,14 +0,0 @@
|
||||
{# author-bio (art-deco) — byline card sourced from the `post` provider's author_* fields. #}
|
||||
{% if post.author_name %}
|
||||
<aside data-block-override="art-deco:author-bio" class="deco-frame bg-card p-6 text-card-foreground{% if class %} {{ class }}{% endif %}">
|
||||
{% if heading %}<p class="deco-caps mb-4 text-xs text-primary">{{ heading }}</p>{% endif %}
|
||||
<div class="flex items-start gap-4">
|
||||
{% if showAvatar and post.author_avatar %}<div class="h-14 w-14 flex-shrink-0 overflow-hidden rounded-full bg-muted ring-1 ring-[hsl(var(--primary)/0.5)]">{% img post.author_avatar alt=post.author_name class="h-full w-full object-cover" %}</div>{% endif %}
|
||||
<div class="min-w-0">
|
||||
<h3 class="deco-caps text-base text-card-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{% if post.author_slug %}<a href="/author/{{ post.author_slug }}" class="transition-colors hover:text-primary">{{ post.author_name }}</a>{% else %}{{ post.author_name }}{% endif %}</h3>
|
||||
<span class="deco-rule mt-2 block w-10"></span>
|
||||
{% if post.author_bio %}<p class="mt-2 text-sm text-muted-foreground" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ post.author_bio }}</p>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
{% endif %}
|
||||
@ -1,24 +0,0 @@
|
||||
{# blog-hero (art-deco) — blog-index header + featured posts from the `posts` provider. #}
|
||||
<section data-block-override="art-deco:blog-hero" class="bg-background py-12 text-foreground md:py-16{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
<div class="mx-auto max-w-2xl text-center">
|
||||
{% if title %}<h1 class="deco-caps deco-underline text-4xl md:text-5xl text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ title }}</h1>{% endif %}
|
||||
{% if subtitle %}<p class="mt-4 text-lg text-muted-foreground" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ subtitle }}</p>{% endif %}
|
||||
</div>
|
||||
{% if posts %}
|
||||
<div class="mt-12 grid grid-cols-1 gap-8 md:grid-cols-3">
|
||||
{% for post in posts %}
|
||||
<article class="group flex flex-col{% if forloop.First %} md:col-span-3 md:flex-row md:items-stretch md:gap-8{% endif %}">
|
||||
{% if post.featured_image_url %}<a href="{{ post.url }}" class="deco-step mb-4 block overflow-hidden bg-muted{% if forloop.First %} md:mb-0 md:w-1/2{% endif %}">{% img post.featured_image_url alt=post.title class="aspect-video h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" %}</a>{% endif %}
|
||||
<div class="flex flex-col justify-center{% if forloop.First %} md:w-1/2{% endif %}">
|
||||
<span class="deco-rule mb-4 block w-12"></span>
|
||||
<h2 class="deco-caps {% if forloop.First %}text-2xl{% else %}text-lg{% endif %} leading-snug text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)"><a href="{{ post.url }}" class="transition-colors hover:text-primary">{{ post.title }}</a></h2>
|
||||
{% if showExcerpt and post.excerpt %}<p class="mt-3 text-sm text-muted-foreground" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ post.excerpt }}</p>{% endif %}
|
||||
<div class="mt-4 flex flex-wrap items-center gap-x-3 text-xs text-muted-foreground">{% if post.author_name %}<span class="deco-caps text-primary">{{ post.author_name }}</span>{% endif %}{% if post.published_at %}<span>{{ post.published_at|date:"M j, Y" }}</span>{% endif %}</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
@ -1,15 +0,0 @@
|
||||
{# breadcrumbs (art-deco) — 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" %}
|
||||
<nav aria-label="Breadcrumb" data-block-override="art-deco:breadcrumbs" class="py-3{% if class %} {{ class }}{% endif %}">
|
||||
<ol class="flex flex-wrap items-center gap-1 text-xs">
|
||||
{% if showHome %}<li class="flex items-center"><a href="/" class="deco-caps text-muted-foreground transition-colors hover:text-primary">{{ homeLabel|default:"Home" }}</a></li>{% endif %}
|
||||
{% for item in breadcrumbs %}
|
||||
<li class="flex items-center">
|
||||
{% if showHome or not forloop.First %}{% if arrows %}<svg class="mx-2 h-3.5 w-3.5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>{% else %}<span class="mx-2 text-primary">{{ separator|default:"/" }}</span>{% endif %}{% endif %}
|
||||
{% if item.is_current %}{% if showCurrent %}<span class="deco-caps text-foreground" aria-current="page">{{ item.label }}</span>{% endif %}{% else %}<a href="{{ item.url }}" class="deco-caps text-muted-foreground transition-colors hover:text-primary">{{ item.label }}</a>{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</nav>
|
||||
@ -1,10 +1 @@
|
||||
{# button override — gold-ringed lacquer pill. Fields (new builtin contract, per OVERRIDE-CONTRACT §4): link, style, label, size, icon, iconPosition, newTab, align. #}
|
||||
{% with align=align|default:"left" %}
|
||||
<div data-block-override="art-deco:button" class="bn-button flex {% if align == "center" %}justify-center{% elif align == "right" %}justify-end{% else %}justify-start{% endif %}{% if class %} {{ class }}{% endif %}">
|
||||
{% if style == "ghost" or style == "link" or style == "secondary" %}
|
||||
<a href="{{ link|default:'#' }}"{% if newTab %} target="_blank" rel="noopener"{% endif %} class="deco-link inline-flex items-center gap-2 text-sm">{% if icon and iconPosition != "right" %}::{{ icon }}:sm::{% endif %}{{ label|default:"Learn more" }}{% if icon and iconPosition == "right" %}::{{ icon }}:sm::{% endif %}</a>
|
||||
{% else %}
|
||||
<a href="{{ link|default:'#' }}"{% if newTab %} target="_blank" rel="noopener"{% endif %} class="deco-pill inline-flex items-center gap-2">{% if icon and iconPosition != "right" %}::{{ icon }}:sm::{% endif %}{{ label|default:"Learn more" }}{% if icon and iconPosition == "right" %}::{{ icon }}:sm::{% endif %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% if label %}{% if url %}<a data-block-override="art-deco:button" href="{{ url }}" class="deco-pill inline-block" style="{% if variant == "secondary" %}background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border-color: hsl(var(--primary));{% elif variant == "ghost" %}background-color: transparent; color: hsl(var(--foreground)); border-color: hsl(var(--primary));{% else %}background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-color: hsl(var(--primary));{% endif %}">{{ label }}</a>{% else %}<button type="button" data-block-override="art-deco:button" class="deco-pill" style="{% if variant == "secondary" %}background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); border-color: hsl(var(--primary));{% elif variant == "ghost" %}background-color: transparent; color: hsl(var(--foreground)); border-color: hsl(var(--primary));{% else %}background-color: hsl(var(--foreground)); color: hsl(var(--background)); border-color: hsl(var(--primary));{% endif %}">{{ label }}</button>{% endif %}{% endif %}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
{# card override — angular gold Deco panel. Fields mirror builtin: layout, link, media, title, text, linkLabel. Media via {% img %}. #}
|
||||
{% with layout=layout|default:"vertical" %}
|
||||
<article data-block-override="art-deco:card" class="bn-card deco-frame overflow-hidden bg-card text-card-foreground transition-shadow hover:deco-foil {% if layout == "horizontal" %}flex flex-col sm:flex-row{% endif %}{% if class %} {{ class }}{% endif %}">{% if link %}<a href="{{ link }}" class="contents">{% endif %}{% if media %}<div class="overflow-hidden bg-muted {% if layout == "horizontal" %}sm:w-2/5 sm:shrink-0{% endif %}">{% if layout == "horizontal" %}{% img media alt=title|default:"" class="h-full w-full object-cover" %}{% else %}{% img media alt=title|default:"" class="aspect-video h-full w-full object-cover" %}{% endif %}</div>{% endif %}<div class="flex flex-col gap-2 p-5 md:p-6 {% if layout == "horizontal" %}justify-center{% endif %}">{% if title %}<h3 class="deco-caps text-lg" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ title }}</h3>{% endif %}{% if text %}<div class="text-sm leading-relaxed" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ text|safe }}</div>{% endif %}{% if linkLabel and link %}<span class="mt-2 inline-flex items-center gap-1 text-sm deco-link">{{ linkLabel }}::lucide:arrow-right:sm::</span>{% endif %}</div>{% if link %}</a>{% endif %}</article>
|
||||
{% endwith %}
|
||||
@ -1,18 +0,0 @@
|
||||
{# category-list (art-deco) — from the `categories` provider. list or pills. #}
|
||||
{% set pills = style == "pills" %}
|
||||
<section data-block-override="art-deco:category-list" class="bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
{% if heading %}<h2 class="deco-caps mb-5 text-xs text-primary">{{ heading }}</h2>{% endif %}
|
||||
{% if pills %}
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% for cat in categories %}
|
||||
<a href="{{ cat.url }}" class="deco-caps inline-flex items-center gap-1.5 rounded-none border border-[hsl(var(--primary)/0.35)] bg-card px-4 py-1.5 text-xs text-card-foreground transition-colors hover:border-primary hover:text-primary">{{ cat.name }}{% if showCount %}<span class="text-xs text-muted-foreground">{{ cat.post_count }}</span>{% endif %}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<ul class="space-y-1">
|
||||
{% for cat in categories %}
|
||||
<li><a href="{{ cat.url }}" class="deco-rule flex items-center justify-between px-3 py-2.5 text-sm text-muted-foreground transition-colors hover:text-primary"><span class="deco-caps">{{ cat.name }}</span>{% if showCount %}<span class="rounded-none border border-[hsl(var(--primary)/0.35)] px-2 py-0.5 text-xs text-muted-foreground">{{ cat.post_count }}</span>{% endif %}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</section>
|
||||
@ -1,17 +0,0 @@
|
||||
<section data-block-override="art-deco:contact-card" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-4xl px-4 text-center">
|
||||
{% if heading %}<h2 class="deco-caps deco-underline text-3xl md:text-4xl text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if description %}<p class="mt-4 mx-auto max-w-2xl text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ description }}</p>{% endif %}
|
||||
<div class="mt-12 grid grid-cols-1 gap-6 text-left {% if columns == 3 %}sm:grid-cols-2 lg:grid-cols-3{% elif columns == 1 %}{% else %}sm:grid-cols-2{% endif %}">
|
||||
{% for channel in channels %}
|
||||
<div class="deco-frame deco-foil flex items-start gap-4 rounded-none bg-card p-6 text-card-foreground">
|
||||
{% if channel.icon %}<span class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-none border border-[hsl(var(--primary)/0.45)] bg-primary/10 text-primary"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ channel.icon|split:":"|first }}.svg#{{ channel.icon|split:":"|last }}"></use></svg></span>{% endif %}
|
||||
<div class="min-w-0">
|
||||
{% if channel.label %}<div class="deco-caps text-xs tracking-[0.16em] text-muted-foreground">{{ channel.label }}</div>{% endif %}
|
||||
{% if channel.value %}<div class="mt-1 break-words text-lg text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{% if channel.link %}<a href="{{ channel.link }}" class="deco-link transition-colors hover:text-primary">{{ channel.value }}</a>{% else %}{{ channel.value }}{% endif %}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,43 +0,0 @@
|
||||
{# contact-form override — reservations enquiry. ALL form wiring preserved verbatim from builtin: bid, {% form %} action/hx attrs, honeypot, field loop, form.submitted/errors, submit target. Only inputs restyled to Art Deco. #}
|
||||
{% with bid=_block_id|default:context.blockId %}
|
||||
<section data-block-override="art-deco:contact-form" id="contact-form-{{ bid }}" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-2xl px-4">
|
||||
{% if form.submitted %}
|
||||
<div class="deco-frame bg-card p-10 text-center">
|
||||
<div class="mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full text-primary" style="box-shadow:inset 0 0 0 1px hsl(var(--primary));">::lucide:check:lg::</div>
|
||||
<p class="text-lg italic" style="font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ form.message|default:successMessage|default:"Thank you. Your table request has been received." }}</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center">
|
||||
{% if heading %}<h2 class="deco-caps text-3xl md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ heading }}</h2>{% endif %}
|
||||
{% if description %}<p class="mt-3 text-lg italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ description }}</p>{% endif %}
|
||||
<div class="mx-auto mt-5 mb-2 h-6 w-40 deco-sunburst" aria-hidden="true"></div>
|
||||
</div>
|
||||
{% if form.errors._form %}<div class="mt-6 border border-destructive/50 bg-destructive/10 px-4 py-3 text-sm text-destructive">{{ form.errors._form }}</div>{% 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 %}
|
||||
<div class="{% if field.width == "half" %}sm:col-span-1{% else %}sm:col-span-2{% endif %}">
|
||||
{% if field.label %}<label for="cf-{{ bid }}-{{ field.name }}" class="deco-caps mb-1.5 block text-xs" style="color:hsl(var(--primary));">{{ field.label }}{% if field.required %} <span class="text-destructive">*</span>{% endif %}</label>{% endif %}
|
||||
{% if field.type == "textarea" %}
|
||||
<textarea id="cf-{{ bid }}-{{ field.name }}" name="{{ field.name }}" rows="5"{% if field.required %} required{% endif %}{% if field.placeholder %} placeholder="{{ field.placeholder }}"{% endif %} class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring"></textarea>
|
||||
{% elif field.type == "select" %}
|
||||
<select id="cf-{{ bid }}-{{ field.name }}" name="{{ field.name }}"{% if field.required %} required{% endif %} class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring">
|
||||
{% if field.placeholder %}<option value="">{{ field.placeholder }}</option>{% endif %}
|
||||
{% for opt in field.options %}<option value="{{ opt.value }}">{{ opt.label|default:opt.value }}</option>{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input id="cf-{{ bid }}-{{ field.name }}" name="{{ field.name }}" type="{{ field.type|default:"text" }}"{% if field.required %} required{% endif %}{% if field.placeholder %} placeholder="{{ field.placeholder }}"{% endif %} class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="hidden" aria-hidden="true"><label>Leave this field empty<input type="text" name="website" tabindex="-1" autocomplete="off"></label></div>
|
||||
<div class="sm:col-span-2 flex justify-center">
|
||||
<button type="submit" class="deco-pill inline-flex items-center justify-center">{{ submitLabel|default:"Request a table" }}</button>
|
||||
</div>
|
||||
{% endform %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endwith %}
|
||||
@ -1,48 +0,0 @@
|
||||
<section data-block-override="art-deco:countdown" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-4xl px-4 text-center">
|
||||
{% if heading %}<h2 class="deco-caps text-3xl tracking-tight md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<div class="mt-10" data-countdown>
|
||||
<div class="flex items-start justify-center gap-3 sm:gap-6" data-countdown-timer data-target="{{ target }}" role="timer" aria-label="Time remaining">
|
||||
<div class="flex flex-col items-center {% if variant == "boxes" %}deco-frame min-w-[4.5rem] bg-card px-3 py-4 text-card-foreground{% endif %}"><span class="text-4xl font-bold tabular-nums text-primary sm:text-5xl" style="font-family:var(--font-mono)" data-unit="days">--</span><span class="deco-caps mt-1 text-xs text-muted-foreground">{{ labelDays|default:"Days" }}</span></div>
|
||||
<div class="flex flex-col items-center {% if variant == "boxes" %}deco-frame min-w-[4.5rem] bg-card px-3 py-4 text-card-foreground{% endif %}"><span class="text-4xl font-bold tabular-nums text-primary sm:text-5xl" style="font-family:var(--font-mono)" data-unit="hours">--</span><span class="deco-caps mt-1 text-xs text-muted-foreground">{{ labelHours|default:"Hours" }}</span></div>
|
||||
<div class="flex flex-col items-center {% if variant == "boxes" %}deco-frame min-w-[4.5rem] bg-card px-3 py-4 text-card-foreground{% endif %}"><span class="text-4xl font-bold tabular-nums text-primary sm:text-5xl" style="font-family:var(--font-mono)" data-unit="minutes">--</span><span class="deco-caps mt-1 text-xs text-muted-foreground">{{ labelMinutes|default:"Minutes" }}</span></div>
|
||||
<div class="flex flex-col items-center {% if variant == "boxes" %}deco-frame min-w-[4.5rem] bg-card px-3 py-4 text-card-foreground{% endif %}"><span class="text-4xl font-bold tabular-nums text-primary sm:text-5xl" style="font-family:var(--font-mono)" data-unit="seconds">--</span><span class="deco-caps mt-1 text-xs text-muted-foreground">{{ labelSeconds|default:"Seconds" }}</span></div>
|
||||
</div>
|
||||
<div class="mt-8 hidden" data-countdown-expired>
|
||||
<p class="deco-caps text-xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ expiredMessage|default:"This has started." }}</p>
|
||||
{% if expiredUrl and expiredLabel %}<a href="{{ expiredUrl }}" class="deco-pill mt-4 inline-flex items-center gap-2">{{ expiredLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<noscript><p class="mt-6 text-muted-foreground">Counting down to <time datetime="{{ target }}">{{ target }}</time>.</p></noscript>
|
||||
</div>
|
||||
</section>
|
||||
<script>
|
||||
(function(){
|
||||
var timers = document.querySelectorAll('[data-countdown-timer]');
|
||||
timers.forEach(function(el){
|
||||
var target = new Date(el.getAttribute('data-target')).getTime();
|
||||
if (isNaN(target)) return;
|
||||
var wrap = el.closest('[data-countdown]');
|
||||
var expired = wrap ? wrap.querySelector('[data-countdown-expired]') : null;
|
||||
function pad(n){ return (n < 10 ? '0' : '') + n; }
|
||||
function set(unit, value){ var node = el.querySelector('[data-unit="' + unit + '"]'); if (node) node.textContent = value; }
|
||||
var interval;
|
||||
function tick(){
|
||||
var diff = target - Date.now();
|
||||
if (diff <= 0){
|
||||
el.style.display = 'none';
|
||||
if (expired) expired.classList.remove('hidden');
|
||||
if (interval) clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
set('days', Math.floor(diff / 86400000));
|
||||
set('hours', pad(Math.floor(diff % 86400000 / 3600000)));
|
||||
set('minutes', pad(Math.floor(diff % 3600000 / 60000)));
|
||||
set('seconds', pad(Math.floor(diff % 60000 / 1000)));
|
||||
}
|
||||
tick();
|
||||
interval = setInterval(tick, 1000);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@ -1,14 +0,0 @@
|
||||
<section data-block-override="art-deco:cta" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
<div class="{% if background == "band" %}deco-frame deco-grain bg-primary px-6 py-14 text-center text-primary-foreground md:px-12{% elif background == "card" %}deco-frame bg-card px-6 py-14 text-center text-card-foreground md:px-12{% else %}deco-frame flex flex-col items-center gap-8 bg-muted px-6 py-12 text-foreground md:flex-row md:justify-between md:px-12 md:text-left{% endif %}">
|
||||
<div class="{% if background != "split" %}mx-auto max-w-2xl{% endif %}">
|
||||
{% if heading %}<h2 class="deco-caps text-3xl tracking-tight md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if text %}<p class="mt-3 text-lg {% if background == "band" %}text-primary-foreground/80{% else %}text-muted-foreground{% endif %}" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ text }}</p>{% endif %}
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center justify-center gap-3 {% if background != "split" %}mt-8{% else %}shrink-0{% endif %}">
|
||||
{% if primaryUrl and primaryLabel %}<a href="{{ primaryUrl }}" class="deco-pill inline-flex items-center gap-2">{{ primaryLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
|
||||
{% if secondaryUrl and secondaryLabel %}<a href="{{ secondaryUrl }}" class="deco-link inline-flex items-center">{{ secondaryLabel }}</a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,13 +0,0 @@
|
||||
{# divider override — folds in the old divider_fan: gold geometric rules. Fields mirror builtin: variant (line|ornament|spacer-rule), weight, width, icon. ornament renders a sunburst fan crest; spacer-rule a short centred gold rule; line a hairline gold rule. #}
|
||||
{% with variant=variant|default:"line" weight=weight|default:"thin" width=width|default:"full" %}
|
||||
{% if variant == "ornament" %}
|
||||
<div data-block-override="art-deco:divider" class="bn-divider mx-auto my-10 flex flex-col items-center gap-2 {% if width == "narrow" %}max-w-[200px]{% elif width == "wide" %}max-w-3xl{% else %}w-full{% endif %}{% if class %} {{ class }}{% endif %}" role="separator">
|
||||
<div class="h-8 w-40 deco-sunburst" aria-hidden="true"></div>
|
||||
<div class="flex w-full items-center gap-4"><span class="deco-rule flex-1"></span><span style="color:hsl(var(--primary));">::{{ icon|default:"lucide:diamond" }}:sm::</span><span class="deco-rule flex-1"></span></div>
|
||||
</div>
|
||||
{% elif variant == "spacer-rule" %}
|
||||
<div data-block-override="art-deco:divider" class="bn-divider mx-auto py-10 flex justify-center {% if width == "narrow" %}max-w-[200px]{% elif width == "wide" %}max-w-3xl{% else %}w-full{% endif %}{% if class %} {{ class }}{% endif %}" role="separator"><span class="{% if weight == "thick" %}deco-rule-thick{% else %}deco-rule{% endif %} w-16"></span></div>
|
||||
{% else %}
|
||||
<div data-block-override="art-deco:divider" class="bn-divider mx-auto my-8 flex justify-center {% if width == "narrow" %}max-w-[200px]{% elif width == "wide" %}max-w-3xl{% else %}w-full{% endif %}{% if class %} {{ class }}{% endif %}" role="separator"><span class="{% if weight == "thick" %}deco-rule-thick{% else %}deco-rule{% endif %} w-full"></span></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@ -1,40 +0,0 @@
|
||||
<section data-block-override="art-deco:event-list" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4 text-center">
|
||||
{% if heading %}<h2 class="deco-caps deco-underline text-3xl md:text-4xl text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mt-4 mx-auto max-w-2xl text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
{% if layout == "cards" %}
|
||||
<div class="mt-12 grid grid-cols-1 gap-8 text-left sm:grid-cols-2 lg:grid-cols-3">
|
||||
{% for event in events %}{% if not (hidePast and event.past) %}
|
||||
<article class="deco-frame deco-foil flex flex-col overflow-hidden rounded-none bg-card text-card-foreground{% if event.past %} opacity-60{% endif %}">
|
||||
{% if event.media %}<div class="deco-step aspect-video overflow-hidden bg-muted">{% img event.media alt=event.title class="h-full w-full object-cover" %}</div>{% endif %}
|
||||
<div class="flex flex-1 flex-col gap-2 p-6">
|
||||
<div class="deco-caps text-xs tracking-[0.18em] text-primary"><time{% if event.datetime %} datetime="{{ event.datetime }}"{% endif %}>{{ event.start }}{% if event.end %} – {{ event.end }}{% endif %}</time>{% if event.timezone %} <span class="text-muted-foreground">{{ event.timezone }}</span>{% endif %}</div>
|
||||
<h3 class="text-xl text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ event.title }}</h3>
|
||||
{% if event.venue %}<p class="deco-caps text-xs tracking-[0.14em] text-muted-foreground">{{ event.venue }}</p>{% endif %}
|
||||
{% if event.description %}<p class="text-sm text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ event.description }}</p>{% endif %}
|
||||
{% if event.link %}<a href="{{ event.link }}" class="deco-link mt-auto inline-flex items-center gap-2 pt-3 text-sm text-primary">{{ event.linkLabel|default:"Details" }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
|
||||
</div>
|
||||
</article>
|
||||
{% endif %}{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<ul class="mt-12 divide-y divide-[hsl(var(--primary)/0.35)] border-y-2 border-[hsl(var(--primary)/0.35)] text-left">
|
||||
{% for event in events %}{% if not (hidePast and event.past) %}
|
||||
<li class="flex flex-col gap-3 py-6 sm:flex-row sm:items-center sm:gap-8{% if event.past %} opacity-60{% endif %}">
|
||||
<div class="shrink-0 sm:w-52">
|
||||
<div class="deco-caps text-sm tracking-[0.16em] text-primary"><time{% if event.datetime %} datetime="{{ event.datetime }}"{% endif %}>{{ event.start }}</time></div>
|
||||
{% if event.end %}<div class="text-xs text-muted-foreground">to {{ event.end }}</div>{% endif %}
|
||||
{% if event.timezone %}<div class="text-xs text-muted-foreground">{{ event.timezone }}</div>{% endif %}
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="text-lg text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ event.title }}</h3>
|
||||
{% if event.venue %}<p class="deco-caps text-xs tracking-[0.14em] text-muted-foreground">{{ event.venue }}</p>{% endif %}
|
||||
{% if event.description %}<p class="mt-1 text-sm text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ event.description }}</p>{% endif %}
|
||||
</div>
|
||||
{% if event.link %}<a href="{{ event.link }}" class="deco-pill inline-flex shrink-0 items-center gap-2">{{ event.linkLabel|default:"Details" }}</a>{% endif %}
|
||||
</li>
|
||||
{% endif %}{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
@ -1,17 +0,0 @@
|
||||
<section data-block-override="art-deco:faq" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-3xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-center text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<div class="mt-10 divide-y divide-[hsl(var(--primary)/0.25)] border-y border-[hsl(var(--primary)/0.4)]">
|
||||
{% for item in items %}
|
||||
<details class="group py-2"{% if variant == "open-list" %} open{% endif %}>
|
||||
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 py-3 text-lg font-medium marker:content-none [&::-webkit-details-marker]:hidden" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">
|
||||
<span>{{ item.question }}</span>
|
||||
<svg class="h-5 w-5 shrink-0 text-primary transition-transform duration-200 group-open:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg>
|
||||
</summary>
|
||||
<div class="pb-4 text-muted-foreground [&_a]:text-primary [&_a]:underline" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ item.answer|safe }}</div>
|
||||
</details>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,17 +0,0 @@
|
||||
<section data-block-override="art-deco:feature-grid" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if eyebrow %}<div class="mb-3 flex items-center justify-center gap-4"><span class="deco-rule w-12"></span><p class="deco-caps text-xs text-primary">{{ eyebrow }}</p><span class="deco-rule w-12"></span></div>{% endif %}
|
||||
{% if heading %}<h2 class="deco-caps mt-2 text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-center text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<div class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% elif columns == 4 %}lg:grid-cols-4{% else %}lg:grid-cols-3{% endif %}">
|
||||
{% for item in items %}
|
||||
<div class="{% if layout == "card" %}deco-frame bg-card p-6 text-card-foreground deco-foil transition-shadow{% elif layout == "centered" %}text-center{% endif %}">
|
||||
{% if item.icon %}<div class="mb-4 inline-flex h-11 w-11 items-center justify-center border border-[hsl(var(--primary)/0.35)] bg-primary/10 text-primary{% if layout == "centered" %} mx-auto{% endif %}"><svg class="h-6 w-6" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg></div>{% endif %}
|
||||
<h3 class="deco-caps text-lg text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{% if item.linkUrl %}<a href="{{ item.linkUrl }}" class="transition-colors hover:text-primary">{{ item.title }}</a>{% else %}{{ item.title }}{% endif %}</h3>
|
||||
{% if item.text %}<p class="mt-2 text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ item.text }}</p>{% endif %}
|
||||
{% if item.linkUrl and item.linkLabel %}<a href="{{ item.linkUrl }}" class="deco-link mt-3 inline-flex items-center gap-1 text-sm">{{ item.linkLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,24 +0,0 @@
|
||||
{# featured-posts (art-deco) — grid of cards from the `posts` provider #}
|
||||
{# (params: limit, featured=true). Card: image, title, excerpt, meta. #}
|
||||
<section data-block-override="art-deco:featured-posts" class="py-12 md:py-16 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps deco-underline mb-10 text-center text-2xl md:text-3xl text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
<div class="grid grid-cols-1 gap-8 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% elif columns == 4 %}lg:grid-cols-4{% else %}lg:grid-cols-3{% endif %}">
|
||||
{% for post in posts %}
|
||||
<article class="deco-frame group flex flex-col overflow-hidden bg-card text-card-foreground transition-shadow">
|
||||
{% if showFeaturedImage and post.featured_image_url %}<a href="{{ post.url }}" class="block aspect-video overflow-hidden bg-muted">{% img post.featured_image_url alt=post.title class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" %}</a>{% endif %}
|
||||
<div class="flex flex-1 flex-col p-6 text-center">
|
||||
<h3 class="deco-caps text-lg leading-snug text-card-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)"><a href="{{ post.url }}" class="transition-colors hover:text-primary">{{ post.title }}</a></h3>
|
||||
<span class="deco-rule mx-auto mt-3 block w-10"></span>
|
||||
{% if showExcerpt and post.excerpt %}<p class="mt-3 flex-1 text-sm text-muted-foreground" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ post.excerpt }}</p>{% endif %}
|
||||
<div class="mt-4 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs text-muted-foreground">
|
||||
{% if showAuthor and post.author_name %}<span class="deco-caps text-primary">{{ post.author_name }}</span>{% endif %}
|
||||
{% if showDate and post.published_at %}<span>{{ post.published_at|date:"M j, Y" }}</span>{% endif %}
|
||||
{% if post.reading_time %}<span>{{ post.reading_time }} min read</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,40 +0,0 @@
|
||||
{# footer override — folds in the old footer block: centred gilded footer with gold rule, address, reservations, social. Structure/fields/signup_form preserved from builtin; reskinned to Art Deco. #}
|
||||
{% set fl = layout %}
|
||||
{% if not fl %}{% if template == "centered" %}{% set fl = "centered" %}{% else %}{% set fl = "columns" %}{% endif %}{% endif %}
|
||||
{% set fbg = backgroundColor|default:"bg-foreground text-background" %}
|
||||
{% macro sociallinks(cls) %}{% if social_items %}<div class="flex items-center gap-4 {{ cls }}">{% for s in social_items %}<a href="{{ s.url }}" target="_blank" rel="noopener" title="{{ s.label }}" class="text-background/70 hover:text-primary transition-colors"><span class="sr-only">{{ s.label }}</span>{% if s.icon %}::{{ s.icon }}::{% else %}{{ s.label }}{% endif %}</a>{% endfor %}</div>{% endif %}{% endmacro %}
|
||||
{% macro newsletter() %}{% if showNewsletter %}<div class="max-w-sm"><h3 class="deco-caps text-sm text-primary">{{ newsletterTitle|default:"Join the guest list" }}</h3>{% if newsletterDescription %}<p class="mt-1 text-sm italic text-background/70">{{ newsletterDescription }}</p>{% endif %}<div class="mt-3">{% signup_form list=newsletterListSlug|default:"main" source="footer" submit=newsletterButtonText|default:"Subscribe" %}</div></div>{% endif %}{% endmacro %}
|
||||
{% macro legalbar() %}<div class="mt-10 pt-6 border-t border-[hsl(var(--primary)/0.4)] flex flex-col sm:flex-row items-center justify-between gap-3 text-sm text-background/60"><p>{% if copyright %}© {{ copyright }}{% else %}© {{ companyName }}{% endif %}</p>{% if legal_items %}<nav class="flex flex-wrap items-center gap-x-4 gap-y-1">{% for l in legal_items %}<a href="{{ l.url|default:'#' }}"{% if l.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="hover:text-primary transition-colors">{{ l.label }}</a>{% endfor %}</nav>{% endif %}</div>{% endmacro %}
|
||||
<footer data-block-override="art-deco:footer" class="w-full border-t-2 border-[hsl(var(--primary))] {{ fbg }} {{ class }}">
|
||||
<div class="{% if fullWidth %}w-full px-4 sm:px-6 lg:px-8{% else %}max-w-7xl mx-auto px-4 sm:px-6 lg:px-8{% endif %} py-16">
|
||||
{% if fl == "minimal" %}
|
||||
<div class="flex flex-col sm:flex-row items-center justify-between gap-6">
|
||||
<div class="flex items-center gap-3">{% if logo %}<img src="{{ logo }}" alt="{{ companyName }}" class="h-8 w-auto"/>{% elif companyName %}<span class="deco-caps text-lg" style="font-family:var(--font-heading, 'Cinzel', Georgia, serif);">{{ companyName }}</span>{% endif %}{% if tagline %}<span class="text-sm italic text-background/70 hidden sm:inline">{{ tagline }}</span>{% endif %}</div>
|
||||
{{ sociallinks("") }}
|
||||
</div>
|
||||
{{ legalbar() }}
|
||||
{% elif fl == "centered" %}
|
||||
<div class="flex flex-col items-center text-center gap-5">
|
||||
{% if logo %}<img src="{{ logo }}" alt="{{ companyName }}" class="h-10 w-auto"/>{% elif companyName %}<span class="deco-caps text-2xl text-primary" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);">{{ companyName }}</span>{% endif %}
|
||||
<div class="h-6 w-40 deco-sunburst" aria-hidden="true"></div>
|
||||
{% if tagline %}<p class="max-w-md text-sm italic text-background/70">{{ tagline }}</p>{% endif %}
|
||||
{% if columns %}<nav class="flex flex-wrap items-center justify-center gap-x-6 gap-y-2">{% for col in columns %}{% for item in col.items %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="deco-caps text-xs text-background/80 hover:text-primary transition-colors">{{ item.label }}</a>{% endfor %}{% endfor %}</nav>{% endif %}
|
||||
{{ newsletter() }}
|
||||
{{ sociallinks("justify-center") }}
|
||||
</div>
|
||||
{{ legalbar() }}
|
||||
{% else %}
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8">
|
||||
<div class="col-span-2 lg:col-span-2">
|
||||
{% if logo %}<img src="{{ logo }}" alt="{{ companyName }}" class="h-9 w-auto"/>{% elif companyName %}<span class="deco-caps text-xl text-primary" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);">{{ companyName }}</span>{% endif %}
|
||||
{% if tagline %}<p class="mt-3 max-w-xs text-sm italic text-background/70">{{ tagline }}</p>{% endif %}
|
||||
{% if address or email or phone %}<address class="mt-4 not-italic text-sm text-background/70 space-y-1">{% if address %}<div>{{ address }}</div>{% endif %}{% if email %}<div><a href="mailto:{{ email }}" class="hover:text-primary transition-colors">{{ email }}</a></div>{% endif %}{% if phone %}<div><a href="tel:{{ phone }}" class="hover:text-primary transition-colors">{{ phone }}</a></div>{% endif %}</address>{% endif %}
|
||||
{{ sociallinks("mt-5") }}
|
||||
</div>
|
||||
{% for col in columns %}<div><h3 class="deco-caps text-xs text-primary">{{ col.header }}</h3><ul class="mt-3 space-y-2">{% for item in col.items %}<li><a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="text-sm text-background/70 hover:text-primary transition-colors">{{ item.label }}</a></li>{% endfor %}</ul></div>{% endfor %}
|
||||
{% if showNewsletter %}<div class="col-span-2 lg:col-span-1">{{ newsletter() }}</div>{% endif %}
|
||||
</div>
|
||||
{{ legalbar() }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</footer>
|
||||
@ -1,52 +0,0 @@
|
||||
{# gallery override — folds in the old gallery_fan: symmetric gold-framed grid. Fields + lightbox JS mirror builtin verbatim: layout, gap, columns, lightbox, images[].src/.alt/.caption. #}
|
||||
{% with layout=layout|default:"grid" gap=gap|default:"md" cols=columns|default:3 %}<div data-block-override="art-deco:gallery" class="bn-gallery my-8{% if class %} {{ class }}{% endif %}" data-bn-gallery data-lightbox="{% if lightbox %}true{% else %}false{% endif %}"><div class="{% if layout == "carousel" %}flex snap-x snap-mandatory overflow-x-auto pb-2 {% if gap == "sm" %}gap-2{% elif gap == "lg" %}gap-6{% else %}gap-4{% endif %}{% elif layout == "masonry" %}columns-2 {% if cols == 4 %}md:columns-4{% elif cols == 2 %}md:columns-2{% else %}md:columns-3{% endif %} {% if gap == "sm" %}gap-2{% elif gap == "lg" %}gap-6{% else %}gap-4{% endif %}{% else %}grid grid-cols-2 {% if cols == 4 %}md:grid-cols-4{% elif cols == 2 %}md:grid-cols-2{% else %}md:grid-cols-3{% endif %} {% if gap == "sm" %}gap-2{% elif gap == "lg" %}gap-6{% else %}gap-4{% endif %}{% endif %}">{% for image in images %}<a href="{{ image.src|mediaURL }}" data-bn-gallery-item data-caption="{{ image.caption|default:"" }}" class="deco-step group relative block overflow-hidden bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 {% if layout == "carousel" %}w-64 shrink-0 snap-start sm:w-80{% elif layout == "masonry" %}mb-4 w-full break-inside-avoid{% endif %}">{% if layout == "grid" %}{% img image.src alt=image.alt|default:"" class="aspect-square w-full object-cover" %}{% else %}{% img image.src alt=image.alt|default:"" class="h-auto w-full" %}{% endif %}{% if image.caption %}<span class="sr-only">{{ image.caption }}</span>{% endif %}</a>{% endfor %}</div></div>{% if lightbox %}<script>
|
||||
(function(){
|
||||
if(window.__bnLightbox)return;window.__bnLightbox=true;
|
||||
var reduce=window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
var ov,imgEl,capEl,items=[],idx=0,lastFocus=null;
|
||||
function build(){
|
||||
ov=document.createElement('div');
|
||||
ov.setAttribute('role','dialog');ov.setAttribute('aria-modal','true');ov.setAttribute('aria-label','Image viewer');ov.tabIndex=-1;
|
||||
ov.style.cssText='position:fixed;inset:0;z-index:9999;display:none;align-items:center;justify-content:center;background:rgba(0,0,0,0.9);padding:2rem;';
|
||||
var btn='position:absolute;width:2.75rem;height:2.75rem;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;border:none;background:hsl(var(--background));color:hsl(var(--foreground));cursor:pointer;';
|
||||
ov.innerHTML=
|
||||
'<button type="button" data-lb-close aria-label="Close" style="'+btn+'top:1rem;right:1rem;"><svg style="width:1.25rem;height:1.25rem" aria-hidden="true"><use href="/icons/lucide.svg#x"/></svg></button>'+
|
||||
'<button type="button" data-lb-prev aria-label="Previous image" style="'+btn+'left:1rem;top:50%;transform:translateY(-50%);"><svg style="width:1.25rem;height:1.25rem" aria-hidden="true"><use href="/icons/lucide.svg#chevron-left"/></svg></button>'+
|
||||
'<figure style="margin:0;max-width:92vw;max-height:92vh;display:flex;flex-direction:column;align-items:center;gap:0.75rem;"><img data-lb-img alt="" style="max-width:92vw;max-height:82vh;object-fit:contain;border-radius:0.5rem;'+(reduce?'':'transition:opacity .2s ease;')+'"><figcaption data-lb-cap style="color:hsl(var(--background));opacity:.85;font-size:.875rem;text-align:center;max-width:60ch;"></figcaption></figure>'+
|
||||
'<button type="button" data-lb-next aria-label="Next image" style="'+btn+'right:1rem;top:50%;transform:translateY(-50%);"><svg style="width:1.25rem;height:1.25rem" aria-hidden="true"><use href="/icons/lucide.svg#chevron-right"/></svg></button>';
|
||||
document.body.appendChild(ov);
|
||||
imgEl=ov.querySelector('[data-lb-img]');capEl=ov.querySelector('[data-lb-cap]');
|
||||
ov.addEventListener('click',function(e){if(e.target===ov||e.target.closest('[data-lb-close]'))close();});
|
||||
ov.querySelector('[data-lb-prev]').addEventListener('click',function(e){e.stopPropagation();show(idx-1);});
|
||||
ov.querySelector('[data-lb-next]').addEventListener('click',function(e){e.stopPropagation();show(idx+1);});
|
||||
}
|
||||
function show(i){
|
||||
if(!items.length)return;
|
||||
idx=(i+items.length)%items.length;
|
||||
var a=items[idx];var im=a.querySelector('img');
|
||||
imgEl.src=(im&&(im.currentSrc||im.src))||a.getAttribute('href');
|
||||
imgEl.alt=im?im.alt:'';
|
||||
var cap=a.getAttribute('data-caption')||'';capEl.textContent=cap;capEl.style.display=cap?'block':'none';
|
||||
}
|
||||
function open(g,link){
|
||||
if(!ov)build();
|
||||
items=Array.prototype.slice.call(g.querySelectorAll('[data-bn-gallery-item]'));
|
||||
lastFocus=document.activeElement;ov.style.display='flex';
|
||||
var multi=items.length>1;
|
||||
ov.querySelector('[data-lb-prev]').style.display=multi?'inline-flex':'none';
|
||||
ov.querySelector('[data-lb-next]').style.display=multi?'inline-flex':'none';
|
||||
show(items.indexOf(link));ov.focus();
|
||||
}
|
||||
function close(){if(ov)ov.style.display='none';if(lastFocus&&lastFocus.focus)lastFocus.focus();}
|
||||
document.addEventListener('click',function(e){
|
||||
var link=e.target.closest('[data-bn-gallery][data-lightbox="true"] [data-bn-gallery-item]');
|
||||
if(!link)return;e.preventDefault();open(link.closest('[data-bn-gallery]'),link);
|
||||
});
|
||||
document.addEventListener('keydown',function(e){
|
||||
if(!ov||ov.style.display==='none')return;
|
||||
if(e.key==='Escape'){e.preventDefault();close();}
|
||||
else if(e.key==='ArrowLeft')show(idx-1);
|
||||
else if(e.key==='ArrowRight')show(idx+1);
|
||||
});
|
||||
})();
|
||||
</script>{% endif %}{% endwith %}
|
||||
@ -1,7 +1 @@
|
||||
{# heading override — gilded Cinzel display caps with a hairline gold underline. Fields: text, level, textClass (mirrors builtin). #}
|
||||
{% if level == 1 %}<h1 data-block-override="art-deco:heading" class="deco-caps deco-underline text-4xl md:text-5xl flex-1 {{ textClass }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ text }}</h1>
|
||||
{% elif level == 3 %}<h3 data-block-override="art-deco:heading" class="deco-caps deco-underline text-2xl md:text-3xl flex-1 {{ textClass }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ text }}</h3>
|
||||
{% elif level == 4 %}<h4 data-block-override="art-deco:heading" class="deco-caps deco-underline text-xl md:text-2xl flex-1 {{ textClass }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ text }}</h4>
|
||||
{% elif level == 5 %}<h5 data-block-override="art-deco:heading" class="deco-caps deco-underline text-lg md:text-xl flex-1 {{ textClass }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ text }}</h5>
|
||||
{% elif level == 6 %}<h6 data-block-override="art-deco:heading" class="deco-caps deco-underline text-base md:text-lg flex-1 {{ textClass }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ text }}</h6>
|
||||
{% else %}<h2 data-block-override="art-deco:heading" class="deco-caps deco-underline text-3xl md:text-4xl flex-1 {{ textClass }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ text }}</h2>{% endif %}
|
||||
{% if level|integer == 1 %}<h1 data-block-override="art-deco:heading" class="deco-caps deco-underline text-4xl md:text-5xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h1>{% elif level|integer == 3 %}<h3 data-block-override="art-deco:heading" class="deco-caps deco-underline text-2xl md:text-3xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h3>{% elif level|integer == 4 %}<h4 data-block-override="art-deco:heading" class="deco-caps deco-underline text-xl md:text-2xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h4>{% elif level|integer == 5 %}<h5 data-block-override="art-deco:heading" class="deco-caps deco-underline text-lg md:text-xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h5>{% elif level|integer == 6 %}<h6 data-block-override="art-deco:heading" class="deco-caps deco-underline text-base md:text-lg {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h6>{% else %}<h2 data-block-override="art-deco:heading" class="deco-caps deco-underline text-3xl md:text-4xl {{ textClass }}" style="font-family: var(--font-heading, "Italiana", "Cinzel", Georgia, serif); color: hsl(var(--foreground));">{{ text }}</h2>{% endif %}
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
{# hero override — folds in the old marquee_hero: sunburst overlay + stepped ziggurat framing, gold-foil Cinzel headline. Structure/fields/{% img %} calls preserved from builtin. Styled-text fields accept {text,color} or a bare string. #}
|
||||
{% 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 %}<div class="mb-5 flex items-center gap-4 {% if align == "center" %}justify-center{% endif %}"><span class="deco-rule w-10"></span><span class="deco-caps text-xs text-primary">{{ eyebrowText }}</span><span class="deco-rule w-10"></span></div>{% endif %}
|
||||
{% if headlineText %}<h1 class="deco-caps text-4xl sm:text-5xl lg:text-6xl leading-tight" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ headlineText }}</h1>{% endif %}
|
||||
{% if subText %}<h2 class="mt-5 text-xl sm:text-2xl italic max-w-2xl{% if align == "center" %} mx-auto{% endif %}" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ subText }}</h2>{% endif %}
|
||||
{% if descText %}<p class="mt-4 max-w-xl leading-relaxed{% if align == "center" %} mx-auto{% endif %}" style="color:hsl(var(--muted-foreground));">{{ descText }}</p>{% endif %}
|
||||
{% if pText or sText %}<div class="mt-8 flex flex-col sm:flex-row gap-4{% if align == "center" %} justify-center{% endif %}">
|
||||
{% if pText and pUrl %}<a href="{{ pUrl }}" class="deco-pill inline-flex items-center justify-center gap-2">{{ pText }}</a>{% endif %}
|
||||
{% if sText and sUrl %}<a href="{{ sUrl }}" class="deco-link inline-flex items-center justify-center">{{ sText }}</a>{% endif %}
|
||||
</div>{% endif %}
|
||||
{% if trustLogos %}<div class="mt-10">
|
||||
<p class="deco-caps text-xs text-muted-foreground mb-3">Acclaim</p>
|
||||
<div class="flex flex-wrap items-center gap-6{% if align == "center" %} justify-center{% endif %}">{% for logo in trustLogos %}{% if logo.url %}<a href="{{ logo.url }}" target="_blank" rel="noopener noreferrer" class="opacity-60 transition-opacity hover:opacity-100">{% img logo.image alt=logo.alt class="h-8 w-auto" %}</a>{% else %}{% img logo.image alt=logo.alt class="h-8 w-auto opacity-60" %}{% endif %}{% endfor %}</div>
|
||||
</div>{% endif %}
|
||||
{% endmacro %}
|
||||
{% if variant == "split" %}
|
||||
<section data-block-override="art-deco:hero" class="hero grid grid-cols-1 lg:grid-cols-2 overflow-hidden bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="relative min-h-[320px] bg-muted deco-grain {% if mediaPosition == "left" %}order-1 lg:order-1{% else %}order-1 lg:order-2{% endif %}">{% if hasImage %}{% img backgroundImage alt=headlineText class="absolute inset-0 h-full w-full object-cover" layout="hero" %}{% endif %}</div>
|
||||
<div class="flex flex-col justify-center px-6 py-16 lg:px-12 {% if mediaPosition == "left" %}order-2 lg:order-2{% else %}order-2 lg:order-1{% endif %}"><div class="max-w-lg text-left">{{ herocontent("left") }}</div></div>
|
||||
</section>
|
||||
{% else %}
|
||||
{% set align = "center" %}
|
||||
{% if variant == "left-aligned" %}{% set align = "left" %}{% endif %}
|
||||
<section data-block-override="art-deco:hero" class="hero relative flex flex-col overflow-hidden bg-background text-foreground deco-grain {% if hasImage %}{% if minHeight == "screen" %}min-h-screen{% elif minHeight == "50vh" %}min-h-[50vh]{% elif minHeight == "auto" %}min-h-[400px]{% else %}min-h-[75vh]{% endif %}{% else %}deco-hero-compact{% endif %} {% if verticalAlign == "top" %}justify-start pt-20{% elif verticalAlign == "bottom" %}justify-end pb-20{% else %}justify-center{% endif %}{% if class %} {{ class }}{% endif %}">
|
||||
{% if hasImage %}<div class="absolute inset-0 z-0">{% img backgroundImage alt=headlineText class="h-full w-full object-cover" layout="hero" %}{% if showOverlay %}<div class="absolute inset-0 {% if overlayColor == "light" %}bg-background/60{% elif overlayColor == "primary" %}bg-primary/50{% elif overlayOpacity <= 30 %}bg-black/30{% elif overlayOpacity <= 50 %}bg-black/50{% elif overlayOpacity <= 70 %}bg-black/70{% else %}bg-black/80{% endif %}"></div>{% endif %}</div>{% endif %}
|
||||
<div class="pointer-events-none absolute inset-x-0 top-0 z-[1] h-40 opacity-40 deco-sunburst" aria-hidden="true"></div>
|
||||
<div class="relative z-10 mx-auto w-full max-w-4xl px-4 sm:px-6 lg:px-8 {% if variant == "left-aligned" %}text-left{% else %}text-center{% endif %}"><div class="deco-frame bg-transparent px-6 py-10 sm:px-10 sm:py-14">{{ herocontent(align) }}</div></div>
|
||||
</section>
|
||||
{% endif %}
|
||||
@ -1,31 +0,0 @@
|
||||
{# hours-location override — gilded hours ledger + framed map. Map facade <button onclick> preserved verbatim. Fields mirror builtin: heading, hours[].day/.hours/.closed, specialHoursNote, address, phone, directionsUrl, mapEmbedUrl, mapButtonLabel. #}
|
||||
<section data-block-override="art-deco:hours-location" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-5xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-3xl md:text-4xl text-center" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ heading }}</h2>{% endif %}
|
||||
<div class="mt-10 grid grid-cols-1 gap-10 md:grid-cols-2">
|
||||
<div class="deco-frame bg-card p-6 md:p-8">
|
||||
{% if hours %}
|
||||
<table class="w-full text-sm">
|
||||
<tbody class="divide-y divide-[hsl(var(--primary)/0.2)]">
|
||||
{% for row in hours %}
|
||||
<tr>
|
||||
<th scope="row" class="deco-caps py-2 pr-4 text-left text-xs font-medium" style="color:hsl(var(--foreground));">{{ row.day }}</th>
|
||||
<td class="py-2 text-right tabular-nums {% if row.closed %}italic{% endif %}" style="{% if row.closed %}color:hsl(var(--muted-foreground));{% else %}color:hsl(var(--primary));{% endif %}">{% if row.closed %}Closed{% else %}{{ row.hours }}{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% if specialHoursNote %}<p class="mt-4 border-t border-[hsl(var(--primary)/0.3)] pt-3 text-sm italic" style="color:hsl(var(--muted-foreground));">{{ specialHoursNote }}</p>{% endif %}
|
||||
{% if address %}<div class="mt-6"><div class="deco-caps text-xs" style="color:hsl(var(--primary));">Address</div><address class="mt-1 whitespace-pre-line not-italic" style="font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ address }}</address></div>{% endif %}
|
||||
{% if phone %}<div class="mt-4"><div class="deco-caps text-xs" style="color:hsl(var(--primary));">Reservations</div><a href="tel:{{ phone }}" class="deco-link mt-1 inline-block">{{ phone }}</a></div>{% endif %}
|
||||
{% if directionsUrl %}<a href="{{ directionsUrl }}" target="_blank" rel="noopener noreferrer" class="deco-pill mt-6 inline-flex items-center gap-2">::lucide:navigation:sm:: Get directions</a>{% endif %}
|
||||
</div>
|
||||
{% if mapEmbedUrl %}
|
||||
<div class="deco-step aspect-square w-full overflow-hidden bg-muted md:aspect-auto">
|
||||
<button type="button" data-map-src="{{ mapEmbedUrl }}" onclick="var f=document.createElement('iframe');f.src=this.getAttribute('data-map-src');f.setAttribute('class','h-full w-full border-0');f.setAttribute('loading','lazy');f.setAttribute('referrerpolicy','no-referrer-when-downgrade');f.setAttribute('title','Map');this.parentNode.replaceChild(f,this);" class="deco-caps flex h-full min-h-[16rem] w-full items-center justify-center gap-2 text-sm transition-colors hover:bg-accent hover:text-accent-foreground" style="color:hsl(var(--primary));">::lucide:map-pin:md:: {{ mapButtonLabel|default:"Load map" }}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,11 +1 @@
|
||||
{# image override — stepped gold Deco frame. Fields mirror builtin: src, alt, caption, size, align, aspectRatio, objectFit. Media resolved via {% img %} (media filter is not registered in the block render path). #}
|
||||
{% with size=size|default:"full" align=align|default:"center" objectFit=objectFit|default:"cover" %}
|
||||
<figure data-block-override="art-deco:image" class="my-8 flex-1 {% if align == "left" %}flex justify-start{% elif align == "right" %}flex justify-end{% else %}flex justify-center{% endif %}{% if class %} {{ class }}{% endif %}">
|
||||
<div class="deco-step {% if size == "xs" %}max-w-[200px] w-full{% elif size == "sm" %}max-w-[400px] w-full{% elif size == "md" %}max-w-[600px] w-full{% elif size == "lg" %}max-w-[800px] w-full{% else %}w-full{% endif %}">
|
||||
<div class="relative overflow-hidden bg-muted {% if aspectRatio == "square" %}aspect-square{% elif aspectRatio == "video" %}aspect-video{% elif aspectRatio == "portrait" %}aspect-[3/4]{% elif aspectRatio == "wide" %}aspect-[21/9]{% endif %}">
|
||||
{% 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 %}
|
||||
</div>
|
||||
</div>
|
||||
{% if caption %}<figcaption class="mt-3 text-center text-sm italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ caption }}</figcaption>{% endif %}
|
||||
</figure>
|
||||
{% endwith %}
|
||||
<figure data-block-override="art-deco:image" class="my-8"><div class="{% if frame == "scallop" %}deco-scallop{% elif frame == "plain" %}{% else %}deco-step{% endif %}"><img src="{% if src %}{{ src }}{% else %}data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20fill%3D%22%23222%22%2F%3E%3C%2Fsvg%3E{% endif %}" alt="{{ alt }}" class="block w-full h-auto"></div>{% if caption %}<figcaption class="mt-2 italic text-center text-sm" style="color: hsl(var(--muted-foreground));">{{ caption }}</figcaption>{% endif %}</figure>
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
<section data-block-override="art-deco:logo-strip" class="py-12 md:py-16 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if heading %}<div class="mb-8 flex items-center justify-center gap-4"><span class="deco-rule w-12"></span><p class="deco-caps text-xs text-muted-foreground">{{ heading }}</p><span class="deco-rule w-12"></span></div>{% endif %}
|
||||
<div class="mt-8 {% if marquee %}group relative overflow-hidden [mask-image:linear-gradient(to_right,transparent,black_8%,black_92%,transparent)]{% endif %}">
|
||||
<div class="flex flex-wrap items-center justify-center gap-x-10 gap-y-6 {% if marquee %}flex-nowrap [animation:logo-marquee_30s_linear_infinite] motion-reduce:[animation:none] group-hover:[animation-play-state:paused]{% endif %}">
|
||||
{% for logo in logos %}
|
||||
{% if logo.url %}<a href="{{ logo.url }}" class="block shrink-0 opacity-80 transition hover:opacity-100">{% endif %}
|
||||
<span class="inline-flex h-8 items-center{% if grayscale %} grayscale transition-[filter] hover:grayscale-0{% endif %}">{% img logo.image alt=logo.alt class="h-8 w-auto object-contain" %}</span>
|
||||
{% if logo.url %}</a>{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% if marquee %}<style>@keyframes logo-marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}</style>{% endif %}
|
||||
@ -1,30 +0,0 @@
|
||||
{# menu-list override — the supper-club menu card: centred Cinzel section titles, gold leader rules, symmetric columns. Fields mirror builtin: heading, intro, columns, sections[].title/.note/.items[].name/.badges/.description/.price, currency, footnote. #}
|
||||
<section data-block-override="art-deco:menu-list" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-5xl px-4 text-center">
|
||||
{% if heading %}<h2 class="deco-caps text-3xl md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-3 max-w-2xl text-lg italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ intro }}</p>{% endif %}
|
||||
<div class="mx-auto mt-6 mb-4 h-6 w-40 deco-sunburst" aria-hidden="true"></div>
|
||||
<div class="mt-6 grid grid-cols-1 gap-x-14 gap-y-12 text-left {% if columns == 2 %}md:grid-cols-2{% endif %}">
|
||||
{% for section in sections %}
|
||||
<div class="menu-section">
|
||||
{% if section.title %}<h3 class="deco-caps deco-underline pb-2 text-center text-xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--primary));">{{ section.title }}</h3>{% endif %}
|
||||
{% if section.note %}<p class="mt-2 text-center text-sm italic" style="color:hsl(var(--muted-foreground));">{{ section.note }}</p>{% endif %}
|
||||
<ul class="mt-5 space-y-5">
|
||||
{% for item in section.items %}
|
||||
<li>
|
||||
<div class="flex items-baseline gap-3">
|
||||
<span class="shrink-0 font-medium" style="color:hsl(var(--foreground));">{{ item.name }}</span>
|
||||
<span class="min-w-6 flex-1 translate-y-[-2px] border-b border-dotted border-[hsl(var(--primary)/0.5)]" aria-hidden="true"></span>
|
||||
{% if item.price %}<span class="shrink-0 tabular-nums" style="color:hsl(var(--primary));font-family:var(--font-heading, 'Cinzel', Georgia, serif);">{% if currency %}{{ currency }}{% endif %}{{ item.price }}</span>{% endif %}
|
||||
</div>
|
||||
{% if item.badges %}<div class="mt-1 flex flex-wrap gap-1.5">{% for badge in item.badges %}{% if badge.label %}<span class="deco-caps inline-block border border-[hsl(var(--primary)/0.4)] px-2 py-0.5 text-[0.65rem]" style="color:hsl(var(--muted-foreground));">{{ badge.label }}</span>{% endif %}{% endfor %}</div>{% endif %}
|
||||
{% if item.description %}<p class="mt-1 text-sm italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ item.description }}</p>{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if footnote %}<p class="mt-12 text-xs" style="color:hsl(var(--muted-foreground));">{{ footnote }}</p>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
@ -1,104 +0,0 @@
|
||||
{# navbar override — gilded masthead. Structure, fixed drawer ids, focus-trap JS and all data-* preserved verbatim from the builtin; presentation reskinned to Art Deco. Fields identical: variant/stickyBehavior/megaMenu/logoType/logoText/logo/companyName/cta/menu.items/... #}
|
||||
{% 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) %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} class="deco-caps px-3 py-2 text-xs text-foreground/80 hover:text-primary transition-colors {{ item.css_class }}">{{ item.label }}</a>{% endmacro %}
|
||||
{% macro dropdown(item) %}<div class="relative group">
|
||||
<button type="button" class="deco-caps px-3 py-2 text-xs text-foreground/80 hover:text-primary transition-colors inline-flex items-center gap-1">{{ item.label }}<svg class="h-4 w-4 transition-transform group-hover:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg></button>
|
||||
{% if use_mega %}<div class="absolute left-1/2 -translate-x-1/2 mt-1 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50"><div class="deco-frame p-6 bg-card grid gap-8" style="grid-template-columns:repeat({{ item.children|length|default:1 }},minmax(10rem,1fr));min-width:min(90vw,42rem)">{% for child in item.children %}<div class="space-y-1">{% if child.item_type == "header" %}<div class="deco-caps px-2 py-1 text-[0.65rem] text-primary border-b border-[hsl(var(--primary)/0.3)] mb-2">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-2 py-2 hover:bg-accent transition-colors {{ child.css_class }}">{% if child.icon %}<span class="mr-1.5 text-primary">::{{ child.icon }}::</span>{% endif %}<span class="text-sm font-medium text-foreground">{{ child.label }}</span>{% if child.description %}<span class="block text-xs text-muted-foreground mt-0.5">{{ child.description }}</span>{% endif %}</a>{% endif %}</div>{% endfor %}</div></div>
|
||||
{% else %}<div class="absolute left-0 mt-1 w-56 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50"><div class="deco-frame py-2 bg-card">{% for child in item.children %}{% if child.item_type == "header" %}<div class="deco-caps px-4 py-2 text-[0.65rem] text-primary">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-4 py-2 text-sm text-foreground hover:bg-accent transition-colors {{ child.css_class }}">{{ child.label }}</a>{% endif %}{% endfor %}</div></div>{% endif %}
|
||||
</div>{% endmacro %}
|
||||
{% macro brand(size) %}<a href="/" class="flex-shrink-0 flex items-center">{% if logoType == "text" and logoText.text %}<span class="deco-caps text-xl {{ logoText.color }}" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ logoText.text }}</span>{% elif logo %}<img src="{{ logo }}" alt="{{ alt|default:companyName }}" class="{{ size }} w-auto"{% if logoMaxWidth or logoMaxHeight %} style="{% if logoMaxWidth %}max-width:{{ logoMaxWidth }};{% endif %}{% if logoMaxHeight %}max-height:{{ logoMaxHeight }};{% endif %}"{% endif %}/>{% elif companyName %}<span class="deco-caps text-xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ companyName }}</span>{% endif %}</a>{% endmacro %}
|
||||
{% macro ctabtn(extra) %}{% if cta_text %}<a href="{{ cta_url|default:'#' }}" class="deco-pill inline-flex items-center {{ extra }}">{{ cta_text }}</a>{% endif %}{% endmacro %}
|
||||
<nav data-block-override="art-deco:navbar" data-bn-navbar data-bn-nav-variant="{{ nv }}" data-bn-sticky="{{ sb }}"{% if is_transparent %} data-bn-transparent="1"{% endif %} class="bn-navbar w-full {% if sb == "sticky" or sb == "shrink-on-scroll" %}sticky top-0 z-40 {% endif %}{% if is_transparent %}absolute top-0 left-0 z-40 text-white{% else %}{{ bg }} border-b border-[hsl(var(--primary)/0.4)]{% endif %} {{ class }}">
|
||||
{% if showUtilityBar %}<div class="w-full text-xs {% if not showOnMobile %}hidden sm:block{% endif %} bg-foreground text-background"><div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between h-8"><div>{{ utilityBarText|safe }}</div><div class="flex items-center gap-4">{% if utilityBarPhone %}<a href="tel:{{ utilityBarPhone }}" class="hover:text-primary transition-colors">{{ utilityBarPhone }}</a>{% endif %}{% if utilityBarEmail %}<a href="mailto:{{ utilityBarEmail }}" class="hover:text-primary transition-colors">{{ utilityBarEmail }}</a>{% endif %}</div></div></div>{% endif %}
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="bn-navbar-row flex items-center justify-between h-16">
|
||||
{% if nv == "centered-logo" %}
|
||||
<div class="hidden md:flex items-center gap-1 flex-1">{% for item in menu.items %}{% if item.children %}{{ dropdown(item) }}{% else %}{{ navlink(item) }}{% endif %}{% endfor %}</div>
|
||||
<div class="flex items-center justify-center">{{ brand("h-9") }}</div>
|
||||
<div class="hidden md:flex items-center gap-3 flex-1 justify-end">{{ ctabtn("") }}</div>
|
||||
{% elif nv == "split" %}
|
||||
<div class="hidden md:flex items-center gap-1 flex-1">{% for item in menu.items %}{% if forloop.Counter0 * 2 < menu.items|length %}{% if item.children %}{{ dropdown(item) }}{% else %}{{ navlink(item) }}{% endif %}{% endif %}{% endfor %}</div>
|
||||
<div class="flex items-center justify-center">{{ brand("h-9") }}</div>
|
||||
<div class="hidden md:flex items-center gap-1 flex-1 justify-end">{% for item in menu.items %}{% if forloop.Counter0 * 2 >= menu.items|length %}{% if item.children %}{{ dropdown(item) }}{% else %}{{ navlink(item) }}{% endif %}{% endif %}{% endfor %}{{ ctabtn("ml-3") }}</div>
|
||||
{% else %}
|
||||
<div class="flex items-center">{{ brand("h-8") }}</div>
|
||||
<div class="hidden md:flex items-center gap-1">{% for item in menu.items %}{% if item.children %}{{ dropdown(item) }}{% else %}{{ navlink(item) }}{% endif %}{% endfor %}{{ ctabtn("ml-3") }}</div>
|
||||
{% endif %}
|
||||
<div class="flex items-center md:hidden">
|
||||
<label for="bn-navbar-toggle" data-bn-nav-open aria-controls="bn-navbar-drawer" aria-expanded="false" class="inline-flex items-center justify-center p-2 rounded-md cursor-pointer hover:bg-accent/50 transition-colors"><span class="sr-only">Open menu</span><svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# --- Mobile off-canvas drawer: pure-CSS checkbox baseline (works with no JS) --- #}
|
||||
<input type="checkbox" id="bn-navbar-toggle" class="bn-navbar-toggle" aria-hidden="true"/>
|
||||
<label for="bn-navbar-toggle" class="bn-navbar-overlay fixed inset-0 bg-black/50 z-40 md:hidden" aria-hidden="true"></label>
|
||||
<div id="bn-navbar-drawer" class="bn-navbar-drawer fixed top-0 right-0 h-full w-80 max-w-[85vw] bg-background text-foreground z-50 shadow-xl md:hidden flex flex-col border-l border-[hsl(var(--primary)/0.4)]" role="dialog" aria-modal="true" aria-label="Site menu">
|
||||
<div class="flex items-center justify-between p-4 border-b border-[hsl(var(--primary)/0.3)]">{{ brand("h-8") }}<label for="bn-navbar-toggle" data-bn-nav-close class="p-2 rounded-md cursor-pointer text-muted-foreground hover:text-primary hover:bg-accent"><span class="sr-only">Close menu</span><svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></label></div>
|
||||
<nav class="flex-1 overflow-y-auto py-4" aria-label="Mobile">{% for item in menu.items %}{% if item.children %}<details class="group/acc"><summary class="deco-caps flex items-center justify-between px-6 py-3 text-sm cursor-pointer hover:bg-accent transition-colors list-none">{{ item.label }}<svg class="h-4 w-4 transition-transform group-open/acc:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg></summary><div class="pl-8 pb-2">{% for child in item.children %}{% if child.item_type != "header" %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-2 py-2 text-sm text-muted-foreground hover:text-primary transition-colors">{{ child.label }}</a>{% endif %}{% endfor %}</div></details>{% else %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="deco-caps block px-6 py-3 text-sm hover:bg-accent transition-colors">{{ item.label }}</a>{% endif %}{% endfor %}</nav>
|
||||
{% if cta_text %}<div class="p-4 border-t border-[hsl(var(--primary)/0.3)]"><a href="{{ cta_url|default:'#' }}" class="deco-pill block w-full text-center">{{ cta_text }}</a></div>{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
<style>
|
||||
.bn-navbar-toggle{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;}
|
||||
.bn-navbar-drawer{transform:translateX(100%);transition:transform .3s ease;}
|
||||
.bn-navbar-overlay{opacity:0;pointer-events:none;transition:opacity .3s ease;}
|
||||
.bn-navbar-toggle:checked ~ .bn-navbar-drawer{transform:translateX(0);}
|
||||
.bn-navbar-toggle:checked ~ .bn-navbar-overlay{opacity:1;pointer-events:auto;}
|
||||
.bn-navbar-drawer details > summary::-webkit-details-marker{display:none;}
|
||||
[data-bn-sticky="shrink-on-scroll"].bn-navbar-shrunk .bn-navbar-row{height:3rem;}
|
||||
[data-bn-sticky="shrink-on-scroll"] .bn-navbar-row{transition:height .2s ease;}
|
||||
[data-bn-transparent].bn-navbar-solid{position:sticky;color:inherit;background:hsl(var(--background));border-bottom:1px solid hsl(var(--primary) / 0.4);}
|
||||
</style>
|
||||
<script>
|
||||
(function(){
|
||||
if(window.__bnNavInit)return;window.__bnNavInit=1;
|
||||
function ready(fn){if(document.readyState!='loading')fn();else document.addEventListener('DOMContentLoaded',fn);}
|
||||
ready(function(){
|
||||
document.querySelectorAll('[data-bn-navbar]').forEach(function(nav){
|
||||
var toggle=nav.querySelector('.bn-navbar-toggle');
|
||||
var drawer=nav.querySelector('.bn-navbar-drawer');
|
||||
var opener=nav.querySelector('[data-bn-nav-open]');
|
||||
if(toggle&&drawer){
|
||||
function focusables(){return drawer.querySelectorAll('a[href],button,label[for],input,summary,[tabindex]:not([tabindex="-1"])');}
|
||||
toggle.addEventListener('change',function(){
|
||||
var open=toggle.checked;
|
||||
document.documentElement.style.overflow=open?'hidden':'';
|
||||
document.body.style.overflow=open?'hidden':'';
|
||||
if(opener)opener.setAttribute('aria-expanded',open?'true':'false');
|
||||
if(open){var f=focusables();if(f.length)f[0].focus();}
|
||||
else if(opener&&opener.focus)opener.focus();
|
||||
});
|
||||
drawer.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){toggle.checked=false;toggle.dispatchEvent(new Event('change'));return;}
|
||||
if(e.key!=='Tab')return;
|
||||
var f=focusables();if(!f.length)return;
|
||||
var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();last.focus();}
|
||||
else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();first.focus();}
|
||||
});
|
||||
drawer.querySelectorAll('a[href]').forEach(function(a){a.addEventListener('click',function(){toggle.checked=false;toggle.dispatchEvent(new Event('change'));});});
|
||||
}
|
||||
var sb=nav.getAttribute('data-bn-sticky');
|
||||
var transparent=nav.getAttribute('data-bn-transparent')==='1';
|
||||
if(sb==='shrink-on-scroll'||transparent){
|
||||
var overHero=false;
|
||||
if(transparent){var next=nav.nextElementSibling;overHero=!!next&&next.getBoundingClientRect().height>=240;if(!overHero)nav.classList.add('bn-navbar-solid');}
|
||||
var onScroll=function(){
|
||||
var y=window.scrollY||window.pageYOffset;
|
||||
if(sb==='shrink-on-scroll')nav.classList.toggle('bn-navbar-shrunk',y>40);
|
||||
if(transparent&&overHero)nav.classList.toggle('bn-navbar-solid',y>40);
|
||||
};
|
||||
window.addEventListener('scroll',onScroll,{passive:true});onScroll();
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@ -1,13 +0,0 @@
|
||||
{# newsletter-signup (art-deco) — the {% signup_form %} tag carries the #}
|
||||
{# untouchable subscribe wiring (/api/lists/subscribe HTMX post + honeypot); #}
|
||||
{# this template supplies only the art-deco chrome around it. #}
|
||||
<section data-block-override="art-deco:newsletter-signup" class="py-12 bg-background text-foreground md:py-16{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-3xl px-4">
|
||||
<div class="deco-frame {% if layout == "inline" %}deco-grain bg-primary px-6 py-12 text-primary-foreground md:px-12{% else %}bg-card px-6 py-12 text-card-foreground md:px-10{% endif %} text-center">
|
||||
<div class="mb-4 flex items-center justify-center gap-4"><span class="deco-rule w-12"></span><span class="deco-rule w-12"></span></div>
|
||||
{% if title %}<h2 class="deco-caps text-2xl md:text-3xl" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ title }}</h2>{% endif %}
|
||||
{% if description %}<p class="mx-auto mt-4 max-w-xl {% if layout == "inline" %}text-primary-foreground/80{% else %}text-muted-foreground{% endif %}" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ description }}</p>{% endif %}
|
||||
<div class="mx-auto mt-6 max-w-md">{% signup_form list=listSlug source=source submit=submitText success_message=successMessage placeholder=placeholder %}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,21 +0,0 @@
|
||||
{# page-suggestions override — themed 404 suggestions. Fields: title, showDescription, emptyMessage; suggestions[] from the provider (.slug/.title/.excerpt). #}
|
||||
{% if suggestions %}
|
||||
<div data-block-override="art-deco:page-suggestions" class="page-suggestions py-10">
|
||||
{% if title %}<h2 class="deco-caps deco-underline mx-auto w-fit text-xl text-center" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">{{ title }}</h2>{% endif %}
|
||||
<ul class="mt-6 space-y-3 max-w-lg mx-auto">
|
||||
{% for suggestion in suggestions %}
|
||||
<li class="flex items-start gap-3">
|
||||
<span class="mt-0.5 shrink-0" style="color:hsl(var(--primary));">::lucide:chevron-right:sm::</span>
|
||||
<div>
|
||||
<a href="{{ suggestion.slug }}" class="deco-link font-medium">{{ suggestion.title }}</a>
|
||||
{% if showDescription and suggestion.excerpt %}<p class="mt-1 text-sm italic" style="color:hsl(var(--muted-foreground));">{{ suggestion.excerpt }}</p>{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% elif emptyMessage %}
|
||||
<div data-block-override="art-deco:page-suggestions" class="page-suggestions py-10 text-center">
|
||||
<p class="italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ emptyMessage }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -1,13 +0,0 @@
|
||||
{# password-reset-form override — request stage only, matching builtin. Wiring UNTOUCHABLE: /api/auth/request-password-reset (email), hx-target #reset-message. Reskinned to Art Deco. #}
|
||||
<div data-block-override="art-deco:password-reset-form" class="password-reset-form deco-frame mx-auto max-w-md bg-card p-8">
|
||||
<div id="reset-message"></div>
|
||||
<div id="request-reset-panel" class="text-center">
|
||||
<h2 class="deco-caps text-2xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif);color:hsl(var(--foreground));">Reset password</h2>
|
||||
<p class="mt-3 text-sm italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">Enter your email and we will send a link to reset your password.</p>
|
||||
<form hx-post="/api/auth/request-password-reset" hx-target="#reset-message" hx-swap="innerHTML" class="mt-6 text-left">
|
||||
<div class="mb-4"><label class="deco-caps block text-xs mb-1" style="color:hsl(var(--primary));">Email</label><input type="email" name="email" required class="w-full rounded-none border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:border-[hsl(var(--primary))] focus:ring-1 focus:ring-ring" /></div>
|
||||
<button type="submit" class="deco-pill w-full" hx-disabled-elt="this">Send reset link</button>
|
||||
</form>
|
||||
<p class="text-center mt-4 text-sm"><a href="/login" class="deco-link">Back to sign in</a></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,16 +0,0 @@
|
||||
{# popular-posts (art-deco) — compact ranked list from the `posts` provider. #}
|
||||
<section data-block-override="art-deco:popular-posts" class="bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
{% if heading %}<h2 class="deco-caps mb-5 text-xs text-primary">{{ heading }}</h2>{% endif %}
|
||||
<ol class="space-y-4">
|
||||
{% for post in posts %}
|
||||
<li class="deco-rule flex items-start gap-3 pt-4">
|
||||
{% if showRank %}<span class="mt-0.5 text-lg font-bold tabular-nums text-primary" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ forloop.Counter }}</span>{% endif %}
|
||||
{% if showThumbnail and post.featured_image_url %}<a href="{{ post.url }}" class="deco-step h-12 w-12 flex-shrink-0 overflow-hidden bg-muted">{% img post.featured_image_url alt=post.title class="h-full w-full object-cover" %}</a>{% endif %}
|
||||
<div class="min-w-0">
|
||||
<h3 class="deco-caps text-sm leading-snug text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)"><a href="{{ post.url }}" class="transition-colors hover:text-primary">{{ post.title }}</a></h3>
|
||||
{% if post.published_at %}<p class="mt-1 text-xs text-muted-foreground">{{ post.published_at|date:"M j, Y" }}</p>{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</section>
|
||||
@ -1,23 +0,0 @@
|
||||
{# post-hero (art-deco) — 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 %}
|
||||
<section data-block-override="art-deco:post-hero" class="hero relative flex min-h-[50vh] flex-col justify-end overflow-hidden bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="absolute inset-0 z-0">{% img post.featured_image_url alt=post.featured_image_alt class="h-full w-full object-cover" layout="hero" %}<div class="absolute inset-0 bg-black/70"></div><div class="deco-grain absolute inset-0"></div></div>
|
||||
<div class="relative z-10 mx-auto w-full max-w-4xl px-4 py-14 sm:px-6 lg:px-8 {% if center %}text-center{% endif %}">
|
||||
{% if center %}<div class="mb-4 flex items-center justify-center gap-4"><span class="deco-rule w-12"></span><span class="deco-rule w-12"></span></div>{% endif %}
|
||||
<h1 class="deco-caps text-3xl leading-tight text-white sm:text-4xl lg:text-5xl" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ post.title }}</h1>
|
||||
{% if showExcerpt and post.excerpt %}<p class="mt-5 max-w-2xl text-lg text-white/80{% if center %} mx-auto{% endif %}" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ post.excerpt }}</p>{% endif %}
|
||||
{% if showMeta %}<div class="mt-6 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-white/80{% if center %} justify-center{% endif %}">{% if post.author_name %}<span class="deco-caps text-white">{{ post.author_name }}</span>{% endif %}{% if post.published_at %}<span>{{ post.published_at|date:"F j, Y" }}</span>{% endif %}{% if post.reading_time %}<span>{{ post.reading_time }} min read</span>{% endif %}</div>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% else %}
|
||||
<section data-block-override="art-deco:post-hero" class="bg-background py-16 text-foreground md:py-20{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto w-full max-w-3xl px-4 {% if center %}text-center{% endif %}">
|
||||
{% if center %}<div class="mb-4 flex items-center justify-center gap-4"><span class="deco-rule w-12"></span><span class="deco-rule w-12"></span></div>{% endif %}
|
||||
<h1 class="deco-caps deco-underline text-3xl leading-tight sm:text-4xl lg:text-5xl text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ post.title }}</h1>
|
||||
{% if showExcerpt and post.excerpt %}<p class="mt-5 text-lg text-muted-foreground{% if center %} mx-auto max-w-2xl{% endif %}" style="font-family:var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif)">{{ post.excerpt }}</p>{% endif %}
|
||||
{% if showMeta %}<div class="mt-6 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-muted-foreground{% if center %} justify-center{% endif %}">{% if post.author_name %}<span class="deco-caps text-primary">{{ post.author_name }}</span>{% endif %}{% if post.published_at %}<span>{{ post.published_at|date:"F j, Y" }}</span>{% endif %}{% if post.reading_time %}<span>{{ post.reading_time }} min read</span>{% endif %}</div>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
@ -1,9 +0,0 @@
|
||||
{# post-metadata (art-deco) — author/date/reading-time row from the `post` provider. #}
|
||||
{% if post %}
|
||||
<div data-block-override="art-deco:post-metadata" class="flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-muted-foreground{% if class %} {{ class }}{% endif %}">
|
||||
{% if showAuthor and post.author_name %}<span class="flex items-center gap-2">{% if showAvatar and post.author_avatar %}{% img post.author_avatar alt=post.author_name class="h-7 w-7 rounded-full object-cover ring-1 ring-[hsl(var(--primary)/0.5)]" %}{% endif %}<span class="deco-caps text-primary">{{ post.author_name }}</span></span>{% endif %}
|
||||
{% if showDate and post.published_at %}<time datetime="{{ post.published_at|date:"Y-m-d" }}">{{ post.published_at|date:"F j, Y" }}</time>{% endif %}
|
||||
{% if showReadingTime and post.reading_time %}<span>{{ post.reading_time }} min read</span>{% endif %}
|
||||
{% if post.categories %}<span class="flex flex-wrap gap-1.5">{% for cat in post.categories %}<a href="{{ cat.url|default:'#' }}" class="deco-caps rounded-none border border-[hsl(var(--primary)/0.35)] px-2 py-0.5 text-xs text-muted-foreground transition-colors hover:text-primary">{{ cat.name }}</a>{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -1,25 +0,0 @@
|
||||
<section data-block-override="art-deco:pricing" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-center text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<div class="mt-12 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{% for tier in tiers %}
|
||||
<div class="relative flex flex-col p-6 {% if tier.highlighted %}deco-frame bg-card text-card-foreground deco-foil{% else %}rounded-none border border-[hsl(var(--primary)/0.35)] bg-card text-card-foreground{% endif %}">
|
||||
{% if tier.badge %}<span class="deco-caps absolute -top-3 left-1/2 -translate-x-1/2 border border-primary bg-primary px-3 py-1 text-xs text-primary-foreground">{{ tier.badge }}</span>{% endif %}
|
||||
<h3 class="deco-caps text-center text-lg text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ tier.name }}</h3>
|
||||
<div class="mx-auto my-3 flex items-center justify-center"><span class="deco-rule w-12"></span></div>
|
||||
<p class="flex items-baseline justify-center gap-1">
|
||||
<span class="text-4xl font-bold tracking-tight text-primary" style="font-family:var(--font-heading)">{% if currency %}{{ currency }}{% else %}${% endif %}{{ tier.price }}</span>
|
||||
{% if tier.period %}<span class="text-sm text-muted-foreground">{{ tier.period }}</span>{% endif %}
|
||||
</p>
|
||||
{% if tier.description %}<p class="mt-3 text-center text-sm text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ tier.description }}</p>{% endif %}
|
||||
{% if tier.features %}<ul class="mt-6 flex-1 space-y-3 text-sm">
|
||||
{% for feature in tier.features %}<li class="flex items-start gap-2"><svg class="mt-0.5 h-4 w-4 shrink-0 text-primary" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg><span>{{ feature }}</span></li>{% endfor %}
|
||||
</ul>{% endif %}
|
||||
{% if tier.ctaUrl and tier.ctaLabel %}{% if tier.highlighted %}<a href="{{ tier.ctaUrl }}" class="deco-pill mt-8 inline-flex w-full items-center justify-center">{{ tier.ctaLabel }}</a>{% else %}<a href="{{ tier.ctaUrl }}" class="deco-link mt-8 inline-flex w-full items-center justify-center">{{ tier.ctaLabel }}</a>{% endif %}{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if billingNote %}<p class="mt-8 text-center text-sm text-muted-foreground">{{ billingNote }}</p>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
@ -1,8 +0,0 @@
|
||||
{# quote override — supper-club press pull-quote: large italic Cormorant flanked by gold sunburst crests. Fields mirror builtin: quote, style, align, cite, attribution, role. #}
|
||||
{% with style=style|default:"block" align=align|default:"left" %}
|
||||
<figure data-block-override="art-deco:quote" class="bn-quote my-10 {% if style == "inline-card" %}deco-frame bg-card p-8 md:p-10{% elif style == "pull" %}border-l-2 border-[hsl(var(--primary))] pl-6 md:pl-8 py-2{% else %}px-2 py-1{% endif %}{% if align == "center" %} text-center{% endif %}{% if class %} {{ class }}{% endif %}">
|
||||
{% if align == "center" %}<div class="mb-5 h-6 deco-scallop" aria-hidden="true"></div>{% endif %}
|
||||
<blockquote{% if cite %} cite="{{ cite }}"{% endif %} class="{% if style == "pull" %}text-2xl md:text-3xl leading-snug{% else %}text-xl md:text-2xl leading-relaxed{% endif %} italic" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif);color:hsl(var(--foreground));">{{ quote|safe }}</blockquote>
|
||||
{% if attribution or role or cite %}<figcaption class="mt-4 text-sm{% if align == "center" %} flex flex-col items-center{% endif %}" style="color:hsl(var(--muted-foreground));">{% if attribution %}<span class="deco-caps text-xs" style="color:hsl(var(--primary));">{{ attribution }}</span>{% endif %}{% if role %}<span class="{% if attribution %}block {% endif %}italic">{{ role }}</span>{% endif %}{% if cite %}<a href="{{ cite }}" class="deco-link {% if attribution or role %}mt-1 {% endif %}inline-block text-xs">Source</a>{% endif %}</figcaption>{% endif %}
|
||||
</figure>
|
||||
{% endwith %}
|
||||
@ -1,17 +0,0 @@
|
||||
{# related-posts (art-deco) — grid from the `posts` provider. #}
|
||||
{% if posts %}
|
||||
<section data-block-override="art-deco:related-posts" class="deco-rule-thick py-12 md:py-16 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
<h2 class="deco-caps deco-underline mb-10 text-center text-2xl md:text-3xl text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ heading|default:"Related posts" }}</h2>
|
||||
<div class="grid grid-cols-1 gap-8 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% else %}lg:grid-cols-3{% endif %}">
|
||||
{% for post in posts %}
|
||||
<article class="group flex flex-col text-center">
|
||||
{% if post.featured_image_url %}<a href="{{ post.url }}" class="deco-step mb-4 block aspect-video overflow-hidden bg-muted">{% img post.featured_image_url alt=post.title class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" %}</a>{% endif %}
|
||||
<h3 class="deco-caps text-base leading-snug text-foreground" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)"><a href="{{ post.url }}" class="transition-colors hover:text-primary">{{ post.title }}</a></h3>
|
||||
{% if post.published_at %}<p class="mt-2 text-xs text-muted-foreground">{{ post.published_at|date:"M j, Y" }}</p>{% endif %}
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
@ -1,13 +0,0 @@
|
||||
<section data-block-override="art-deco:rich-section" class="py-16 md:py-24 {% if background == "muted" %}bg-muted text-foreground{% elif background == "card" %}bg-card text-card-foreground{% else %}bg-background text-foreground{% endif %}{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto grid max-w-6xl items-center gap-10 px-4 md:grid-cols-2 md:gap-16">
|
||||
<div class="{% if mediaPosition == "left" %}md:order-2{% else %}md:order-1{% endif %}">
|
||||
{% if eyebrow %}<div class="mb-3 flex items-center gap-4"><span class="deco-rule w-12"></span><p class="deco-caps text-xs text-primary">{{ eyebrow }}</p></div>{% endif %}
|
||||
{% if heading %}<h2 class="deco-caps deco-underline mt-2 text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if body %}<div class="mt-4 space-y-4 text-lg text-muted-foreground [&_a]:text-primary [&_a]:underline [&_strong]:text-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ body|safe }}</div>{% endif %}
|
||||
{% if ctaUrl and ctaLabel %}<a href="{{ ctaUrl }}" class="deco-pill mt-6 inline-flex items-center gap-2">{{ ctaLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
|
||||
</div>
|
||||
<div class="{% if mediaPosition == "left" %}md:order-1{% else %}md:order-2{% endif %}">
|
||||
{% if media %}<div class="deco-step overflow-hidden">{% img media alt=mediaAlt class="w-full h-auto object-cover" %}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,2 +0,0 @@
|
||||
{# rich-text override — long-form Cormorant editorial column with gilded links. Field: html (mirrors builtin). #}
|
||||
{% if html %}<article data-block-override="art-deco:rich-text" class="rich-text prose prose-lg max-w-none [&_a]:text-primary [&_a]:no-underline [&_a]:border-b [&_a:hover]:text-accent [&_h1]:deco-caps [&_h2]:deco-caps [&_h3]:deco-caps [&_blockquote]:border-l-2 [&_blockquote]:border-[hsl(var(--primary))] [&_blockquote]:italic" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif);color:hsl(var(--foreground));font-size:1.1rem;line-height:1.75;">{{ html|safe }}</article>{% endif %}
|
||||
@ -1,15 +0,0 @@
|
||||
{# sidebar-nav (art-deco) — 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" %}
|
||||
<nav data-block-override="art-deco:sidebar-nav" class="flex-1 {% if compact %}w-56 py-4 pr-3{% else %}w-64 py-6 pr-4{% endif %}{% if showBorder %} border-r border-[hsl(var(--primary)/0.35)]{% endif %}{% if class %} {{ class }}{% endif %}">
|
||||
{% if title %}<h3 class="deco-caps deco-underline {% if compact %}px-2 mb-4 text-xs text-primary{% else %}px-3 mb-5 text-sm text-foreground{% endif %}" style="font-family:var(--font-heading, "Cinzel", "Italiana", Georgia, serif)">{{ title }}</h3>{% endif %}
|
||||
<ul class="{% if compact %}space-y-0.5{% else %}space-y-1{% endif %}">
|
||||
{% for item in menu.items %}
|
||||
<li><a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} data-bn-sidebar-link class="deco-caps flex items-center rounded-none text-sm text-muted-foreground transition-colors hover:text-primary hover:bg-accent {% if compact %}px-2 py-1.5{% else %}px-3 py-2{% endif %} {{ item.css_class }}">{% if item.icon %}<svg class="mr-2 h-4 w-4 text-primary" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg>{% endif %}{{ item.label }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% if highlightCurrent %}<script>
|
||||
(function(){var p=window.location.pathname;document.querySelectorAll('[data-bn-sidebar-link]').forEach(function(a){if(a.getAttribute('href')===p){a.classList.remove('text-muted-foreground');a.classList.add('text-foreground','bg-accent','font-medium');}});})();
|
||||
</script>{% endif %}
|
||||
@ -1,13 +0,0 @@
|
||||
<div data-block-override="art-deco:social-links" class="social-links{% if class %} {{ class }}{% endif %}">
|
||||
{% if heading %}<p class="deco-caps mb-4 text-xs tracking-[0.18em] text-primary">{{ heading }}</p>{% endif %}
|
||||
<ul class="flex {% if style == "stack" %}flex-col gap-2{% else %}flex-wrap items-center gap-3{% endif %}">
|
||||
{% for link in links %}{% if link.url %}
|
||||
<li>
|
||||
<a href="{{ link.url }}" target="_blank" rel="noopener noreferrer" aria-label="{{ link.label|default:link.network }}" class="deco-foil inline-flex items-center gap-2 rounded-none border border-[hsl(var(--primary)/0.45)] text-foreground transition-colors hover:bg-primary/10 hover:text-primary {% if style == "stack" %}w-full px-4 py-2.5{% else %}p-2.5{% endif %}">
|
||||
{% if link.network %}<svg class="h-5 w-5 text-primary" aria-hidden="true"><use href="/icons/{{ link.network|split:":"|first }}.svg#{{ link.network|split:":"|last }}"></use></svg>{% endif %}
|
||||
{% if style == "stack" and link.label %}<span class="deco-caps text-xs tracking-[0.14em]">{{ link.label }}</span>{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
@ -1,48 +0,0 @@
|
||||
<section data-block-override="art-deco:stats" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}"{% if countUp %} data-stats{% endif %}>
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-center text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<dl class="mt-12 grid grid-cols-2 gap-8 divide-x divide-[hsl(var(--primary)/0.25)] {% if columns == 2 %}md:grid-cols-2{% elif columns == 3 %}md:grid-cols-3{% else %}md:grid-cols-4{% endif %}">
|
||||
{% for item in items %}
|
||||
<div class="px-2 text-center">
|
||||
<dd class="text-4xl font-bold tracking-tight text-primary md:text-5xl" style="font-family:var(--font-heading)">{% if item.prefix %}{{ item.prefix }}{% endif %}<span{% if countUp %} data-countup-value="{{ item.value }}"{% endif %}>{{ item.value }}</span>{% if item.suffix %}{{ item.suffix }}{% endif %}</dd>
|
||||
{% if item.label %}<dt class="deco-caps mt-2 text-xs text-muted-foreground">{{ item.label }}</dt>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
{% if countUp %}<script>
|
||||
(function(){
|
||||
var sections = document.querySelectorAll('[data-stats]');
|
||||
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
function animate(section){
|
||||
var nodes = section.querySelectorAll('[data-countup-value]');
|
||||
nodes.forEach(function(node){
|
||||
var raw = node.getAttribute('data-countup-value') || '';
|
||||
var target = parseFloat(raw.replace(/[^0-9.\-]/g, ''));
|
||||
if (isNaN(target)) return;
|
||||
var decimals = (raw.split('.')[1] || '').length;
|
||||
var start = null, dur = 1200;
|
||||
function step(ts){
|
||||
if (start === null) start = ts;
|
||||
var p = Math.min((ts - start) / dur, 1);
|
||||
var eased = 1 - Math.pow(1 - p, 3);
|
||||
node.textContent = (target * eased).toFixed(decimals);
|
||||
if (p < 1) requestAnimationFrame(step);
|
||||
else node.textContent = target.toFixed(decimals);
|
||||
}
|
||||
requestAnimationFrame(step);
|
||||
});
|
||||
}
|
||||
sections.forEach(function(section){
|
||||
if (reduce || !('IntersectionObserver' in window)) return;
|
||||
var io = new IntersectionObserver(function(entries){
|
||||
entries.forEach(function(e){
|
||||
if (e.isIntersecting){ animate(section); io.disconnect(); }
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
io.observe(section);
|
||||
});
|
||||
})();
|
||||
</script>{% endif %}
|
||||
@ -1,21 +0,0 @@
|
||||
<section data-block-override="art-deco:team" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-center text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<div class="mt-12 {% if layout == "list" %}mx-auto max-w-3xl space-y-6{% elif layout == "single" %}mx-auto max-w-xl{% else %}grid grid-cols-1 gap-8 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% elif columns == 4 %}lg:grid-cols-4{% else %}lg:grid-cols-3{% endif %}{% endif %}">
|
||||
{% for member in members %}
|
||||
<div class="{% if layout == "list" %}deco-frame flex items-start gap-5 bg-card p-5 text-card-foreground{% else %}text-center{% endif %}">
|
||||
{% if member.photo %}<span class="{% if layout == "list" %}h-20 w-20{% else %}mx-auto h-28 w-28{% endif %} block shrink-0 overflow-hidden border border-[hsl(var(--primary)/0.4)] bg-muted">{% img member.photo alt=member.name class="h-full w-full object-cover" %}</span>{% endif %}
|
||||
<div class="{% if layout != "list" %}mt-4{% endif %}">
|
||||
{% if member.name %}<h3 class="deco-caps text-lg text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ member.name }}</h3>{% endif %}
|
||||
{% if member.role %}<p class="deco-caps text-xs text-primary">{{ member.role }}</p>{% endif %}
|
||||
{% if member.bio %}<p class="mt-2 text-sm text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ member.bio }}</p>{% endif %}
|
||||
{% if member.socials %}<div class="mt-3 flex gap-3 {% if layout != "list" %}justify-center{% endif %}">
|
||||
{% for social in member.socials %}{% if social.url %}<a href="{{ social.url }}" class="text-muted-foreground transition-colors hover:text-primary" aria-label="Social link"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ social.icon|split:":"|first }}.svg#{{ social.icon|split:":"|last }}"></use></svg></a>{% endif %}{% endfor %}
|
||||
</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,27 +0,0 @@
|
||||
<section data-block-override="art-deco:testimonial" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-6xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
<div class="mt-12 {% if layout == "single" %}mx-auto max-w-3xl{% elif layout == "carousel" %}flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4{% else %}grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3{% endif %}">
|
||||
{% for q in quotes %}
|
||||
<figure class="deco-frame flex flex-col bg-card p-6 text-card-foreground{% if layout == "carousel" %} min-w-[18rem] max-w-sm shrink-0 snap-start{% endif %}">
|
||||
{% if q.rating %}<div class="mb-3 flex justify-center gap-0.5" aria-label="Rated {{ q.rating }} out of 5">
|
||||
<svg class="h-4 w-4 {% if q.rating >= 1 %}text-primary{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
|
||||
<svg class="h-4 w-4 {% if q.rating >= 2 %}text-primary{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
|
||||
<svg class="h-4 w-4 {% if q.rating >= 3 %}text-primary{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
|
||||
<svg class="h-4 w-4 {% if q.rating >= 4 %}text-primary{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
|
||||
<svg class="h-4 w-4 {% if q.rating >= 5 %}text-primary{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
|
||||
</div>{% endif %}
|
||||
<blockquote class="flex-1 text-center text-lg leading-relaxed" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{% if q.quote %}“{{ q.quote }}”{% endif %}</blockquote>
|
||||
<div class="mx-auto my-4 flex items-center justify-center"><span class="deco-rule w-16"></span></div>
|
||||
<figcaption class="flex items-center justify-center gap-3">
|
||||
{% if q.avatar %}<span class="h-10 w-10 shrink-0 overflow-hidden border border-[hsl(var(--primary)/0.4)] bg-muted">{% img q.avatar alt=q.name class="h-full w-full object-cover" %}</span>{% endif %}
|
||||
<span class="text-center">
|
||||
{% if q.name %}<span class="deco-caps block text-sm text-foreground">{{ q.name }}</span>{% endif %}
|
||||
{% if q.role %}<span class="block text-sm text-muted-foreground">{{ q.role }}</span>{% endif %}
|
||||
</span>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,2 +1 @@
|
||||
{# text override — Cormorant body prose with gilded links. Fields: text, proseClass (mirrors builtin). Dropcap is reserved for the article template, not forced on every text block. #}
|
||||
<div data-block-override="art-deco:text" class="prose max-w-none flex-1 [&_a]:text-primary [&_a]:no-underline [&_a]:border-b [&_a]:border-[hsl(var(--primary))] [&_a:hover]:text-accent {{ proseClass }}" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif);color:hsl(var(--foreground));font-size:1.075rem;line-height:1.75;">{{ text|safe }}</div>
|
||||
<div data-block-override="art-deco:text" data-deco-dropcap="true" class="deco-dropcap prose max-w-none {{ class }}" style="font-family: var(--font-body, "Cormorant Garamond", "Cormorant", Georgia, serif); color: hsl(var(--foreground));">{{ text|safe }}</div>
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
<section data-block-override="art-deco:timeline" class="py-16 md:py-24 bg-background text-foreground{% if class %} {{ class }}{% endif %}">
|
||||
<div class="mx-auto max-w-4xl px-4">
|
||||
{% if heading %}<h2 class="deco-caps text-center text-3xl text-foreground md:text-4xl" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ heading }}</h2>{% endif %}
|
||||
{% if intro %}<p class="mx-auto mt-4 max-w-2xl text-center text-lg text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ intro }}</p>{% endif %}
|
||||
<ol class="mt-12 {% if orientation == "horizontal" %}grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-4{% else %}relative space-y-8 before:absolute before:left-4 before:top-2 before:h-[calc(100%-1rem)] before:w-px before:bg-[hsl(var(--primary)/0.4)]{% endif %}">
|
||||
{% for step in steps %}
|
||||
<li class="{% if orientation == "horizontal" %}text-center{% else %}relative pl-14{% endif %}">
|
||||
<span class="deco-caps flex h-8 w-8 items-center justify-center border border-primary bg-primary text-sm text-primary-foreground {% if orientation == "horizontal" %}mx-auto{% else %}absolute left-0 top-0 ring-4 ring-background{% endif %}">
|
||||
{% if marker == "numbered" %}{{ forloop.counter }}{% elif marker == "dot" %}<span class="h-2 w-2 bg-primary-foreground"></span>{% else %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#flag"></use></svg>{% endif %}
|
||||
</span>
|
||||
<div class="{% if orientation == "horizontal" %}mt-4{% else %}pt-1{% endif %}">
|
||||
{% if step.label %}<p class="deco-caps text-xs text-primary">{{ step.label }}</p>{% endif %}
|
||||
{% if step.title %}<h3 class="deco-caps mt-1 text-lg text-foreground" style="font-family:var(--font-heading, 'Cinzel', 'Italiana', Georgia, serif)">{{ step.title }}</h3>{% endif %}
|
||||
{% if step.text %}<p class="mt-1 text-muted-foreground" style="font-family:var(--font-body, 'Cormorant Garamond', 'Cormorant', Georgia, serif)">{{ step.text }}</p>{% endif %}
|
||||
{% if step.media %}<div class="deco-step mt-3 overflow-hidden">{% img step.media alt=step.title class="w-full h-auto object-cover" %}</div>{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,10 +0,0 @@
|
||||
{# utility-bar override — thin lacquer contact strip, gold text. Fields mirror builtin: variant, showOnMobile, leftItems/rightItems {icon,label,link}. #}
|
||||
{% set ubcls = "bg-foreground text-background" %}
|
||||
{% 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 %}<a href="{{ it.link }}" class="deco-caps inline-flex items-center gap-1.5 hover:text-primary transition-colors">{% if it.icon %}::{{ it.icon }}::{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</a>{% else %}<span class="deco-caps inline-flex items-center gap-1.5">{% if it.icon %}::{{ it.icon }}::{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</span>{% endif %}{% endmacro %}
|
||||
<div data-block-override="art-deco:utility-bar" class="w-full text-[0.7rem] {% if not showOnMobile %}hidden sm:block{% endif %} {{ ubcls }} {{ class }}">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-9 flex items-center justify-between gap-4">
|
||||
<div class="flex items-center gap-5 flex-wrap">{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}</div>
|
||||
<div class="flex items-center gap-5 flex-wrap justify-end">{% for it in rightItems %}{{ ubitem(it) }}{% endfor %}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,23 +0,0 @@
|
||||
{# video-embed override — gold-framed facade; play button in a gold-ringed medallion. Fields + facade JS mirror builtin verbatim: aspect, url, media, poster, title, caption. #}
|
||||
{% with aspect=aspect|default:"16:9" %}<figure data-block-override="art-deco:video-embed" class="bn-video my-8{% if class %} {{ class }}{% endif %}"><div class="deco-step"><div class="bn-video-frame relative w-full overflow-hidden bg-muted {% if aspect == "4:3" %}aspect-[4/3]{% elif aspect == "1:1" %}aspect-square{% elif aspect == "21:9" %}aspect-[21/9]{% else %}aspect-video{% endif %}" data-bn-video data-video-url="{{ url|default:"" }}" data-video-media="{% if media %}{{ media|mediaURL }}{% endif %}"><button type="button" data-bn-video-play class="group absolute inset-0 flex h-full w-full items-center justify-center focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" aria-label="Play video{% if title %}: {{ title }}{% endif %}">{% if poster %}{% img poster alt=title|default:"" class="absolute inset-0 h-full w-full object-cover" %}{% endif %}<span class="absolute inset-0 bg-foreground/10 transition-colors group-hover:bg-foreground/20" aria-hidden="true"></span><span class="deco-foil relative inline-flex h-16 w-16 items-center justify-center rounded-full bg-background/90 text-primary transition-transform group-hover:scale-105 motion-reduce:transform-none">::lucide:play:xl::</span></button></div></div>{% if caption %}<figcaption class="mt-3 text-center text-sm italic" style="color:hsl(var(--muted-foreground));font-family:var(--font-body, 'Cormorant Garamond', Georgia, serif);">{{ caption }}</figcaption>{% endif %}</figure><script>
|
||||
(function(){
|
||||
if(window.__bnVideoFacade)return;window.__bnVideoFacade=true;
|
||||
function yt(u){var m=u.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([\w-]{6,})/);return m?m[1]:null;}
|
||||
function vim(u){var m=u.match(/vimeo\.com\/(?:video\/)?(\d+)/);return m?m[1]:null;}
|
||||
document.addEventListener('click',function(e){
|
||||
var btn=e.target.closest('[data-bn-video-play]');if(!btn)return;
|
||||
var frame=btn.closest('[data-bn-video]');if(!frame)return;
|
||||
e.preventDefault();
|
||||
var url=frame.getAttribute('data-video-url')||'',media=frame.getAttribute('data-video-media')||'',node;
|
||||
var vstyle='position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:rgba(0,0,0,1);';
|
||||
if(media){node=document.createElement('video');node.src=media;node.controls=true;node.autoplay=true;node.setAttribute('playsinline','');node.style.cssText=vstyle;}
|
||||
else{var y=yt(url),v=vim(url),embed;
|
||||
if(y)embed='https://www.youtube-nocookie.com/embed/'+y+'?autoplay=1&rel=0';
|
||||
else if(v)embed='https://player.vimeo.com/video/'+v+'?autoplay=1';
|
||||
if(embed){node=document.createElement('iframe');node.src=embed;node.allow='autoplay; fullscreen; picture-in-picture';node.setAttribute('allowfullscreen','');node.setAttribute('title',btn.getAttribute('aria-label')||'Video');node.style.cssText='position:absolute;inset:0;width:100%;height:100%;border:0;';}
|
||||
else if(url){node=document.createElement('video');node.src=url;node.controls=true;node.autoplay=true;node.setAttribute('playsinline','');node.style.cssText=vstyle;}
|
||||
}
|
||||
if(node){btn.remove();frame.appendChild(node);}
|
||||
});
|
||||
})();
|
||||
</script>{% endwith %}
|
||||
Loading…
x
Reference in New Issue
Block a user