Files
Parsons/src/components/templates/WizardLayout/WizardLayout.stories.tsx
Richie 43f0360252 Add WizardLayout template with 5 layout variants
- centered-form: single column ~600px for form steps (intro, auth, etc.)
- list-map: 40/60 split for provider search (card list + map)
- list-detail: 40/60 master-detail for package selection
- grid-sidebar: 25/75 filter sidebar + card grid (coffins)
- detail-toggles: 50/50 hero image + product info (venue/coffin details)

Common elements: nav slot, sticky help bar, optional back link,
optional progress stepper + running total (grid-sidebar, detail-toggles).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 14:15:41 +11:00

425 lines
13 KiB
TypeScript

import type { Meta, StoryObj } from '@storybook/react';
import { WizardLayout } from './WizardLayout';
import Box from '@mui/material/Box';
import { Typography } from '../../atoms/Typography';
import { Button } from '../../atoms/Button';
import { Divider } from '../../atoms/Divider';
import { Navigation } from '../../organisms/Navigation';
import { StepIndicator } from '../../molecules/StepIndicator';
// ─── Helpers ─────────────────────────────────────────────────────────────────
const FALogo = () => (
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Box
component="img"
src="/brandlogo/logo-full.svg"
alt="Funeral Arranger"
sx={{ height: 28, display: { xs: 'none', md: 'block' } }}
/>
<Box
component="img"
src="/brandlogo/logo-short.svg"
alt="Funeral Arranger"
sx={{ height: 28, display: { xs: 'block', md: 'none' } }}
/>
</Box>
);
const nav = (
<Navigation
logo={<FALogo />}
items={[
{ label: 'FAQ', href: '/faq' },
{ label: 'Contact Us', href: '/contact' },
{ label: 'Log in', href: '/login' },
]}
/>
);
const stepper = (
<StepIndicator
steps={[
{ label: 'Details' },
{ label: 'Service' },
{ label: 'Venue' },
{ label: 'Coffin' },
{ label: 'Extras' },
]}
currentStep={2}
/>
);
const runningTotal = (
<Box
sx={{
bgcolor: 'background.paper',
border: '1px solid',
borderColor: 'divider',
borderRadius: 1,
px: 2,
py: 0.75,
display: 'flex',
alignItems: 'center',
gap: 1,
}}
>
<Typography variant="body2" color="text.secondary">
Your plan
</Typography>
<Typography variant="h6" color="primary.main">
$3,600
</Typography>
</Box>
);
const PlaceholderCard: React.FC<{ title: string; height?: number }> = ({ title, height = 100 }) => (
<Box
sx={{
p: 3,
mb: 2,
bgcolor: 'background.paper',
borderRadius: 1,
border: '1px solid',
borderColor: 'divider',
minHeight: height,
}}
>
<Typography variant="h6">{title}</Typography>
<Typography variant="body2" color="text.secondary">
Placeholder content for layout demonstration.
</Typography>
</Box>
);
// ─── Meta ────────────────────────────────────────────────────────────────────
const meta: Meta<typeof WizardLayout> = {
title: 'Templates/WizardLayout',
component: WizardLayout,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen',
},
argTypes: {
variant: {
control: 'select',
options: ['centered-form', 'list-map', 'list-detail', 'grid-sidebar', 'detail-toggles'],
description: 'Layout variant',
table: { defaultValue: { summary: 'centered-form' } },
},
showBackLink: { control: 'boolean' },
hideHelpBar: { control: 'boolean' },
backLabel: { control: 'text' },
helpPhone: { control: 'text' },
},
};
export default meta;
type Story = StoryObj<typeof WizardLayout>;
// ─── Centered Form ──────────────────────────────────────────────────────────
/** Step 1 (Intro) style — single centered column, no back link, no progress stepper */
export const CenteredForm: Story = {
args: {
variant: 'centered-form',
navigation: nav,
},
render: (args) => (
<WizardLayout {...args}>
<Typography variant="h4" sx={{ mb: 1 }}>
Let&apos;s get started
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 4 }}>
We&apos;ll guide you through arranging a funeral, step by step.
</Typography>
<Box sx={{ mb: 3 }}>
<Typography variant="label" sx={{ mb: 1, display: 'block' }}>
Who is this funeral being arranged for?
</Typography>
<Box sx={{ display: 'flex', gap: 2 }}>
<Button variant="soft" color="secondary" size="large" fullWidth>
Myself
</Button>
<Button variant="soft" color="secondary" size="large" fullWidth>
Someone else
</Button>
</Box>
</Box>
<Divider sx={{ my: 4 }} />
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button variant="contained" size="large">
Continue
</Button>
</Box>
</WizardLayout>
),
};
// ─── Centered Form with Back ────────────────────────────────────────────────
/** Form step with back link (e.g. date/time, payment) */
export const CenteredFormWithBack: Story = {
args: {
variant: 'centered-form',
navigation: nav,
showBackLink: true,
backLabel: 'Back',
},
render: (args) => (
<WizardLayout {...args}>
<Typography variant="h4" sx={{ mb: 1 }}>
Date and time
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 4 }}>
When would you like the service to take place?
</Typography>
<PlaceholderCard title="Date picker" height={200} />
<PlaceholderCard title="Time selector" />
<Divider sx={{ my: 4 }} />
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button variant="contained" size="large">
Continue
</Button>
</Box>
</WizardLayout>
),
};
// ─── List + Map ──────────────────────────────────────────────────────────────
/** Provider search — scrollable card list with map panel */
export const ListMap: Story = {
args: {
variant: 'list-map',
navigation: nav,
showBackLink: true,
},
render: (args) => (
<WizardLayout
{...args}
secondaryPanel={
<Box
sx={{
bgcolor: 'var(--fa-color-sage-200)',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Typography variant="body1" color="text.secondary">
Map placeholder
</Typography>
</Box>
}
>
<Typography variant="h5" sx={{ mb: 0.5 }}>
Choose a funeral provider
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
Explore providers near you
</Typography>
<PlaceholderCard title="Search bar + filters" height={48} />
<Typography variant="caption" color="text.secondary" sx={{ mb: 2, display: 'block' }}>
Showing results from 5 providers
</Typography>
{Array.from({ length: 4 }).map((_, i) => (
<PlaceholderCard key={i} title={`Provider ${i + 1}`} />
))}
</WizardLayout>
),
};
// ─── List + Detail ───────────────────────────────────────────────────────────
/** Package selection — list left, detail panel right */
export const ListDetail: Story = {
args: {
variant: 'list-detail',
navigation: nav,
showBackLink: true,
},
render: (args) => (
<WizardLayout
{...args}
secondaryPanel={
<Box>
<Typography variant="h5" sx={{ mb: 1 }}>
Everyday Funeral Package
</Typography>
<Typography variant="h4" color="primary.main" sx={{ mb: 3 }}>
$2,700
</Typography>
<Button variant="contained" size="large" fullWidth sx={{ mb: 3 }}>
Select Package
</Button>
<Divider sx={{ mb: 2 }} />
{['Essentials', 'Complimentary Items', 'Extras'].map((section) => (
<Box key={section} sx={{ mb: 3 }}>
<Typography variant="label" sx={{ mb: 1, display: 'block' }}>
{section}
</Typography>
{Array.from({ length: 3 }).map((_, i) => (
<PlaceholderCard key={i} title={`Item ${i + 1}`} height={40} />
))}
</Box>
))}
</Box>
}
>
<PlaceholderCard title="Provider card (compact)" height={80} />
<Typography variant="h6" sx={{ mb: 2 }}>
Packages
</Typography>
{Array.from({ length: 4 }).map((_, i) => (
<PlaceholderCard key={i} title={`Package ${i + 1}$${900 * (i + 1)}`} />
))}
</WizardLayout>
),
};
// ─── Grid + Sidebar ──────────────────────────────────────────────────────────
/** Coffin selection — filter sidebar + responsive card grid */
export const GridSidebar: Story = {
args: {
variant: 'grid-sidebar',
navigation: nav,
showBackLink: true,
progressStepper: stepper,
runningTotal: runningTotal,
},
render: (args) => (
<WizardLayout
{...args}
secondaryPanel={
<Box>
<Typography variant="h5" sx={{ mb: 0.5 }}>
Coffins
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
Browse our selection of bespoke designer coffins.
</Typography>
<Box
sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr', md: '1fr 1fr 1fr' },
gap: 2,
}}
>
{Array.from({ length: 6 }).map((_, i) => (
<PlaceholderCard key={i} title={`Coffin ${i + 1}`} height={160} />
))}
</Box>
</Box>
}
>
<Typography variant="h6" sx={{ mb: 2 }}>
Categories
</Typography>
{['Materials', 'Colour', 'Environmental', 'Religious'].map((cat) => (
<PlaceholderCard key={cat} title={cat} height={40} />
))}
<Typography variant="h6" sx={{ mt: 3, mb: 2 }}>
Price
</Typography>
<PlaceholderCard title="Price range slider" height={48} />
</WizardLayout>
),
};
// ─── Detail + Toggles ───────────────────────────────────────────────────────
/** Venue/coffin detail — hero image + product info */
export const DetailToggles: Story = {
args: {
variant: 'detail-toggles',
navigation: nav,
showBackLink: true,
progressStepper: stepper,
runningTotal: runningTotal,
},
render: (args) => (
<WizardLayout
{...args}
secondaryPanel={
<Box>
<Typography variant="h4" sx={{ mb: 0.5 }}>
West Chapel
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
Wentworth, NSW
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
Capacity: 120 guests
</Typography>
<Typography variant="body1" sx={{ mb: 2 }}>
A beautiful heritage chapel set in peaceful gardens, offering a serene setting for
farewell services.
</Typography>
<Typography variant="h5" color="primary.main" sx={{ mb: 2 }}>
$900
</Typography>
<Button variant="contained" size="large" fullWidth>
Add to package
</Button>
</Box>
}
>
<Box
sx={{
bgcolor: 'var(--fa-color-sage-200)',
borderRadius: 2,
height: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
mb: 2,
}}
>
<Typography variant="body1" color="text.secondary">
Venue image placeholder
</Typography>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
{Array.from({ length: 5 }).map((_, i) => (
<Box
key={i}
sx={{
bgcolor: 'var(--fa-color-sage-200)',
borderRadius: 1,
width: 60,
height: 48,
}}
/>
))}
</Box>
</WizardLayout>
),
};
// ─── No Navigation ──────────────────────────────────────────────────────────
/** Minimal — no nav, no help bar (for embedded use) */
export const Minimal: Story = {
args: {
variant: 'centered-form',
hideHelpBar: true,
},
render: (args) => (
<WizardLayout {...args}>
<Typography variant="h4" sx={{ mb: 1 }}>
Embedded form
</Typography>
<Typography variant="body1" color="text.secondary">
No navigation or help bar for iframe or modal contexts.
</Typography>
</WizardLayout>
),
};