Sections and cards: three grids, two quiet panels and five headings become three names

Counted first, as with the last sweep. A grid of cards was written three times with three different sets
of breakpoints and gaps, so cards on different pages lined up differently for no reason anyone chose. A
tinted aside card existed twice, hand-rolled, with different borders. A section heading existed five ways:
centred with one margin, centred with another, left-aligned with a blurb, left without.

Now `card-grid`, `panel-quiet` and a `section-head` fragment (with a cream-on-sage twin for the dark
bands). The catering small print and the contact page's "ordering for a crowd?" card are the same object
now, which is what they always were.

TWO THINGS THE SCREENSHOTS DECIDED, not taste:

Three prices go three-up from md, while the shared card grid waits for lg. A grid of photos is fine
two-wide; three prices are a comparison, and 2 + 1 on a laptop strands the third size on its own row.

And the per-table column count is entirely in one classappend rather than overriding `card-grid`, because
Tailwind emits grid-cols-1, -2, -3 in that order — so a `grid-cols-3` from the shared class beats a
`grid-cols-2` written beside it in the markup, whatever the markup says. Two classes for one property,
winner decided by the stylesheet: the same trap that stopped `hidden` from hiding the open-now line, and I
had already written it before catching it. A one-size and a two-size table were both wrong; proved the fix
by building a real two-size table through the admin and looking at it, then deleting it again.

