Archived
TYPOGRAPHY, taken from the lockup and walked down to something you can read a paragraph in. "The Vine" in LeJour Script over COFFEEHOUSE + BAKERY in AdBhashitha is the whole brand voice, so: the script stays in the wordmark and nowhere else (it is unreadable at length); AdBhashitha carries h1–h4 and the price, and keeps the wordmark's 0.01em letter-spacing so a heading sits on the same rhythm as the logo above it; `eyebrow` and `label` are the hinge — sans, but letterspaced like the tagline — and then plain Raleway. Sizes are declared once in type.css instead of being re-chosen per template, and none of the type classes set a colour, because the same heading appears in sage on cream and in cream on sage. BUTTONS AND SURFACES have names now. `panel` is the white box that was "bg-white rounded-3xl shadow-xs" written out in nine places (which is how two of them end up with different corners); `panel-lift` is one that reacts. `pill` is one shape in four colourways, which exist because this site puts buttons on cream AND on sage and they cannot be the same colour on both. `chip`/`chip-on` are the products filter. RHYTHM: `section` (py-16 md:py-24) and `band` (py-14 md:py-20, tighter because a coloured strip is already doing the separating) replace nine hand-picked paddings. FOCUS: one visible ring for everything reachable by keyboard, as an outline rather than a shadow so it works on cream, on white and on the sage bands, at zero specificity so a utility can still win. Z-INDEX: written down in base.css, all two of it — 40 the sticky header, 30 the mobile panel, which is a child of the header and so can only ever sit under the bar. Everything else stacks in document order. The point of the comment is that a third layer doesn't get invented at 9999. DROPDOWNS: the admin's category selects were drawing the platform's own arrow in the platform's grey; they get the site's chevron and room for it. 53 tests green. Every class used across all nine pages — five public, four admin — resolves in the compiled stylesheet, so nothing here is styled by a name that doesn't exist. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
59 lines
3.0 KiB
HTML
59 lines
3.0 KiB
HTML
<!DOCTYPE html>
|
|
<html xmlns:th="http://www.thymeleaf.org">
|
|
<body>
|
|
<!--/*
|
|
The sticky bar, and the mobile menu.
|
|
|
|
The menu is a <details> element. That is not a trick to avoid writing JavaScript for its own sake —
|
|
the React version needed an effect to close the panel on navigation, another to close it on Escape,
|
|
another to stop the page behind it scrolling, and a third to unmount it (a panel parked off-screen
|
|
still extends the scrollable area, which is how you used to be able to scroll sideways and find the
|
|
menu). A <details> closes on Escape by itself, and navigation is a new document, so it cannot survive
|
|
it. Nothing to remember, nothing to clean up.
|
|
|
|
The panel is `absolute` and starts below the bar (`top-full`), so the logo and the toggle stay put and
|
|
the panel needs no second copy of either. It must not be `fixed`: the header carries `backdrop-blur`,
|
|
and a backdrop-filter makes an element a containing block for fixed descendants — a fixed panel in
|
|
here would resolve against the 80px header box and get clipped to a sliver.
|
|
*/-->
|
|
<header th:fragment="header" class="sticky top-0 z-40 bg-bakery-50/90 backdrop-blur border-b border-bakery-200">
|
|
<div class="container mx-auto px-4">
|
|
<div class="flex items-center justify-between gap-2 h-20 md:h-24">
|
|
<div th:replace="~{fragments/lockup :: small('text-bakery-700')}"></div>
|
|
|
|
<nav class="hidden md:flex items-center gap-8">
|
|
<th:block th:replace="~{:: links('label text-bakery-700 hover:text-bakery-900 transition-colors')}"></th:block>
|
|
</nav>
|
|
|
|
<details class="group md:hidden shrink-0">
|
|
<summary class="p-2 cursor-pointer list-none" aria-label="Menu">
|
|
<svg class="h-6 w-6 text-bakery-700 group-open:hidden" fill="none" stroke-linecap="round"
|
|
stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
|
<path d="M4 6h16M4 12h16M4 18h16" />
|
|
</svg>
|
|
<svg class="h-6 w-6 text-bakery-700 hidden group-open:block" fill="none" stroke-linecap="round"
|
|
stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
|
<path d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</summary>
|
|
<div class="absolute inset-x-0 top-full z-30 h-[calc(100dvh-5rem)] bg-bakery-50">
|
|
<nav class="container mx-auto px-4 flex flex-col">
|
|
<th:block th:replace="~{:: links('text-bakery-800 hover:text-bakery-600 transition py-4 text-lg border-b border-bakery-100')}"></th:block>
|
|
</nav>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!--/* One list of links, worn two ways — so the phone and the desktop can't end up offering different
|
|
pages. */-->
|
|
<th:block th:fragment="links(itemClass)">
|
|
<a href="/products" th:class="${itemClass}">Our Products</a>
|
|
<a href="/catering" th:class="${itemClass}">Catering</a>
|
|
<a href="/history" th:class="${itemClass}">Our Story</a>
|
|
<a href="/contact" th:class="${itemClass}">Contact</a>
|
|
</th:block>
|
|
</body>
|
|
</html>
|