Compare commits

..

3 Commits

Author SHA1 Message Date
f121ac7168 Strip AI tooling and working docs for dev push 2026-04-16 16:02:06 +10:00
9ac8e31516 Refine HomePage layout and add Locations dropdown to Navigation
- Navigation: add NavItem.children support for desktop dropdown + mobile collapsible sections. Wire Locations (Melbourne, Brisbane, Sydney, South Coast NSW, Central Coast NSW) before FAQ in all HomePage stories.
- HomePage hero: add italic "Trusted by thousands of families across Australia" tagline above h1, widen text container to 990px, use hero-couple.jpg background.
- HomePage features: rename "How it works" to "4 Reasons to use Funeral Arranger", add "Why Use Funeral Arranger" overline, remove placeholder body copy.
- HomePage testimonials: add "Funeral Arranger Reviews" overline above "What families are saying".
- HomePage CTA: promote "Start planning" to primary contained button (medium).
- FuneralFinderV3: remove header + divider so the form starts directly at "How can we help".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:00:28 +10:00
348f3912fd Promote hero h1 to display2 for visual hierarchy over section h2s
Hero heading was display3 (same as every section h2), giving no visual
distinction. Now display2 (52px/24px) vs display3 (40px/22px). Still
renders as semantic h1 for SEO.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:03:32 +10:00
8 changed files with 341 additions and 130 deletions

View File

@@ -41,10 +41,6 @@ export interface FuneralFinderV3Props {
onSearch?: (params: FuneralFinderV3SearchParams) => void;
/** Shows loading state on the CTA */
loading?: boolean;
/** Optional heading override */
heading?: string;
/** Optional subheading override */
subheading?: string;
/** MUI sx override for the root container */
sx?: SxProps<Theme>;
}
@@ -251,13 +247,7 @@ const selectMenuProps = {
*/
export const FuneralFinderV3 = React.forwardRef<HTMLDivElement, FuneralFinderV3Props>(
(props, ref) => {
const {
onSearch,
loading = false,
heading = 'Find funeral directors near you',
subheading,
sx,
} = props;
const { onSearch, loading = false, sx } = props;
// ─── IDs for aria-labelledby ──────────────────────────────
const id = React.useId();
@@ -392,29 +382,6 @@ export const FuneralFinderV3 = React.forwardRef<HTMLDivElement, FuneralFinderV3P
...(Array.isArray(sx) ? sx : [sx]),
]}
>
{/* ── Header ──────────────────────────────────────────── */}
<Box sx={{ textAlign: 'center' }}>
<Typography
variant="h3"
component="h2"
sx={{
fontFamily: 'var(--fa-font-family-display)',
fontWeight: 600,
fontSize: { xs: '1.25rem', sm: '1.5rem' },
mb: subheading ? 1 : 0,
}}
>
{heading}
</Typography>
{subheading && (
<Typography variant="body2" color="text.secondary">
{subheading}
</Typography>
)}
</Box>
<Divider />
{/* ── How can we help ─────────────────────────────────── */}
<Box ref={statusSectionRef}>
<SectionLabel id={statusLabelId}>How Can We Help</SectionLabel>

View File

@@ -143,3 +143,28 @@ export const ExtendedNavigation: Story = {
ctaLabel: 'Start planning',
},
};
// --- With Dropdown -----------------------------------------------------------
/** Items with `children` render as a dropdown on desktop and a collapsible
* section in the mobile drawer */
export const WithDropdown: Story = {
args: {
logo: <FALogo />,
items: [
{
label: 'Locations',
children: [
{ label: 'Melbourne', href: '/locations/melbourne' },
{ label: 'Brisbane', href: '/locations/brisbane' },
{ label: 'Sydney', href: '/locations/sydney' },
{ label: 'South Coast NSW', href: '/locations/south-coast-nsw' },
{ label: 'Central Coast NSW', href: '/locations/central-coast-nsw' },
],
},
{ label: 'FAQ', href: '/faq' },
{ label: 'Contact Us', href: '/contact' },
{ label: 'Log in', href: '/login' },
],
},
};

View File

