Batch 2: List-map layout rework — 420px fixed column, sticky headers

- WizardLayout ListMapLayout: 420px fixed left column (D-B), flex:1
  right panel, back link rendered inside left panel instead of above
  the split (eliminates gap above map)
- LAYOUT_MAP type updated to accept backLink prop for list-map variant
- ProvidersStep: heading + search + filters wrapped in sticky Box
  that pins at top of scrollable left panel while card list scrolls
- VenueStep: same sticky header treatment, heading moved inside form
  for consistent wrapper structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 22:18:52 +11:00
parent 6ebd52f36f
commit 1c3cdbc101
3 changed files with 134 additions and 94 deletions

View File

@@ -146,7 +146,18 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
)
}
>
{/* Header */}
{/* Sticky header — stays pinned while card list scrolls */}
<Box
sx={{
position: 'sticky',
top: 0,
zIndex: 1,
bgcolor: 'background.default',
pb: 1,
mx: -3,
px: 3,
}}
>
<Typography variant="display3" component="h1" sx={{ mb: 0.5 }} tabIndex={-1}>
Choose a funeral provider
</Typography>
@@ -185,11 +196,12 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
<Typography
variant="caption"
color="text.secondary"
sx={{ mb: 2, display: 'block' }}
sx={{ mb: 0, display: 'block' }}
aria-live="polite"
>
{providers.length} provider{providers.length !== 1 ? 's' : ''} found
</Typography>
</Box>
{/* Error message */}
{error && (

View File

@@ -193,7 +193,27 @@ export const VenueStep: React.FC<VenueStepProps> = ({
)
}
>
{/* Page heading */}
<Box
component="form"
noValidate
aria-busy={loading}
onSubmit={(e: React.FormEvent) => {
e.preventDefault();
if (!loading) onContinue();
}}
>
{/* Sticky header — stays pinned while card list scrolls */}
<Box
sx={{
position: 'sticky',
top: 0,
zIndex: 1,
bgcolor: 'background.default',
pb: 1,
mx: -3,
px: 3,
}}
>
<Typography variant="display3" component="h1" sx={{ mb: 0.5 }} tabIndex={-1}>
Where would you like the service?
</Typography>
@@ -204,17 +224,8 @@ export const VenueStep: React.FC<VenueStepProps> = ({
: 'Choose a venue for the funeral service. You can filter by location, features, and religion.'}
</Typography>
<Box
component="form"
noValidate
aria-busy={loading}
onSubmit={(e: React.FormEvent) => {
e.preventDefault();
if (!loading) onContinue();
}}
>
{/* ─── Search + Filters ─── */}
<Box sx={{ mb: 3 }}>
<Box sx={{ mb: 2 }}>
<TextField
placeholder="Search a town or suburb..."
value={values.search}
@@ -243,10 +254,11 @@ export const VenueStep: React.FC<VenueStepProps> = ({
</Box>
{/* ─── Results count ─── */}
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }} aria-live="polite">
<Typography variant="body2" color="text.secondary" sx={{ mb: 0 }} aria-live="polite">
Found {venues.length} venue{venues.length !== 1 ? 's' : ''}
{locationName ? ` near ${locationName}` : ''}
</Typography>
</Box>
{/* ─── Venue card grid ─── */}
<Box

View File

@@ -142,11 +142,12 @@ const CenteredFormLayout: React.FC<{ children: React.ReactNode }> = ({ children
</Container>
);
/** List + Map: ~40% scrollable list (left) / ~60% map (right) */
/** List + Map: 420px fixed scrollable list (left) / flex map (right) — D-B */
const ListMapLayout: React.FC<{
children: React.ReactNode;
secondaryPanel?: React.ReactNode;
}> = ({ children, secondaryPanel }) => (
backLink?: React.ReactNode;
}> = ({ children, secondaryPanel, backLink }) => (
<Box
sx={{
display: 'flex',
@@ -156,18 +157,20 @@ const ListMapLayout: React.FC<{
>
<Box
sx={{
width: { xs: '100%', md: '40%' },
width: { xs: '100%', md: 420 },
flexShrink: 0,
overflowY: 'auto',
px: { xs: 2, md: 3 },
py: 3,
}}
>
{backLink}
{children}
</Box>
<Box
sx={{
display: { xs: 'none', md: 'block' },
width: '60%',
display: { xs: 'none', md: 'flex' },
flex: 1,
position: 'relative',
}}
>
@@ -246,7 +249,11 @@ const DetailTogglesLayout: React.FC<{
const LAYOUT_MAP: Record<
WizardLayoutVariant,
React.FC<{ children: React.ReactNode; secondaryPanel?: React.ReactNode }>
React.FC<{
children: React.ReactNode;
secondaryPanel?: React.ReactNode;
backLink?: React.ReactNode;
}>
> = {
'centered-form': CenteredFormLayout,
'list-map': ListMapLayout,
@@ -313,8 +320,8 @@ export const WizardLayout = React.forwardRef<HTMLDivElement, WizardLayoutProps>(
{/* Stepper + running total bar (grid-sidebar, detail-toggles only) */}
{showStepper && <StepperBar stepper={progressStepper} total={runningTotal} />}
{/* Back link — inside a container for consistent alignment */}
{showBackLink && (
{/* Back link — inside left panel for list-map, above content for others */}
{showBackLink && variant !== 'list-map' && (
<Container
maxWidth={variant === 'centered-form' ? 'sm' : 'lg'}
sx={{ pt: 2, px: { xs: 4, md: 3 } }}
@@ -325,7 +332,16 @@ export const WizardLayout = React.forwardRef<HTMLDivElement, WizardLayoutProps>(
{/* Main content area */}
<Box component="main" sx={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
<LayoutComponent secondaryPanel={secondaryPanel}>{children}</LayoutComponent>
<LayoutComponent
secondaryPanel={secondaryPanel}
backLink={
showBackLink && variant === 'list-map' ? (
<BackLink label={backLabel} onClick={onBack} />
) : undefined
}
>
{children}
</LayoutComponent>
</Box>
{/* Sticky help bar */}