From ff10cff71c3dcc14ff010b7a17d7815a1e5abd56 Mon Sep 17 00:00:00 2001 From: Bowen Liang Date: Sun, 13 Sep 2026 10:09:27 +0800 Subject: [PATCH] refactor(client): fold the responsive layout into Tailwind variants and intrinsic flex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All seven hand-written @container blocks move out of the sheets: the head-band stack, the stats grid's wide/narrow columns, the donut row's gap fold and stack, and the events/file rows' narrow-card wraps now ride @min/@max-[…]/lc-card utilities on the elements (named lc-card / lc-head-row containers). Reviewing that migration against the shared column idiom folded the head band's 720px container query away entirely — the rows were already flex-wrap rows, so the head cards take the same `flex-1 min-w-[min(360px,100%)]` floor as every other column and wrap intrinsically. The count grid became repeat(auto-fit, minmax(108px,1fr)) — 108px is the floor where the longest English label fits — replacing the 700px/320px breakpoints and filling the card at every width instead of jumping 3 to 6 columns. What stays hand-written: the 240px donut stack and 380px row wraps (the ring/legend and the 92px/46px reservations are measured-content facts, and Tailwind's preset container scale is rem-based where this plugin is px-anchored), plus the lc-card container definition whose .lc-root scope deliberately keeps the /context modal's cards container-less. Verified in the browser across 1280/900/736/640/390 in both locales and in the /context modal: same folds at the same widths, no overflow, no horizontal scrollbars. The visible delta is the count grid filling intermediate widths with 4/5 columns. --- src/client/components/contextView.tsx | 15 +++++---- src/client/components/donut.tsx | 2 +- src/client/components/events.tsx | 8 +++-- src/client/components/fileCard.tsx | 10 ++++-- src/client/components/pluginInfo.tsx | 2 +- src/client/components/sliceList.tsx | 2 +- src/client/components/statsContext.tsx | 7 ++-- src/client/components/statsTiming.tsx | 8 +++-- src/client/components/statsTokens.tsx | 6 ++-- src/client/styles/base.css | 35 +++++++------------- src/client/styles/events.css | 12 ------- src/client/styles/fileCard.css | 17 +--------- src/client/styles/stats.css | 46 +++++--------------------- 13 files changed, 60 insertions(+), 110 deletions(-) diff --git a/src/client/components/contextView.tsx b/src/client/components/contextView.tsx index ff7bf7f..4eb48de 100644 --- a/src/client/components/contextView.tsx +++ b/src/client/components/contextView.tsx @@ -509,8 +509,8 @@ export function makeContextView( {/* The head band splits into two rows: the session's shape beside the plugin card, then the two donut cards together. The sidebar panel drops the first row (context stats / plugin info pay off only on - the full-width tab) and keeps the donut row, whose container query - stacks the pair in the narrow pane. */} + the full-width tab); the rows' own flex-wrap stacks the pair in a + narrow pane at the shared 360px card floor. */} {inSidebar ? null : (
-
{compositionCard}{trendCard}
+
{compositionCard}{trendCard}
{/* `lc-col-browser` stretches the browser card to the left column's height; the /context modal, which draws its own stack, must stay content-sized. */} -
{browserCard}
+
{browserCard}
-
+
{t('events.title')}
diff --git a/src/client/components/donut.tsx b/src/client/components/donut.tsx index 4180a2b..d892269 100644 --- a/src/client/components/donut.tsx +++ b/src/client/components/donut.tsx @@ -80,7 +80,7 @@ export function makeDonut(kit: ViewKit): (props: DonutProps) => ReactElement { && arcs.some(a => a.key === props.hoverKey) return (
{ if (props.onHoverKey !== undefined) props.onHoverKey(null) }} > diff --git a/src/client/components/events.tsx b/src/client/components/events.tsx index c5dd9c4..bc02a9d 100644 --- a/src/client/components/events.tsx +++ b/src/client/components/events.tsx @@ -119,11 +119,15 @@ export function makeEventList(kit: ViewKit): (props: EventListProps) => ReactEle : EVENT_ICONS[ev.kind] || '•' // Key on the durable seq alone: the list renders newest-first, so a fresh event lands at index 0 // and an index-bearing key would shift EVERY existing row's key — a full-list remount on every push. + // Narrow cards (phone panes): the single-line row would crush the label and push the meta + // tail into a scrollbar, so the row wraps — the label's near-full-width basis keeps line 1 + // to icon + kind + label, and the meta tail folds onto line 2. The 92px basis reservation + // covers icon + gap + the widest kind chip (both locales) + gap. return ( -
+
{glyph} {t('kind.' + ev.kind)} - {label} + {label} {at !== null ? {at} : null} {ev.tokens ? ( diff --git a/src/client/components/fileCard.tsx b/src/client/components/fileCard.tsx index 322ca38..31b2734 100644 --- a/src/client/components/fileCard.tsx +++ b/src/client/components/fileCard.tsx @@ -156,7 +156,8 @@ export function makeFileCard(kit: ViewKit, settings: ContextSettings): Component ) : (
-
+ {/* The five purpose chips (labels + counts) overflow a ~300px card in English — flow the group to two lines. */} +
{chips.map(c => (