@@ -6,9 +6,14 @@ import Drawer from '@mui/material/Drawer';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import Collapse from '@mui/material/Collapse';
import useMediaQuery from '@mui/material/useMediaQuery';
import MenuIcon from '@mui/icons-material/Menu';
import CloseIcon from '@mui/icons-material/Close';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import type { SxProps, Theme } from '@mui/material/styles';
import { IconButton } from '../../atoms/IconButton';
import { Link } from '../../atoms/Link';
@@ -18,14 +23,16 @@ import { Divider } from '../../atoms/Divider';
// ─── Types ───────────────────────────────────────────────────────────────────
/** A navigation link item */
/** A navigation link item. May have children to render as a dropdown. */
export interface NavItem {
/** Display label */
label: string;
/** URL to navigate to */
href: string;
/** URL to navigate to (ignored when `children` is provided) */
href?: string;
/** Click handler (alternative to href for SPA navigation) */
onClick?: () => void;
/** Sub-items rendered as a dropdown (desktop) or collapsible (mobile) */
children?: NavItem[];
}
/** Props for the FA Navigation organism */
@@ -44,6 +51,163 @@ export interface NavigationProps {
sx?: SxProps<Theme>;
}
// ─── Desktop dropdown link ───────────────────────────────────────────────────
interface DesktopDropdownProps {
item: NavItem;
}
const DesktopDropdown: React.FC<DesktopDropdownProps> = ({ item }) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleOpen = (event: React.MouseEvent<HTMLElement>) => setAnchorEl(event.currentTarget);
const handleClose = () => setAnchorEl(null);
return (
<>
<Box
component="button"
type="button"
aria-haspopup="menu"
aria-expanded={open}
onClick={handleOpen}
sx={{
background: 'none',
border: 'none',
padding: 0,
cursor: 'pointer',
color: 'var(--fa-color-brand-900)',
fontFamily: 'inherit',
fontWeight: 600,
fontSize: '1rem',
'&:hover': {
color: 'primary.main',
},
}}
>
{item.label}
</Box>
<Menu
anchorEl={anchorEl}
open={open}
onClose={handleClose}
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
slotProps={{
paper: {
sx: {
mt: 1,
minWidth: 200,
borderRadius: 'var(--fa-border-radius-md, 8px)',
boxShadow: '0 8px 24px rgba(0,0,0,0.08)',
},
},
}}
>
{item.children?.map((child) => (
<MenuItem
key={child.label}
component="a"
href={child.href}
onClick={(e: React.MouseEvent) => {
if (child.onClick) {
e.preventDefault();
child.onClick();
}
handleClose();
}}
sx={{
color: 'var(--fa-color-brand-900)',
fontWeight: 500,
py: 1.25,
'&:hover': {
bgcolor: 'var(--fa-color-brand-100)',
color: 'primary.main',
},
}}
>
{child.label}
</MenuItem>
))}
</Menu>
</>
);
};
// ─── Mobile collapsible item ─────────────────────────────────────────────────
interface MobileCollapsibleProps {
item: NavItem;
onItemClick: () => void;
}
const MobileCollapsible: React.FC<MobileCollapsibleProps> = ({ item, onItemClick }) => {
const [open, setOpen] = React.useState(false);
return (
<>
<ListItemButton
onClick={() => setOpen((prev) => !prev)}
aria-expanded={open}
sx={{
py: 1.5,
px: 3,
minHeight: 44,
'&:hover': {
bgcolor: 'var(--fa-color-brand-100)',
},
}}
>
<ListItemText
primary={item.label}
primaryTypographyProps={{
fontWeight: 500,
fontSize: '1rem',
}}
/>
{open ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</ListItemButton>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{item.children?.map((child) => (
<ListItemButton
key={child.label}
component="a"
href={child.href}
onClick={(e: React.MouseEvent) => {
if (child.onClick) {
e.preventDefault();
child.onClick();
}
onItemClick();
}}
sx={{
py: 1.25,
pl: 5,
pr: 3,
minHeight: 44,
'&:hover': {
bgcolor: 'var(--fa-color-brand-100)',
},
}}
>
<ListItemText
primary={child.label}
primaryTypographyProps={{
fontWeight: 400,
fontSize: '0.9375rem',
color: 'text.secondary',
}}
/>
</ListItemButton>
))}
</List>
</Collapse>
</>
);
};
// ─── Component ───────────────────────────────────────────────────────────────
/**
@@ -51,26 +215,13 @@ export interface NavigationProps {
*
* Responsive header with logo, navigation links, and optional CTA.
* Desktop shows links inline; mobile collapses to hamburger + drawer.
* Items with `children` render as a dropdown (desktop) or collapsible
* section (mobile).
*
* Maps to Figma "Main Nav" (14:108) desktop and "Mobile Header"
* (2391:41508) mobile patterns.
*
* Composes AppBar + Link + IconButton + Button + Divider + Drawer.
*
* Usage:
* ```tsx
* <Navigation
* logo={<img src="/logo.svg" alt="Funeral Arranger" height={40} />}
* onLogoClick={() => navigate('/')}
* items={[
* { label: 'FAQ', href: '/faq' },
* { label: 'Contact Us', href: '/contact' },
* { label: 'Log in', href: '/login' },
* ]}
* ctaLabel="Start planning"
* onCtaClick={() => navigate('/arrange')}
* />
* ```
* Composes AppBar + Link + IconButton + Button + Divider + Drawer + Menu.
*/
export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
({ logo, onLogoClick, items = [], ctaLabel, onCtaClick, sx }, ref) => {
@@ -78,6 +229,7 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
const isMobile = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'));
const handleDrawerToggle = () => setDrawerOpen((prev) => !prev);
const closeDrawer = () => setDrawerOpen(false);
return (
<>
@@ -147,7 +299,10 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
aria-label="Main navigation"
sx={{ display: 'flex', alignItems: 'center', gap: 3.5 }}
>
{items.map((item) => (
{items.map((item) =>
item.children && item.children.length > 0 ? (
<DesktopDropdown key={item.label} item={item} />
) : (
<Link
key={item.label}
href={item.href}
@@ -164,7 +319,8 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
>
{item.label}
</Link>
))}
),
)}
{ctaLabel && (
<Button variant="contained" size="medium" onClick={onCtaClick}>
@@ -210,7 +366,10 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
{/* Nav items */}
<List component="nav" aria-label="Main navigation">
{items.map((item) => (
{items.map((item) =>
item.children && item.children.length > 0 ? (
<MobileCollapsible key={item.label} item={item} onItemClick={closeDrawer} />
) : (
<ListItemButton
key={item.label}
component="a"
@@ -220,7 +379,7 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
e.preventDefault();
item.onClick();
}
setDrawerOpen(false);
closeDrawer();
}}
sx={{
py: 1.5,
@@ -239,7 +398,8 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
}}
/>
</ListItemButton>
))}
),
)}
</List>
{ctaLabel && (
@@ -250,7 +410,7 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
fullWidth
onClick={() => {
if (onCtaClick) onCtaClick();
setDrawerOpen(false);
closeDrawer();
}}
>
{ctaLabel}

View File

@@ -40,6 +40,16 @@ const nav = (
<Navigation
logo={<FALogo />}
items={[
{
label: 'Locations',
children: [
{ label: 'Melbourne', href: '/locations/melbourne' },
{ label: 'Brisbane', href: '/locations/brisbane' },
{ label: 'Sydney', href: '/locations/sydney' },
{ label: 'South Coast NSW', href: '/locations/south-coast-nsw' },
{ label: 'Central Coast NSW', href: '/locations/central-coast-nsw' },
],
},
{ label: 'FAQ', href: '/faq' },
{ label: 'Contact Us', href: '/contact' },
{ label: 'Log in', href: '/login' },

View File

@@ -186,8 +186,8 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
discoverMapSlot,
onSelectFeaturedProvider,
features = [],
featuresHeading = 'How it works',
featuresBody = 'Search local funeral directors, compare transparent pricing, and personalise a plan — all in your own time. No pressure, no hidden costs.',
featuresHeading = '4 Reasons to use Funeral Arranger',
featuresBody,
googleRating,
googleReviewCount,
testimonials = [],
@@ -241,17 +241,28 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
}}
>
<Container
maxWidth="md"
maxWidth={false}
sx={{
position: 'relative',
zIndex: 1,
textAlign: 'center',
maxWidth: 990,
pt: { xs: 10, md: 14 },
pb: { xs: 3, md: 4 },
}}
>
<Typography
variant="display3"
variant="body1"
sx={{
color: 'rgba(255,255,255,0.85)',
fontStyle: 'italic',
mb: 2,
}}
>
Trusted by thousands of families across Australia
</Typography>
<Typography
variant="display2"
component="h1"
id="hero-heading"
tabIndex={-1}
@@ -280,13 +291,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
}}
>
<Box sx={{ width: '100%', maxWidth: finderSlot ? 500 : 520, mx: 'auto' }}>
{finderSlot || (
<FuneralFinderV3
heading="Find your local providers"
onSearch={onSearch}
loading={searchLoading}
/>
)}
{finderSlot || <FuneralFinderV3 onSearch={onSearch} loading={searchLoading} />}
</Box>
</Box>
</Box>
@@ -316,7 +321,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
}}
>
<Typography
variant="display3"
variant="display2"
component="h1"
id="hero-heading"
tabIndex={-1}
@@ -369,13 +374,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
}}
>
<Box sx={{ maxWidth: 620, mx: 'auto' }}>
{finderSlot || (
<FuneralFinderV3
heading="Find your local providers"
onSearch={onSearch}
loading={searchLoading}
/>
)}
{finderSlot || <FuneralFinderV3 onSearch={onSearch} loading={searchLoading} />}
</Box>
</Box>
)}
@@ -801,14 +800,22 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
>
<Container maxWidth="lg">
<Box sx={{ textAlign: 'center', mb: { xs: 5, md: 8 } }}>
<Typography
variant="overline"
component="div"
sx={{ color: 'var(--fa-color-brand-600)', mb: 1.5 }}
>
Why Use Funeral Arranger
</Typography>
<Typography
variant="display3"
component="h2"
id="features-heading"
sx={{ mb: 2.5, color: 'text.primary' }}
sx={{ mb: featuresBody ? 2.5 : 0, color: 'text.primary' }}
>
{featuresHeading}
</Typography>
{featuresBody && (
<Typography
variant="body1"
color="text.secondary"
@@ -816,6 +823,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
>
{featuresBody}
</Typography>
)}
</Box>
<Box
@@ -866,6 +874,17 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
}}
>
<Container maxWidth="md">
<Typography
variant="overline"
component="div"
sx={{
textAlign: 'center',
color: 'var(--fa-color-brand-600)',
mb: 1.5,
}}
>
Funeral Arranger Reviews
</Typography>
<Typography
variant="display3"
component="h2"
@@ -978,7 +997,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
>
{ctaHeading}
</Typography>
<Button variant="text" size="large" onClick={onCtaClick}>
<Button variant="contained" size="medium" onClick={onCtaClick}>
{ctaButtonLabel}
</Button>
</Container>

