From d14d83ebaaf408581b1814e9be3d0ce529c55f39 Mon Sep 17 00:00:00 2001 From: Maurice Date: Sun, 20 Sep 2026 23:08:41 +0200 Subject: [PATCH] fix(dashboard): a long trip title cannot widen the hero card The hero's content grid had an auto column, which takes the title's min-content width. A title that is one long word made the column, the tools row and the boarding pass as wide as that word, with edit, clone, archive and delete pushed off the card. The column is capped at the card now, and the title breaks inside it and stops at two lines. --- client/src/styles/dashboard.css | 15 ++++++++++++-- client/src/styles/dashboardCss.test.ts | 27 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 client/src/styles/dashboardCss.test.ts diff --git a/client/src/styles/dashboard.css b/client/src/styles/dashboard.css index 3ac27861a..c75cfabdd 100644 --- a/client/src/styles/dashboard.css +++ b/client/src/styles/dashboard.css @@ -187,6 +187,10 @@ .trek-dash .hero-content { position: absolute; inset: 0; z-index: 2; padding: 32px 32px 26px; display: grid; grid-template-rows: auto 1fr auto; color: #fff; + /* The one column may not grow past the hero. An auto track takes the title's + min-content width, and a title that is one long word made the track, the tools + row and the boarding pass as wide as that word, with the tools off the card. */ + grid-template-columns: minmax(0, 1fr); } .trek-dash .hero-top { display: flex; justify-content: space-between; align-items: start; } .trek-dash .hero-badge { @@ -221,14 +225,21 @@ } .trek-dash .hero-tool:hover { background: oklch(0.22 0.01 260 / .78); transform: scale(1.05); } .trek-dash .hero-tool svg { width: 17px; height: 17px; } -.trek-dash .hero-title-block { align-self: end; padding-bottom: 24px; } +.trek-dash .hero-title-block { align-self: end; padding-bottom: 24px; min-width: 0; } .trek-dash .hero-eyebrow { display: inline-flex; align-items: center; gap: 10px; font-size: 11.5px; letter-spacing: 0.22em; text-transform: uppercase; opacity: .88; margin-bottom: 16px; font-weight: 500; } .trek-dash .hero-eyebrow::before { content: ""; width: 28px; height: 1px; background: oklch(1 0 0 / .6); } -.trek-dash .hero-title { font-size: 104px; font-weight: 600; line-height: 0.9; letter-spacing: -0.045em; margin: 0; text-shadow: 0 1px 12px oklch(0 0 0 / .32), 0 1px 3px oklch(0 0 0 / .4); } +.trek-dash .hero-title { + font-size: 104px; font-weight: 600; line-height: 0.9; letter-spacing: -0.045em; margin: 0; + text-shadow: 0 1px 12px oklch(0 0 0 / .32), 0 1px 3px oklch(0 0 0 / .4); + /* Two lines at most, a word longer than the card broken inside it: the rows above + and below have a fixed budget and a third line would run into the badge row. */ + overflow-wrap: anywhere; + display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; +} /* ----------------- boarding pass ----------------- */ /* The pass is split into an outer wrapper (left notch) and an inner glass panel diff --git a/client/src/styles/dashboardCss.test.ts b/client/src/styles/dashboardCss.test.ts new file mode 100644 index 000000000..c50a55743 --- /dev/null +++ b/client/src/styles/dashboardCss.test.ts @@ -0,0 +1,27 @@ +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' +import { describe, it, expect } from 'vitest' + +// jsdom lays nothing out, so the rules themselves are the assertion, the way +// releaseNoticeCss.test.ts pins the notice's stacking. +describe('dashboard css', () => { + const css = readFileSync(resolve(process.cwd(), 'src/styles/dashboard.css'), 'utf8') + const block = (selector: string): string => { + const at = css.indexOf(selector) + expect(at, `${selector} missing from dashboard.css`).toBeGreaterThan(-1) + return css.slice(at, css.indexOf('}', at) + 1) + } + + it('FE-DASH-CSS-001: a hero title that is one long word cannot widen the card', () => { + // Reported from Discord: with a title like "asdaaaa…" the tools row and the + // boarding pass grew to the width of the word, and edit, clone, archive and + // delete sat off the card. The grid column may not grow past the hero, and the + // title breaks inside the card and stops at two lines. + expect(block('.trek-dash .hero-content {')).toMatch(/grid-template-columns:\s*minmax\(0,\s*1fr\)/) + expect(block('.trek-dash .hero-title-block {')).toMatch(/min-width:\s*0/) + const title = block('.trek-dash .hero-title {') + expect(title).toMatch(/overflow-wrap:\s*anywhere/) + expect(title).toMatch(/-webkit-line-clamp:\s*2/) + expect(title).toMatch(/overflow:\s*hidden/) + }) +})