Skip to content

Restore the DatedList's multi-column grid on the cocktails index (#78) - #80

Merged
britt merged 4 commits into
masterfrom
issue-78
Sep 2, 2026
Merged

britt merged 4 commits into
masterfrom
issue-78

Conversation

@britt

@britt britt commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Fixes #78

What was actually wrong

Not a stale cache and not a viewport artifact — reproduced at the reporter's exact viewport (1512×949, DPR 2) against a fresh hugo --gc --minify build.

design/tokens/utilities.css is a lossy export of the component, and the part it lost is the layout.

.ds-dated{display:grid;gap:var(--space-4);margin:var(--space-7) 0;padding:0;list-style:none}

display: grid with no grid-template-columns — one column. components/lists/DatedList.jsx, fetched from the source project with DesignSync, is not:

export function DatedList({ items = [], onSelect, columns = true }) {
  <ul style={{ display: "grid",
               gridTemplateColumns: columns
                 ? "repeat(auto-fit, minmax(var(--grid-min), 1fr))"
                 : "1fr",
               gap: "0 var(--gutter-column)" }}>
    <li style={{ display: "grid", gridTemplateColumns: "150px 1fr",
                 gap: "var(--space-5)", padding: "var(--space-4) 0",}}>
      <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)",}}>
      <a style={{ fontWeight: "var(--weight-semibold)", color: "var(--text-heading)" }}>

columns defaults to true. The archive is supposed to reflow across columns; upstream's own section-index template header says so:

@template name="Section index" description="Dated archive index: title, one-line intro, and a **two-up list of posts**."

A token file cannot express a prop, so the export flattened the component to its columns={false} variant — and the page rendered as one narrow column down the left of a 1440px container.

design/README.md already records this exact class of gap for --col-min / --sidebar / --container-max-wide: "upstream these are supplied per-instance by the React components (inline style), not by the token layer", and any template using the component must supply them. .ds-dated belongs on that list and was not on it.

A first attempt that was wrong