61 tests.
This commit is contained in:
2026-07-26 21:15:37 -05:00
parent e10da662a0
commit e35434a609
6 changed files with 59 additions and 16 deletions
+15 -9
View File
@@ -34,18 +34,24 @@
alignment the aggregate guarantees.
*/-->
<section th:each="table : ${menu.packages}">
<header class="measure text-center">
<h2 class="h2 text-bakery-900" th:text="${table.name}">Office boxes</h2>
<p th:if="${table.blurb}" class="mt-3 text-bakery-700 leading-relaxed" th:text="${table.blurb}">
Mini pastries for a morning meeting.
</p>
</header>
<div th:replace="~{fragments/opening :: section-head(${table.name}, ${table.blurb})}"></div>
<!--/* Three sizes is the common case; a table with one or two shouldn't stretch to fill the row. */-->
<div class="mt-8 grid gap-6 md:gap-8"
<!--/*
Three sizes go three-up from md, not lg like the shared `card-grid`: a grid of PHOTOS is fine
two-wide, but three prices are a comparison, and landing 2 + 1 on a laptop strands the third
size on its own row where it reads as an afterthought.
The column count is entirely in the classappend rather than overriding `card-grid`, and that
is not a style preference: Tailwind emits grid-cols-1, -2, -3 in that order, so `grid-cols-3`
from the shared class would beat a `grid-cols-2` written next to it in the markup. Two classes
for one property, with the winner decided by the stylesheet's order — the same trap that made
`hidden` fail to hide the open-now line. Never both.
*/-->
<div class="grid gap-6 md:gap-8 mt-8"
th:classappend="${#lists.size(table.tiers) == 1} ? 'max-w-sm mx-auto'
: (${#lists.size(table.tiers) == 2} ? 'sm:grid-cols-2 max-w-3xl mx-auto'
: 'sm:grid-cols-2 lg:grid-cols-3')">
: 'sm:grid-cols-2 md:grid-cols-3')">
<article th:each="tier, t : ${table.tiers}"
class="relative flex flex-col overflow-hidden panel">
<!--/* The wordmark's branch, at watermark weight. */-->
@@ -89,7 +95,7 @@
three cards led to the same place, since an enquiry is about the table rather than the size,
and the label read "Ask about the 1520 people" on the tables whose sizes are headcounts.
*/-->
<div class="mt-8 measure rounded-panel border border-bakery-200/70 bg-bakery-50/60 px-6 py-6 text-center">
<div class="panel-quiet mt-8 measure px-6 py-6 text-center">
<div th:if="${!#lists.isEmpty(table.notes)}">
<h3 class="label text-bakery-500">Good to know</h3>
<ul class="mt-3 space-y-2 text-sm text-bakery-700">
+1 -1
View File
@@ -89,7 +89,7 @@
<div class="mt-4 text-bakery-800"
th:replace="~{fragments/visit :: address('link-plain')}"></div>
</div>
<div class="rounded-panel border border-bakery-200 p-6 md:p-8">
<div class="panel-quiet p-6 md:p-8">
<h2 class="h4 text-bakery-900">Ordering for a crowd?</h2>
<p class="mt-2 text-sm text-bakery-700 leading-relaxed">
Goodie boxes, party packages and wedding desserts have their own page, with sizes and prices.
@@ -36,6 +36,24 @@
<p class="lede mt-4 measure text-bakery-800" th:text="${lede}">One line about the page.</p>
</header>
<!--/*
How a section begins, as opposed to a page: the title, centred, and optionally a line under it. Pass an
empty string for no line.
It was five different pieces of markup — centred with one margin, centred with another, left-aligned
with a blurb — for what is one idea repeated down every page.
*/-->
<div th:fragment="section-head(title, blurb)" class="measure text-center">
<h2 class="h2 text-bakery-900" th:text="${title}">What people come in for</h2>
<p th:if="${!#strings.isEmpty(blurb)}" class="mt-3 text-bakery-700 leading-relaxed" th:text="${blurb}">A line.</p>
</div>
<!--/* The same, on the sage bands, where the type is cream. */-->
<div th:fragment="section-head-dark(title, blurb)" class="measure text-center">
<h2 class="h2" th:text="${title}">Before you order</h2>
<p th:if="${!#strings.isEmpty(blurb)}" class="mt-3 text-bakery-100 leading-relaxed" th:text="${blurb}">A line.</p>
</div>
<!--/* The branch from the wordmark, between one part of a page and the next. */-->
<div th:fragment="divider" class="flex justify-center" aria-hidden="true">
<span class="mark mark-r w-12 h-12 text-bakery-400"></span>
+5 -5
View File
@@ -45,8 +45,8 @@
<!--/* What people come in for */-->
<section class="section bg-bakery-50">
<div class="container">
<h2 class="h2 text-center text-bakery-900 mb-12">What people come in for</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 md:gap-8">
<div class="mb-12" th:replace="~{fragments/opening :: section-head('What people come in for', '')}"></div>
<div class="card-grid">
<div th:each="item : ${ {'Cinnamon Rolls', 'Sugar Cookies', 'Cakes'} }"
class="panel overflow-hidden text-center">
<!--/* The filenames carry the spaces in these names; SitePhotos encodes them. */-->
@@ -88,8 +88,8 @@
<section class="section bg-bakery-800 text-white">
<div class="container">
<div class="measure text-center">
<h2 class="h2 mb-8">Our story</h2>
<p class="lede text-bakery-100 mb-8">
<h2 class="h2">Our story</h2>
<p class="lede mt-4 text-bakery-100 mb-8">
Morissa Bennett opened The Vine in 2024. We bake in our own kitchen on Main Street:
cinnamon rolls, cookies, custom cakes, sandwiches, paninis, and coffee.
</p>
@@ -103,7 +103,7 @@
<!--/* Visit us */-->
<section id="visit" class="section bg-bakery-50 scroll-mt-24">
<div class="container">
<h2 class="h2 text-center text-bakery-900 mb-12">Visit us</h2>
<div class="mb-12" th:replace="~{fragments/opening :: section-head('Visit us', '')}"></div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 measure-wide">
<div class="panel p-6 md:p-8">
<h2 class="h3 text-bakery-900 mb-6">Our hours</h2>
+1 -1
View File
@@ -26,7 +26,7 @@
<!--/* Deliberately unanimated, as before: filtering used to run a layout reflow plus an enter/exit
fade on every card, which on a 40-card grid reads as the page lurching rather than
responding. The only motion left is the shadow on hover. */-->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div class="card-grid">
<div th:each="product : ${products}"
class="panel overflow-hidden">
<div class="relative w-full overflow-hidden">