View File

@@ -42,6 +42,16 @@ const nav = (
<Navigation
logo={<FALogo />}
items={[
{
label: 'Locations',
children: [
{ label: 'Melbourne', href: '/locations/melbourne' },
{ label: 'Brisbane', href: '/locations/brisbane' },
{ label: 'Sydney', href: '/locations/sydney' },
{ label: 'South Coast NSW', href: '/locations/south-coast-nsw' },
{ label: 'Central Coast NSW', href: '/locations/central-coast-nsw' },
],
},
{ label: 'FAQ', href: '/faq' },
{ label: 'Contact Us', href: '/contact' },
{ label: 'Log in', href: '/login' },

View File

@@ -38,6 +38,16 @@ const nav = (
<Navigation
logo={<FALogo />}
items={[
{
label: 'Locations',
children: [
{ label: 'Melbourne', href: '/locations/melbourne' },
{ label: 'Brisbane', href: '/locations/brisbane' },
{ label: 'Sydney', href: '/locations/sydney' },
{ label: 'South Coast NSW', href: '/locations/south-coast-nsw' },
{ label: 'Central Coast NSW', href: '/locations/central-coast-nsw' },
],
},
{ label: 'FAQ', href: '/faq' },
{ label: 'Contact Us', href: '/contact' },
{ label: 'Log in', href: '/login' },
@@ -258,7 +268,7 @@ export const Default: Story = {
args: {
navigation: nav,
footer,
heroImageUrl: assetUrl('/images/heroes/hero-3.png'),
heroImageUrl: assetUrl('/images/heroes/hero-couple.jpg'),
heroHeading: 'Compare funeral director pricing near you and arrange with confidence',
heroSubheading: 'Transparent pricing \u00B7 No hidden fees \u00B7 Arrange 24/7',
stats: trustStats,

View File

@@ -39,6 +39,16 @@ const nav = (
<Navigation
logo={<FALogo />}
items={[
{
label: 'Locations',
children: [
{ label: 'Melbourne', href: '/locations/melbourne' },
{ label: 'Brisbane', href: '/locations/brisbane' },
{ label: 'Sydney', href: '/locations/sydney' },
{ label: 'South Coast NSW', href: '/locations/south-coast-nsw' },
{ label: 'Central Coast NSW', href: '/locations/central-coast-nsw' },
],
},
{ label: 'FAQ', href: '/faq' },
{ label: 'Contact Us', href: '/contact' },
{ label: 'Log in', href: '/login' },