The first commit on this branch wrapped the page in .ds-split and put the title in a rail. It moved the ink from 40% to 65% of the container and looked better, but it left the list one column wide — which is what the issue was about — and it matched neither upstream rendering of this page (CocktailIndex.jsx has no rail; CocktailIndex.dc.html's rail carries ProfileHeader, and both keep PageTitle in the content column). Reverted in the second commit.

The change

assets/css/pages.css only, in the existing ── dated archive ── block. Every value is quoted from DatedList.jsx in a comment, except the two-column ceiling.

.ds-dated repeat(auto-fit, minmax(max(var(--grid-min), (100% - var(--gutter-column)) / 2), 1fr)), gap: 0 var(--gutter-column)
.ds-dated__row padding-block: var(--space-4)utilities.css pads only the bottom and leans on the row gap that is now zero
.ds-dated__row @ ≥641px 150px 1fr, gap: var(--space-5) — the mirror's minmax(120px,180px) + 40px gap left 413px for the title against the component's 463px
.ds-dated__date --text-xs (was --text-sm)
.ds-dated__title drop --font-display / --text-h4; the component sets neither

The two-column cap. The component itself is uncapped auto-fit, which is three columns in a 1319px container. Upstream never sees three because its list sits in a ~1000px column behind a ProfileHeader rail — hence "two-up". Without that rail the cap has to be stated, and it is stated as a floor rather than a fixed repeat(2, …): a track can never be narrower than half the row, so auto-fit cannot place a third; below two full --grid-min columns the --grid-min side of the max() wins again and the grid collapses to one on its own. A fixed two-track grid would instead hold two cramped columns all the way down to the 640px stack.

layouts/cocktails/list.html returns to its pre-#78 structure with an updated comment. Nothing under themes/ or design/tokens/ is touched — the mirror is read-only, and the design system isn't wrong here, the export is.

Verification

before after
.ds-dated grid-template-columns @1512 (none — one column) 629.297px 629.297px
Columns of rows rendered 1 2
.ds-dated__row 180px 1108.83px 150px 463.297px
Titles wrapping to a second line 0 of 14
Rightmost text ink, % of container 40% 84%

Column count swept at 375 / 500 / 640 / 700 / 820 / 900 / 1024 / 1280 / 1440 / 1512 / 1920 / 2560 px in chromium, firefox and webkit — byte-identical in all three. One column to 700px, two from 820px, still two at 2560px.

# Criterion Result
AC1 Reflows with the container, never more than two columns PASS — the sweep above
AC2 Page reads as filled PASS — ink 40% → 84%
AC3 Row is still date + title with a hairline rule PASS150px 463.297px, border-bottom-width: 1px, no title wraps
AC4 Still stacks below 640px — grid and row PASS — both single-track at 375px
AC5 Every recipe listed, newest first, links resolve PASS — 14 rows, descending, all resolve
AC6 themes/ and design/ untouched PASSgit diff --stat origin/master -- themes/ design/ empty
AC7 CI build flags PASS — exit 0, no warnings
AC8 Coverage checks PASSno new allowlist entry; tokens 141/142 accounted for
AC9 check-links.py PASS — 22 pages, none broken
AC10 npm test (scheme + axe) PASS — 24/24
AC11 npm run test:responsive PASS — 7/7, chromium/firefox/webkit × 6 viewports

One trap worth a look in review: pages.css is concatenated after ds/utilities.css, so a flat .ds-dated__row { grid-template-columns: 150px 1fr } outranks utilities.css's own @media (max-width:640px) stack — same specificity, later file — and the row would silently never collapse on a phone. Hence the @media (min-width: 641px) guard, and AC4 checks it.

Not run: tests/visual/baseline.sh / check.sh. Port 1414 is held by an unrelated hugo server in this workspace and the script refuses rather than diff against a stale server. Not in CI, baseline not committed, and it would report a large intentional diff by design.

Left out deliberately

Both are real divergences from upstream's section index; both add content the issue didn't ask for.

  1. PageTitle takes kicker="Cocktails" and meta="14 recipes". The site's .page-header renders neither.
  2. templates/cocktail-index/CocktailIndex.dc.html puts a sticky ProfileHeader rail beside the content — avatar, name, tagline, social links. ui_kits/personal-site/CocktailIndex.jsx has no rail at all. The two upstream sources disagree; this follows the ui_kit, which is also what the site already did.

Also noticed: design/DESIGN-SYSTEM.md says the rail collapses under 900px and the dated index stacks under 600px; utilities.css uses 820px and 640px. The doc isn't authoritative on breakpoints. Not touched.

🤖 Generated with Claude Code

/cocktails/ was the only content page dropping a component straight into a
full-bleed 1440px .ds-container with no rail. .ds-dated was behaving exactly to
spec — measured at the reporter's viewport, .ds-dated__row is 1319px wide with
`grid-template-columns: 180px 1108.83px` — but a date and a three-word drink
name filled the left 40% and the hairline rule ran on across nine hundred empty
pixels. Reproduced locally against a fresh build, so the screenshot was not a
stale cache or a viewport artifact.

Put the page in a .ds-split: title and intro in the rail, the archive beside
them. That is what the design system says the full-bleed width is for —
"Width is spent on a two-column RailLayout […] content beside it", and
"the source site is a single narrow column; the two-column rail is this
system's way of filling the page at desktop width" — and it is what the home
page and every recipe page already do.

Rightmost ink at 1512px goes from 40% to 65% of the container. The list itself
is untouched: same rows, same order, same links, same two-column grid, same
stack at 640px.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 2, 2026

Copy link
Copy Markdown

Deploying britt-github-com with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2fd827d
Status: ✅  Deploy successful!
Preview URL: https://d3881219.britt-github-com.pages.dev
Branch Preview URL: https://issue-78.britt-github-com.pages.dev

View logs

The first pass at this misread the defect. It wrapped the page in a .ds-split
and put the title in a rail, which moved the ink from 40% to 65% of the
container but left the list one column wide — which is what the issue was
about.

The actual cause is that design/tokens/utilities.css is a lossy export of the
component. It has:

  .ds-dated{display:grid;gap:var(--space-4);…}

display:grid with no grid-template-columns — one column. components/lists/
DatedList.jsx, fetched from the source project with DesignSync, is:

  function DatedList({ items = [], onSelect, columns = true }) {
    <ul style={{ display: "grid",
                 gridTemplateColumns: columns
                   ? "repeat(auto-fit, minmax(var(--grid-min), 1fr))"
                   : "1fr",
                 gap: "0 var(--gutter-column)" }}>

columns defaults to true. The archive is supposed to reflow across as many
360px columns as fit — upstream's own section-index template calls the result
"a two-up list of posts". A token file cannot express a prop, so the export
flattened the component to its columns={false} variant, and the page rendered
as one narrow column down the left of a 1440px container.

design/README.md already records this exact class of gap for --col-min,
--sidebar and --container-max-wide: "upstream these are supplied per-instance
by the React components (inline style), not by the token layer", and any
template using the component must supply them. .ds-dated belongs on that list.

So it is restored in pages.css — design/tokens/ is a read-only mirror and the
design system is not wrong here, the export is — along with the row geometry,
date size and title treatment the same component specifies. Titles come off the
display face at --text-h4, which the component never set and which cannot fit
"Slightly Sour Strawberry Smash" in a column of the grid.

The row override is wrapped in @media (min-width: 641px) because pages.css is
concatenated after ds/utilities.css: flat, it would outrank utilities.css's own
640px stack and the row would never collapse on a phone.

1512px: 3 columns, ink 40% -> 94%. 900px: 2 columns. 375px: 1 column, stacked.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@britt britt changed the title Fill the page on the cocktails index (#78) Restore the DatedList's multi-column grid on the cocktails index (#78) Sep 2, 2026
britt and others added 2 commits September 2, 2026 08:59
The DatedList component is uncapped `auto-fit` — as many --grid-min columns as
fit, which is three in a 1319px container. Upstream never sees three because
its list sits in a ~1000px column behind a ProfileHeader rail, and its template
describes the result as "a two-up list of posts". This site has no rail, so the
cap has to be stated.

Stated as a floor rather than a fixed `repeat(2, …)`:

  minmax(max(var(--grid-min), (100% - var(--gutter-column)) / 2), 1fr)

A track can never be narrower than half the row, so auto-fit cannot place a
third column; below two full --grid-min columns the --grid-min side of the
max() wins again and the grid collapses to one on its own. A fixed two-track
grid would instead hold two cramped columns all the way down to the 640px
stack.

Swept 375–2560px in chromium, firefox and webkit: identical in all three. One
column to 700px, two from 820px, still two at 2560px. Titles get 463px instead
of 233px, so none of the fourteen wraps.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@britt
britt merged commit 0ac294e into master Sep 2, 2026
5 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cocktails index page doesn't match design system: single column, doesn't fill page width

1 participant