Commit Graph
3 Commits
Author SHA1 Message Date
austinandClaude Opus 5 9e80590687 Everything on the shared names — the copy-paste is gone
The ported markup was written a page at a time, so the same thing was said several ways. Counted before
touching anything: nine variants of the page gutter, seven max-widths, six link styles, two definitions of
an input, and one stray shadow.

Now: `container` (which already centres and pads), `measure`/`measure-wide`, `link`/`link-plain`/
`link-on-dark`, one `field`, `photo`, `page-head`. Nothing in a template writes `bg-white rounded-…
shadow-…` or `underline underline-offset-4` any more — 119 uses of `panel`, 82 of `label`, 52 of
`panel-lift`, 17 of `link`.

TWO REAL FIXES FELL OUT OF IT, not just tidying:

- Every section said `container mx-auto px-4`: `mx-auto` twice, and a px-4 that beat the responsive
  padding inside `container`. The gutter was 16px at every width, including on a 27-inch screen. Removing
  the copy-paste restores sm:px-6 lg:px-8, which is most of why the pages now breathe.
- The public form and the admin had grown two different inputs — cream vs white, ring-2 vs ring-1, py-2.5
  vs py-2, and different text sizes. There is one `field` now, and the same focus ring as everything else.

The admin uses the same names where they are the same thing (`link`, `field`, `h4`, `--radius-*`) and
keeps its own denser buttons, because it is a tool and not a shop front.

53 tests green. Every class used across all nine pages resolves in the compiled stylesheet — that check is
what makes a sweep this size safe to do with a script.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-26 18:43:40 -05:00
austinandClaude Opus 5 6b6ddcea42 A design pass: the type ladder from the logo, and one name per thing
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]>
2026-07-26 18:10:47 -05:00
austinandClaude Opus 5 61f3eb90ff The site renders itself: Thymeleaf pages, and a catering page among them
build-and-publish / build (pull_request) Successful in 2m8s
The public site was a React SPA. It is now server-rendered Thymeleaf, and the goodie box and catering
tables added in the previous commit have a page of their own. The look is unchanged: the templates
carry the same Tailwind classes the components did, and every one of the 241 classes the five pages
use resolves in the compiled stylesheet.

WHAT WENT AWAY. PageMetaController — 148 lines whose only job was to splice per-page <title> and OG
tags into one shell with regular expressions, with a test that read the real index.html so that
reformatting it failed the build instead of silently breaking the rewriting. A page rendered on the
server writes its own head. Also react-router (no client-side routes left), motion, vite-plugin-svgr,
and the SPA fallback (platform.web.spa.enabled=false): with the site server-rendered, forwarding a
mistyped URL to /index.html would answer with a blank admin shell and a 200 instead of the site's own
404 page.

WHAT GOT BETTER ON THE WAY, none of it visible. The category filter is a ?category= link, so every
filtered view is a URL you can send someone and a crawler can reach all forty items instead of the
twelve the default filter showed. The contact form is a form post: the enquiry is recorded before
delivery is attempted, and a refused relay re-renders the page with what the visitor typed still in
the boxes. The mobile menu is a <details> — the React version needed four effects to close on
navigation, close on Escape, stop the page behind it scrolling, and unmount (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 new document cannot inherit an open menu.

THE PUBLIC SITE SHIPS 5 KB OF JAVASCRIPT, and works without it. The product cards are scroll-snap
strips, so the photos swipe on a phone and scroll with a trackpad unaided; gallery.js adds the arrows
and the dots, and creates them itself rather than having the template render controls that would sit
there dead.

Tailwind still needs its compiler, so npm remains a BUILD tool: the CLI compiles the templates into
static/css/site.css at process-classes (so `spring-boot:run` gets it too), and frontend/ now builds
only that stylesheet and the admin. The brand tokens are one file both stylesheets import — the
alternative was the shop front and the screen that edits it drifting a shade apart. The stylesheet URL
carries ?v=<sha>, because one hand-written CSS file has no content hash and a deploy has to be able to
tell a browser that what it cached is stale.

The admin is still React and is untouched, apart from losing the router it no longer needs. It is an
editor, not content.

PlatformContractTest stopped inheriting platform-starter-test's contract and restates it. The shared
version asserts that an unknown path forwards to the SPA shell, which is no longer true here, and its
test methods are package-private so it cannot be overridden. The platform should decide that assertion
from platform.web.spa.enabled — noted in the file.

9 new tests (46 total): every page's real title and og:url, the catalogue and the catering tables in
the HTML rather than fetched afterwards, server-side filtering, the 404, and that a crafted ?about=
link cannot put words of its own choosing in front of a customer.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-26 16:07:01 -05:00