From 312a77aeb9a8cf62c2cf60a311d6c0aa8831cf92 Mon Sep 17 00:00:00 2001 From: Richie Date: Fri, 17 Apr 2026 15:52:07 +1000 Subject: [PATCH] Polish ComparisonPage mobile cards + page layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ComparisonTabCard: width 210 → 235; recommended badge switched to filled brand + StarRoundedIcon matching the desktop ComparisonColumnCard treatment; removed glow + active glow shadow in favour of the standard shadow-sm; border colour brand-500 → brand-600; pt 2.4 → 3.5. - ComparisonPackageCard: verified badge replaced with inline VerifiedOutlinedIcon to the left of the provider name (matches desktop pattern); warm tint confined to the header (Card body now explicitly white); 2px brand-600 border when recommended; header padding px 2.5 → 3, pt 2.5 → 3, pb 2 → 4; spacing pass across the provider identity / package info / sections groups — Divider my 1.5 → 3, section mb 3 → 5, item py 1.5 → 2, heading→first-item 1.5 → 2.5. - ComparisonPage mobile: Divider between page header and tab rail; "Choose a package to view" h2 heading (user-centric copy), used as aria-labelledby for the tablist; dot indicator below the rail (8px grey, active 24×8 brand-600 pill) — aria-hidden and tabIndex=-1 so the tab rail above remains the canonical accessible navigation. Also leaves the Figma capture script in preview-head.html for future page captures. Co-Authored-By: Claude Opus 4.7 (1M context) --- .storybook/preview-head.html | 1 + docs/memory/component-registry.md | 12 +- docs/memory/session-log.md | 133 ++++++++++++++++++ .../ComparisonPackageCard.tsx | 98 +++++++------ .../ComparisonTabCard/ComparisonTabCard.tsx | 19 +-- 5 files changed, 208 insertions(+), 55 deletions(-) diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index f2662d7..8f1a3b1 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -1,3 +1,4 @@ + ` landmark wrapper. | +| WizardLayout | done | Container + Box + Link + Typography + Navigation (slot) + StepIndicator (slot) | Page-level layout for arrangement wizard. **6 variants**: centered-form, wide-form, list-map, list-detail, grid-sidebar, detail-toggles, **bleed**. `bleed` = viewport-locked + `
` as single scroll container (both axes) + no inner Container; back link routed into children; scroll host marked `data-wizard-scroll` so descendants can find it (IntersectionObserver roots, etc.). Used by ComparisonPage. Nav slot, sticky help bar, optional back link, optional progress stepper + running total. `
` landmark wrapper. | ## Pages @@ -105,7 +105,7 @@ duplicates) and MUST update it after completing one. | ConfirmationStep | done | WizardLayout (centered-form) + Button | Wizard step 15 — confirmation. Terminal page. At-need: "submitted" + callback. Pre-planning: "saved" + return-anytime. Muted success icon. | | UnverifiedProviderStep | done | WizardLayout (list-detail) + ProviderCardCompact + ProviderCard + Badge + Button + Divider + Typography | Unverified provider detail. Left: compact card + "Listing" badge + available info (conditional dl) + verified recommendations. Right: warm header band + detail rows + "Make an Enquiry" CTA. Graceful degradation (no data → straight to enquiry). 4 story variants. | | HomePage | done | FuneralFinderV3/V4 (via finderSlot) + ProviderCardCompact + Button + Typography + Accordion + Divider + Navigation (prop) + Footer (prop) | Marketing landing page. 4 archived versions: V1 (split hero), V2 (full-bleed parsonshero.png), V3 (hero-3.png + updated copy + logo bar + venue photos + warm CTA gradient), V4 (same as V3 but with FuneralFinderV4 stepped form via finderSlot). `finderSlot` prop allows swapping finder widget. Light grey footer (surface.subtle). | -| ComparisonPage (V2) | done | WizardLayout (wide-form) + ComparisonTable + Card + Typography + Button + Divider + StarRoundedIcon | **Production version.** Package comparison page. Desktop: full ComparisonTable with sticky headers, **recommended package as first (leftmost) column**. Mobile: tabbed card view with horizontal tab rail (role="tablist") + single package card (role="tabpanel"); **recommended tab is first in rail, first user-selected package is initially active**. Recommended package as separate prop (D038). Star icon (brand-600) marks recommended in mobile tab labels. Share + Print in page header. Back link, help bar. | +| ComparisonPage (V2) | done | WizardLayout (**bleed** desktop / wide-form mobile) + ComparisonTable + ComparisonTabCard + ComparisonPackageCard + Divider + Typography + Button + Link | **Production version.** Package comparison page, restructured 2026-04-17. **Desktop**: `bleed` WizardLayout variant. Structure: centred page-header container (maxWidth 1200 = `COMPARISON_TABLE_COL_WIDTH × 4`) with own Back link → `` → full-bleed `[spacer][ComparisonTable][spacer]` flex row. When viewport > 1200 spacers centre the table; when a 4th+ package makes the table wider than viewport, spacers collapse to their min-width (16/24px matching the page-header padding) and the table extends rightward with the content's left edge pinned. Recommended package as first (leftmost) column with warm tint + 2px brand-600 border + filled Recommended badge. **Mobile**: `` between page header and tab rail. "Choose a package to view" h2 heading (user-centric), serves as `aria-labelledby` for the tablist. Horizontal tab rail (role="tablist") of `ComparisonTabCard` (235px each) + **dot indicator** below (8px grey dots, active expands to 24×8 brand-600 pill, aria-hidden, tabIndex=-1 — visual supplement to the tab rail which is canonical accessible nav). Single `ComparisonPackageCard` in role="tabpanel"; recommended tab is first in rail, first user-selected package is initially active. Share + Print in page header (desktop). Back link, help bar. | | ComparisonPage V1 | archived | WizardLayout + ComparisonTable + Card + Typography + Button + Divider | Archived — viewable in Storybook under Archive/. Recommended package as **last** column/tab. Same component tree as V2. | ## Future enhancements diff --git a/docs/memory/session-log.md b/docs/memory/session-log.md index 3b102a4..9c89211 100644 --- a/docs/memory/session-log.md +++ b/docs/memory/session-log.md @@ -26,6 +26,139 @@ Each entry follows this structure: ## Sessions +### Session 2026-04-17 — ComparisonPage restructure (scroll model, sticky-left, tiered hover) + card refinements + mobile polish + +**Agent(s):** Claude Opus 4.7 (1M context) + +**Work completed:** + +**Phase A — WizardLayout `bleed` variant (new):** +- Added a 7th layout variant `bleed` for pages that own their own alignment logic. +- Viewport-locked (`height: 100vh; overflow: hidden` on root). `
` becomes the single scroll container (both axes) via `flex: 1; overflow: auto`. +- No inner `Container` — children render full-bleed. +- Back link slot passed into children (like `list-map` / `detail-toggles`) so it scrolls with content. +- `data-wizard-scroll` attribute on the scroll host — used by descendants to find the scroll ancestor (e.g. for IntersectionObserver roots). + +**Phase B — ComparisonPage + ComparisonTable restructure:** +- `ComparisonPage` (desktop) now uses `bleed`. Structure: centred page-header container (maxWidth = `COMPARISON_TABLE_COL_WIDTH × 4` = 1200px) → `` → full-bleed flex row `[spacer][table][spacer]`. Matching horizontal padding (16/24px) between container and spacers keeps content left-edges aligned on all viewports. +- Own `` link inside the page-header container (not `WizardLayout`'s) so it sits under the shared left-edge rather than the raw scroll-host edge. +- `ComparisonTable` rewritten with fixed column widths: `COMPARISON_TABLE_COL_WIDTH = 300` exported as a constant. Natural width = `300 × (packages.length + 1)`. +- Sticky-left on row-label column across every per-section mini-table. Works because each mini-table shares the scroll ancestor (the bleed `
`). +- Tiered hover: base row-cells → `surface-subtle` (#fafafa), recommended column cells → `surface-warm` (#fef9f5). Recommended column has a resting 50%-opacity warm tint that promotes to full warm on row hover (via `color-mix`). +- Per-section mini-tables kept (user preference) with left-accent brand heading. +- "Not Included" rendering: new rule — `unavailable` cell values in sections whose heading matches `OPTIONAL_SECTION_HEADINGS` (currently `Optionals`, `Extras`) render "Not Included" in neutral-500; `Essentials` keeps the em-dash. Meaning: missing in Essentials = "not itemised", missing in Extras = "deliberately absent". +- `CellIconText` local helper introduced for icon+label cell values (complimentary, included, unknown). Sets `lineHeight: 1` on flex container AND Typography so geometric and optical centres align — fixes the icons-sitting-slightly-high visual bug. + +**Phase C (stripped):** Built a collapsing sticky mini-header (IntersectionObserver + sentinel + max-height transition) then removed per user request — they want to revisit later. All machinery (observer, state, sentinel, Button import, z-index const) removed clean. + +**ComparisonColumnCard refinements:** +- Fixed physical height consistency: outer wrapper in ComparisonTable is now `display: flex; flexDirection: column; minWidth: 0`, and the card root receives `flex: 1` so all cards stretch to the tallest grid-row height. +- Top padding inside card bumped from conditional `2.5/3` to uniform `pt: 5` (40px) — significantly more breathing room above the provider name. Bottom padding `pb: 2.5` → `pb: 3`. +- Badge size bumped from `small` (22px) to `medium` (26px) with icon fontSize 14 → 16 and `top: -12` → `-13`. +- Remove link footer: instead of conditional Link-vs-Box, always renders the same `Link` element; visibility-hidden + tabindex=-1 + aria-hidden when no Remove action applies. CTA + footer row layouts now identical across all cards, fixing a sub-pixel CTA-height drift. +- Provider name: wraps to up to 2 lines via `WebkitLineClamp: 2`. Name Box has `minHeight: 36` (= 2 × label-line-height) and `alignItems: flex-end` — 1-line names sit at the bottom of a reserved 2-line slot, so location/rating/price below stay on the same baseline regardless of wrap. +- Inline verified icon adjusted from `mt: 3px` + alignItems:center to `mb: 2px` + alignItems:flex-end to pair with bottom-aligned text. +- Tooltip threshold for long provider names raised from 24 to 50 chars (wrapping handles most cases). +- Internal grouping spacing pass: outer gap `0.5 → 1`, Divider `my: 1 → 1.5`. Price subgroup wrapped in its own sub-Box with `gap: 0.25` so "Total package price" label + amount stay visually joined despite the larger outer gap. Redundant Button `mt: 1.5` and Remove `mt: 0.5` removed. + +**Mobile polish — ComparisonTabCard:** +- Width: 210 → 235 (+25px). +- Recommended badge aligned with desktop: `filled` variant + `StarRoundedIcon`, keeps `size="small"` per user instruction. +- Removed the glow (`0 0 12px rgba(186, 131, 78, 0.3)`) — uses same `var(--fa-shadow-sm)` as other cards. No custom active-recommended glow either. +- Border colour: `brand-500` → `brand-600` (consistent with primary). +- Top padding inside card: 2.4 → 3.5. + +**Mobile polish — ComparisonPackageCard:** +- Badge removed in favour of inline verified icon (consistent with desktop `ComparisonColumnCard` pattern): `VerifiedOutlinedIcon` in brand-600 sits left of provider name in a flex row when `provider.verified` is true. +- Warm background confined to the provider header only: removed `selected={pkg.isRecommended}` from the root Card (it was applying `surface-warm` across the whole card). Explicit `bgcolor: 'background.paper'`. Border: explicit `2px solid brand-600` on the Card when recommended (matches desktop ComparisonColumnCard exactly). +- Header horizontal padding: `px: 2.5 → px: 3`. Top padding `pt: 2.5 → pt: 3`, bottom `pb: 2 → pb: 4`. +- Spacing between groups: badge→name→metadata bumped (mb: 1 → 2, mb: 0.5 → 1.25, mb: 1.5 → 2). Divider `mb: 1.5 → my: 3`. Package-info subgroup wrapped in flex column with `gap: 0.75` between name and price block; inner price block has `gap: 0.25`. Button `mt: 2 → mt: 3`. +- Sections area: `py: 2.5 → pt: 3.5, pb: 3`. Between sections `mb: 3 → mb: 5`. Section heading → first item `mb: 1.5 → mb: 2.5`. Item rows `py: 1.5 → py: 2`. Redundant `mt: 1` on subsequent section headings removed (parent spacing now owns the gap). + +**Mobile polish — ComparisonPage:** +- Added `` between page header (h1 + subhead) and package selector. +- Added `Choose a package to view` as user-centric heading for the tab rail. Hooked up as the tablist's `aria-labelledby`. +- Dot indicator added below the rail: 8×8px grey neutral-300 dots, active dot expands to `24×8px` brand-600 pill (width transition 200ms). Tap-to-navigate. Container is `aria-hidden="true"` with dots having `tabIndex: -1` — purely visual supplement; the tab rail above remains the canonical accessible navigation, avoiding duplicate tabstops for screen reader / keyboard users. +- Tab rail `mb: 3 → 1.5` so dots sit close to the rail they describe. + +**Test data update:** +- `pkgMackay.provider.name` extended to "Mackay Family Funeral Directors & Cremation Services" (52 chars) — exercises the 2-line provider-name wrap in all four comparison stories. + +**Decisions made:** +- **Scroll model A** (single scroll container on main, page header scrolls away) chosen over B (table-internal scroll with page chrome pinned) and C (hybrid). Makes the width-matching left-edge alignment trick work naturally. +- **Sticky columns: row-labels only**, not recommended column. Simpler, preserves horizontal space for other packages on medium screens. +- **Per-section mini-tables kept** — user preferred visual rhythm over single continuous table. +- **Tokens unchanged**: `brand-50` (#fef9f5) and `brand-600` (#b0610f) are exactly what Make's exploration landed on. No token work needed. +- **Collapsing sticky header dropped** — user will revisit. Preserve option; removed all machinery cleanly. +- **Info-icon tooltip on mobile package card**: accepted as exception. Touch-device tooltip UX isn't ideal but info is supplementary. + +**Open questions:** +- None blocking. + +**Next steps:** +- Commit today's work (2 commits: Phase A+B desktop restructure, then card refinements + mobile polish). +- Optional: `/audit` on refreshed ComparisonPage + ComparisonTable; `/critique` on the mobile and desktop views. +- User flagged next focus areas (not started this session): package select page refinements; map pins / map cards (MapCard molecule is still "planned" in the registry). + +--- + +### Session 2026-04-16b — ComparisonColumnCard refinements + +**Agent(s):** Claude Opus 4.6 (1M context) + +**Work completed:** +- **Recommended banner removed** — was causing CTA misalignment between recommended and non-recommended cards. Replaced with a floating "Recommended" badge (primary fill, star icon) that replaces the "Verified" badge (soft, checkmark) when recommended. +- **Card border fix** — selected state was using `brand-500` (via `--fa-card-border-selected` token) which looked inconsistent with the rest of the primary system. Recommended cards now override to `brand-600` to match banner/button primary colour. +- **Inline verified icon** — small `VerifiedOutlinedIcon` in brand-600 now sits to the left of the provider name **only on recommended cards** (recommended providers are always verified). Regular verified providers rely on the top badge alone. +- **No-rating fallback** — when `provider.rating == null`, renders a single `—` in the rating slot to keep card heights consistent across all columns. +- **CTA alignment** — recommended cards now render an invisible `Remove` placeholder (same height) so the primary CTA button aligns with non-recommended cards that do have a Remove link. +- **Remove link dropped to caption** — from `body2` (14px) to `caption` (12px) on both real and spacer versions. +- **Gap between verified icon and provider name** bumped from 0.5 to 0.75. + +**Decisions made:** +- Star (`StarRoundedIcon`) used for Recommended badge icon — reads as "standout" at 14px and differentiates from the Verified checkmark. +- Recommended-card border override is local (sx) rather than a new theme token — the inconsistency is between the token (brand-500) and the rest of the system (brand-600); the right long-term fix is probably updating the token itself. + +**Next steps (tomorrow):** +- Retry Sheffield remote push on next `/publish` (still 502 last session). +- Consider promoting the `brand-500 → brand-600` border fix to the `--fa-card-border-selected` token if it applies broadly. + +--- + +### Session 2026-04-16 — HomePage refinements + Navigation dropdown + hero image + +**Agent(s):** Claude Opus 4.6 (1M context) + +**Work completed:** +- **Navigation organism extended** — `NavItem.children` now supported. Desktop renders dropdown menu (MUI Menu, click-triggered), mobile renders collapsible section in drawer. Story `Organisms/Navigation > WithDropdown` added. +- **Locations nav added** — Melbourne, Brisbane, Sydney, South Coast NSW, Central Coast NSW, placed before FAQ in all four HomePage stories. +- **Hero refinements (HomePage)** — new `hero-couple.jpg` background (compressed 1.4MB → 239KB via ImageMagick `-quality 82 -interlace Plane -strip`); italic tagline "Trusted by thousands of families across Australia" above h1; hero text container widened from md (900px) to 990px; mobile top padding increased; mobile side padding on FuneralFinder bumped from 16px to 24px. +- **Hero h1 typography** — promoted from `display3` (same as section h2s) to `display2` (52px desktop / 24px mobile) for hierarchy contrast. Still renders as semantic `

