From 9ac8e31516472310cf07a5d3cbcd4f978d84efdc Mon Sep 17 00:00:00 2001 From: Richie Date: Thu, 16 Apr 2026 16:00:28 +1000 Subject: [PATCH] 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) --- .../FuneralFinder/FuneralFinderV3.tsx | 35 +-- .../Navigation/Navigation.stories.tsx | 25 ++ .../organisms/Navigation/Navigation.tsx | 294 ++++++++++++++---- .../pages/HomePage/HomePage.stories.tsx | 10 + src/components/pages/HomePage/HomePage.tsx | 71 +++-- .../pages/HomePage/HomePageV2.stories.tsx | 10 + .../pages/HomePage/HomePageV3.stories.tsx | 12 +- .../pages/HomePage/HomePageV4.stories.tsx | 10 + 8 files changed, 339 insertions(+), 128 deletions(-) diff --git a/src/components/organisms/FuneralFinder/FuneralFinderV3.tsx b/src/components/organisms/FuneralFinder/FuneralFinderV3.tsx index bff9b80..d6ba374 100644 --- a/src/components/organisms/FuneralFinder/FuneralFinderV3.tsx +++ b/src/components/organisms/FuneralFinder/FuneralFinderV3.tsx @@ -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; } @@ -251,13 +247,7 @@ const selectMenuProps = { */ export const FuneralFinderV3 = React.forwardRef( (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 - {/* ── Header ──────────────────────────────────────────── */} - - - {heading} - - {subheading && ( - - {subheading} - - )} - - - - {/* ── How can we help ─────────────────────────────────── */} How Can We Help diff --git a/src/components/organisms/Navigation/Navigation.stories.tsx b/src/components/organisms/Navigation/Navigation.stories.tsx index 759cc04..8a7f2c1 100644 --- a/src/components/organisms/Navigation/Navigation.stories.tsx +++ b/src/components/organisms/Navigation/Navigation.stories.tsx @@ -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: , + 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' }, + ], + }, +}; diff --git a/src/components/organisms/Navigation/Navigation.tsx b/src/components/organisms/Navigation/Navigation.tsx index ab4aa95..42c57f2 100644 --- a/src/components/organisms/Navigation/Navigation.tsx +++ b/src/components/organisms/Navigation/Navigation.tsx @@ -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; } +// ─── Desktop dropdown link ─────────────────────────────────────────────────── + +interface DesktopDropdownProps { + item: NavItem; +} + +const DesktopDropdown: React.FC = ({ item }) => { + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + + const handleOpen = (event: React.MouseEvent) => setAnchorEl(event.currentTarget); + const handleClose = () => setAnchorEl(null); + + return ( + <> + + {item.label} + + + {item.children?.map((child) => ( + { + 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} + + ))} + + + ); +}; + +// ─── Mobile collapsible item ───────────────────────────────────────────────── + +interface MobileCollapsibleProps { + item: NavItem; + onItemClick: () => void; +} + +const MobileCollapsible: React.FC = ({ item, onItemClick }) => { + const [open, setOpen] = React.useState(false); + + return ( + <> + setOpen((prev) => !prev)} + aria-expanded={open} + sx={{ + py: 1.5, + px: 3, + minHeight: 44, + '&:hover': { + bgcolor: 'var(--fa-color-brand-100)', + }, + }} + > + + {open ? : } + + + + {item.children?.map((child) => ( + { + 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)', + }, + }} + > + + + ))} + + + + ); +}; + // ─── 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 - * } - * 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( ({ logo, onLogoClick, items = [], ctaLabel, onCtaClick, sx }, ref) => { @@ -78,6 +229,7 @@ export const Navigation = React.forwardRef( const isMobile = useMediaQuery((theme: Theme) => theme.breakpoints.down('md')); const handleDrawerToggle = () => setDrawerOpen((prev) => !prev); + const closeDrawer = () => setDrawerOpen(false); return ( <> @@ -147,24 +299,28 @@ export const Navigation = React.forwardRef( aria-label="Main navigation" sx={{ display: 'flex', alignItems: 'center', gap: 3.5 }} > - {items.map((item) => ( - - {item.label} - - ))} + {items.map((item) => + item.children && item.children.length > 0 ? ( + + ) : ( + + {item.label} + + ), + )} {ctaLabel && ( diff --git a/src/components/pages/HomePage/HomePageV2.stories.tsx b/src/components/pages/HomePage/HomePageV2.stories.tsx index 9dd8717..ea764d4 100644 --- a/src/components/pages/HomePage/HomePageV2.stories.tsx +++ b/src/components/pages/HomePage/HomePageV2.stories.tsx @@ -42,6 +42,16 @@ const nav = ( } 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' }, diff --git a/src/components/pages/HomePage/HomePageV3.stories.tsx b/src/components/pages/HomePage/HomePageV3.stories.tsx index e1aa618..0aea8ad 100644 --- a/src/components/pages/HomePage/HomePageV3.stories.tsx +++ b/src/components/pages/HomePage/HomePageV3.stories.tsx @@ -38,6 +38,16 @@ const nav = ( } 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, diff --git a/src/components/pages/HomePage/HomePageV4.stories.tsx b/src/components/pages/HomePage/HomePageV4.stories.tsx index aac1374..545b88e 100644 --- a/src/components/pages/HomePage/HomePageV4.stories.tsx +++ b/src/components/pages/HomePage/HomePageV4.stories.tsx @@ -39,6 +39,16 @@ const nav = ( } 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' },