`. +- **Section overlines added** — "FUNERAL ARRANGER REVIEWS" above "What families are saying"; "WHY USE FUNERAL ARRANGER" above "4 Reasons to use Funeral Arranger" (renamed from "How it works"). Placeholder body copy removed from features section. +- **Features block body copy removed** — "Search local funeral directors, compare transparent pricing..." paragraph removed; body now only renders if explicitly passed. +- **CTA button promoted** — "Start planning" in the "We Are Here When You Need Us" section changed from text/large to contained/medium. +- **Arrow removed** from "Start exploring" text button. +- **FuneralFinderV3 header removed** — form now starts directly at "How can we help"; unused `heading`/`subheading` props deleted; consumers updated. +- **Mobile typography scaling** — body1 paragraphs under display3 headings now scale to 14px on mobile (better hierarchy vs the 22px mobile display3). Applied to Discover, Why Use FA, and Features sections, plus FAQ questions. +- **Why Use FA text block** — centre-aligned on mobile, left-aligned on desktop. +- **HomePage captured to Figma** — node 6061-25005 via capture-to-figma skill. + +**Publishing:** +- Builds 6–9 published to Chromatic across the session. Build 9 is current client-facing: https://69c9f45d915025e56139051e-ktlogciofe.chromatic.com/ +- Asset sync step added to `/publish` skill — new `hero-couple.jpg` picked up automatically. +- Sheffield remote returning 502 intermittently (server-side) — skipped, retry on next publish. + +**Decisions made:** +- `body1` under `display3` gets a mobile fontSize override (14px) rather than adding a new theme variant — the issue is contextual, not systemic. +- Nav dropdown trigger is a plain button (no chevron) per user preference; mobile keeps expand/collapse chevrons because they're tappable affordances. +- Hero image filename convention: short + content-descriptive (`hero-couple.jpg`), not marketing-suffixed. + +**Next steps:** +- Retry Sheffield push on next `/publish`. +- Consider extracting the inline FAQ accordion in HomePage to a shared molecule if used on more pages. + +--- + ### Session 2026-04-13 — Chromatic image hosting + Gitea domain migration **Agent(s):** Claude Opus 4.6 (1M context) diff --git a/src/components/molecules/ComparisonPackageCard/ComparisonPackageCard.tsx b/src/components/molecules/ComparisonPackageCard/ComparisonPackageCard.tsx index 6b8e5a4..8d2ff8d 100644 --- a/src/components/molecules/ComparisonPackageCard/ComparisonPackageCard.tsx +++ b/src/components/molecules/ComparisonPackageCard/ComparisonPackageCard.tsx @@ -9,7 +9,6 @@ import VerifiedOutlinedIcon from '@mui/icons-material/VerifiedOutlined'; import type { SxProps, Theme } from '@mui/material/styles'; import { Typography } from '../../atoms/Typography'; import { Button } from '../../atoms/Button'; -import { Badge } from '../../atoms/Badge'; import { Divider } from '../../atoms/Divider'; import { Card } from '../../atoms/Card'; import type { ComparisonPackage, ComparisonCellValue } from '../../organisms/ComparisonTable'; @@ -125,12 +124,21 @@ export const ComparisonPackageCard = React.forwardRef - {/* Verified badge */} - {pkg.provider.verified && ( - } - sx={{ mb: 1 }} - > - Verified - - )} - - {/* Provider name */} - - {pkg.provider.name} - + {/* Provider name with optional inline verified icon (matches desktop + ComparisonColumnCard treatment) */} + + {pkg.provider.verified && ( + + )} + + {pkg.provider.name} + + {/* Location + Rating */} - + @@ -203,18 +218,22 @@ export const ComparisonPackageCard = React.forwardRef - + - {/* Package name + price */} - - {pkg.name} - - - Total package price - - - {formatPrice(pkg.price)} - + {/* Package info group — name, label, price stacked with small internal gap */} + + + {pkg.name} + + + + Total package price + + + {formatPrice(pkg.price)} + + + {/* Sections — with left accent borders on headings */} - + {pkg.itemizedAvailable === false ? ( @@ -238,15 +257,14 @@ export const ComparisonPackageCard = React.forwardRef ) : ( pkg.sections.map((section, sIdx) => ( - + {/* Section heading with left accent */} 0 ? 1 : 0, + mb: 2.5, }} > @@ -262,7 +280,7 @@ export const ComparisonPackageCard = React.forwardRef - {/* Recommended badge in normal flow — overlaps card via negative mb */} + {/* Recommended badge in normal flow — overlaps card via negative mb. + Matches the desktop ComparisonColumnCard styling (filled brand + + star icon) for consistency between surfaces. */} {pkg.isRecommended ? ( } sx={{ mb: '-10px', zIndex: 1, @@ -89,21 +93,18 @@ export const ComparisonTabCard = React.forwardRef - +