Compare commits
1 Commits
main
...
a9e5843375
| Author | SHA1 | Date | |
|---|---|---|---|
| a9e5843375 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -28,9 +28,6 @@ docs/reference/how-to-work-with-both-tools.md
|
||||
docs/reference/mcp-setup.md
|
||||
docs/reference/retroactive-review-plan.md
|
||||
|
||||
# Deploy scripts (contain credentials)
|
||||
scripts/
|
||||
|
||||
# Build logs
|
||||
build-storybook.log
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@ 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>;
|
||||
}
|
||||
@@ -247,7 +251,13 @@ const selectMenuProps = {
|
||||
*/
|
||||
export const FuneralFinderV3 = React.forwardRef<HTMLDivElement, FuneralFinderV3Props>(
|
||||
(props, ref) => {
|
||||
const { onSearch, loading = false, sx } = props;
|
||||
const {
|
||||
onSearch,
|
||||
loading = false,
|
||||
heading = 'Find funeral directors near you',
|
||||
subheading,
|
||||
sx,
|
||||
} = props;
|
||||
|
||||
// ─── IDs for aria-labelledby ──────────────────────────────
|
||||
const id = React.useId();
|
||||
@@ -382,6 +392,29 @@ 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>
|
||||
|
||||
@@ -143,28 +143,3 @@ 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' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -6,14 +6,9 @@ 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';
|
||||
@@ -23,16 +18,14 @@ import { Divider } from '../../atoms/Divider';
|
||||
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** A navigation link item. May have children to render as a dropdown. */
|
||||
/** A navigation link item */
|
||||
export interface NavItem {
|
||||
/** Display label */
|
||||
label: string;
|
||||
/** URL to navigate to (ignored when `children` is provided) */
|
||||
href?: string;
|
||||
/** URL to navigate to */
|
||||
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 */
|
||||
@@ -51,163 +44,6 @@ 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 ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -215,13 +51,26 @@ const MobileCollapsible: React.FC<MobileCollapsibleProps> = ({ item, onItemClick
|
||||
*
|
||||
* 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 + Menu.
|
||||
* 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')}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
|
||||
({ logo, onLogoClick, items = [], ctaLabel, onCtaClick, sx }, ref) => {
|
||||
@@ -229,7 +78,6 @@ 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 (
|
||||
<>
|
||||
@@ -299,28 +147,24 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
|
||||
aria-label="Main navigation"
|
||||
sx={{ display: 'flex', alignItems: 'center', gap: 3.5 }}
|
||||
>
|
||||
{items.map((item) =>
|
||||
item.children && item.children.length > 0 ? (
|
||||
<DesktopDropdown key={item.label} item={item} />
|
||||
) : (
|
||||
<Link
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
onClick={item.onClick}
|
||||
underline="hover"
|
||||
sx={{
|
||||
color: 'var(--fa-color-brand-900)',
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem',
|
||||
'&:hover': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
),
|
||||
)}
|
||||
{items.map((item) => (
|
||||
<Link
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
onClick={item.onClick}
|
||||
underline="hover"
|
||||
sx={{
|
||||
color: 'var(--fa-color-brand-900)',
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem',
|
||||
'&:hover': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
{ctaLabel && (
|
||||
<Button variant="contained" size="medium" onClick={onCtaClick}>
|
||||
@@ -366,40 +210,36 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
|
||||
|
||||
{/* Nav items */}
|
||||
<List component="nav" aria-label="Main navigation">
|
||||
{items.map((item) =>
|
||||
item.children && item.children.length > 0 ? (
|
||||
<MobileCollapsible key={item.label} item={item} onItemClick={closeDrawer} />
|
||||
) : (
|
||||
<ListItemButton
|
||||
key={item.label}
|
||||
component="a"
|
||||
href={item.href}
|
||||
onClick={(e: React.MouseEvent) => {
|
||||
if (item.onClick) {
|
||||
e.preventDefault();
|
||||
item.onClick();
|
||||
}
|
||||
closeDrawer();
|
||||
{items.map((item) => (
|
||||
<ListItemButton
|
||||
key={item.label}
|
||||
component="a"
|
||||
href={item.href}
|
||||
onClick={(e: React.MouseEvent) => {
|
||||
if (item.onClick) {
|
||||
e.preventDefault();
|
||||
item.onClick();
|
||||
}
|
||||
setDrawerOpen(false);
|
||||
}}
|
||||
sx={{
|
||||
py: 1.5,
|
||||
px: 3,
|
||||
minHeight: 44,
|
||||
'&:hover': {
|
||||
bgcolor: 'var(--fa-color-brand-100)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={item.label}
|
||||
primaryTypographyProps={{
|
||||
fontWeight: 500,
|
||||
fontSize: '1rem',
|
||||
}}
|
||||
sx={{
|
||||
py: 1.5,
|
||||
px: 3,
|
||||
minHeight: 44,
|
||||
'&:hover': {
|
||||
bgcolor: 'var(--fa-color-brand-100)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={item.label}
|
||||
primaryTypographyProps={{
|
||||
fontWeight: 500,
|
||||
fontSize: '1rem',
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
),
|
||||
)}
|
||||
/>
|
||||
</ListItemButton>
|
||||
))}
|
||||
</List>
|
||||
|
||||
{ctaLabel && (
|
||||
@@ -410,7 +250,7 @@ export const Navigation = React.forwardRef<HTMLDivElement, NavigationProps>(
|
||||
fullWidth
|
||||
onClick={() => {
|
||||
if (onCtaClick) onCtaClick();
|
||||
closeDrawer();
|
||||
setDrawerOpen(false);
|
||||
}}
|
||||
>
|
||||
{ctaLabel}
|
||||
|
||||
@@ -40,16 +40,6 @@ 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' },
|
||||
|
||||
@@ -13,7 +13,6 @@ import type { SxProps, Theme } from '@mui/material/styles';
|
||||
import { Typography } from '../../atoms/Typography';
|
||||
import { Button } from '../../atoms/Button';
|
||||
import { ProviderCardCompact } from '../../molecules/ProviderCardCompact';
|
||||
import { assetUrl } from '../../../utils/assetUrl';
|
||||
import { Divider } from '../../atoms/Divider';
|
||||
import { FuneralFinderV3, type FuneralFinderV3SearchParams } from '../../organisms/FuneralFinder';
|
||||
|
||||
@@ -186,8 +185,8 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
discoverMapSlot,
|
||||
onSelectFeaturedProvider,
|
||||
features = [],
|
||||
featuresHeading = '4 Reasons to use Funeral Arranger',
|
||||
featuresBody,
|
||||
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.',
|
||||
googleRating,
|
||||
googleReviewCount,
|
||||
testimonials = [],
|
||||
@@ -241,32 +240,21 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
}}
|
||||
>
|
||||
<Container
|
||||
maxWidth={false}
|
||||
maxWidth="md"
|
||||
sx={{
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
textAlign: 'center',
|
||||
maxWidth: 990,
|
||||
pt: { xs: 10, md: 14 },
|
||||
pb: { xs: 3, md: 4 },
|
||||
pt: { xs: 8, md: 11 },
|
||||
pb: 4,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
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"
|
||||
variant="display3"
|
||||
component="h1"
|
||||
id="hero-heading"
|
||||
tabIndex={-1}
|
||||
sx={{ mb: 5, color: 'var(--fa-color-white)' }}
|
||||
sx={{ mb: 3, color: 'var(--fa-color-white)' }}
|
||||
>
|
||||
{heroHeading}
|
||||
</Typography>
|
||||
@@ -284,14 +272,20 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
position: 'relative',
|
||||
zIndex: 2,
|
||||
width: '100%',
|
||||
px: { xs: 3, md: 2 },
|
||||
pt: 6,
|
||||
px: 2,
|
||||
pt: 2,
|
||||
pb: 0,
|
||||
mb: { xs: -14, md: -18 },
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: '100%', maxWidth: finderSlot ? 500 : 520, mx: 'auto' }}>
|
||||
{finderSlot || <FuneralFinderV3 onSearch={onSearch} loading={searchLoading} />}
|
||||
{finderSlot || (
|
||||
<FuneralFinderV3
|
||||
heading="Find your local providers"
|
||||
onSearch={onSearch}
|
||||
loading={searchLoading}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -321,7 +315,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="display2"
|
||||
variant="display3"
|
||||
component="h1"
|
||||
id="hero-heading"
|
||||
tabIndex={-1}
|
||||
@@ -374,7 +368,13 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
}}
|
||||
>
|
||||
<Box sx={{ maxWidth: 620, mx: 'auto' }}>
|
||||
{finderSlot || <FuneralFinderV3 onSearch={onSearch} loading={searchLoading} />}
|
||||
{finderSlot || (
|
||||
<FuneralFinderV3
|
||||
heading="Find your local providers"
|
||||
onSearch={onSearch}
|
||||
loading={searchLoading}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
@@ -498,7 +498,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="text.secondary"
|
||||
sx={{ maxWidth: 520, mx: 'auto', fontSize: { xs: '0.875rem', md: '1rem' } }}
|
||||
sx={{ maxWidth: 520, mx: 'auto' }}
|
||||
>
|
||||
From trusted local providers to personalised options, find the right care near
|
||||
you.
|
||||
@@ -571,7 +571,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
{/* CTA */}
|
||||
<Box sx={{ textAlign: 'center', mt: 4 }}>
|
||||
<Button variant="text" size="medium" onClick={onCtaClick}>
|
||||
Start exploring
|
||||
Start exploring →
|
||||
</Button>
|
||||
</Box>
|
||||
</Container>
|
||||
@@ -601,7 +601,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
}}
|
||||
>
|
||||
{/* Text */}
|
||||
<Box sx={{ textAlign: { xs: 'center', md: 'left' } }}>
|
||||
<Box>
|
||||
<Typography
|
||||
variant="overline"
|
||||
component="div"
|
||||
@@ -617,11 +617,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
>
|
||||
Making an impossible time a little easier
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="text.secondary"
|
||||
sx={{ fontSize: { xs: '0.875rem', md: '1rem' } }}
|
||||
>
|
||||
<Typography variant="body1" color="text.secondary">
|
||||
Funeral planning doesn’t have to be overwhelming. Whether a loved one has
|
||||
just passed, is imminent, or you’re pre-planning the future for yourself.
|
||||
Compare transparent pricing from local funeral directors. Explore the service
|
||||
@@ -642,7 +638,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={assetUrl('/images/Homepage/people.png')}
|
||||
src="/brandassets/images/Homepage/people.png"
|
||||
alt="Family planning together with care and confidence"
|
||||
/>
|
||||
</Box>
|
||||
@@ -800,30 +796,21 @@ 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: featuresBody ? 2.5 : 0, color: 'text.primary' }}
|
||||
sx={{ mb: 2.5, color: 'text.primary' }}
|
||||
>
|
||||
{featuresHeading}
|
||||
</Typography>
|
||||
{featuresBody && (
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="text.secondary"
|
||||
sx={{ maxWidth: 560, mx: 'auto', fontSize: { xs: '0.875rem', md: '1rem' } }}
|
||||
>
|
||||
{featuresBody}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="text.secondary"
|
||||
sx={{ maxWidth: 560, mx: 'auto' }}
|
||||
>
|
||||
{featuresBody}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
@@ -874,17 +861,6 @@ 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"
|
||||
@@ -997,7 +973,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
>
|
||||
{ctaHeading}
|
||||
</Typography>
|
||||
<Button variant="contained" size="medium" onClick={onCtaClick}>
|
||||
<Button variant="text" size="large" onClick={onCtaClick}>
|
||||
{ctaButtonLabel}
|
||||
</Button>
|
||||
</Container>
|
||||
@@ -1043,13 +1019,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
|
||||
}}
|
||||
>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} sx={{ px: 0, py: 1.5 }}>
|
||||
<Typography
|
||||
variant="body1"
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
fontSize: { xs: '0.875rem', md: '1rem' },
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" sx={{ fontWeight: 500 }}>
|
||||
{item.question}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { HomePage } from './HomePage';
|
||||
import type { FeaturedProvider, TrustStat } from './HomePage';
|
||||
import { Navigation } from '../../organisms/Navigation';
|
||||
import { Footer } from '../../organisms/Footer';
|
||||
import { assetUrl } from '../../../utils/assetUrl';
|
||||
|
||||
// ─── Shared helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
@@ -42,16 +41,6 @@ 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' },
|
||||
@@ -242,7 +231,7 @@ export const Default: Story = {
|
||||
args: {
|
||||
navigation: nav,
|
||||
footer,
|
||||
heroImageUrl: assetUrl('/images/heroes/parsonshero.png'),
|
||||
heroImageUrl: '/brandassets/images/heroes/parsonshero.png',
|
||||
stats: trustStats,
|
||||
featuredProviders,
|
||||
onSelectFeaturedProvider: (id) => console.log('Featured provider:', id),
|
||||
|
||||
@@ -9,7 +9,6 @@ import type { FeaturedProvider, TrustStat, PartnerLogo } from './HomePage';
|
||||
import React from 'react';
|
||||
import { Navigation } from '../../organisms/Navigation';
|
||||
import { Footer } from '../../organisms/Footer';
|
||||
import { assetUrl } from '../../../utils/assetUrl';
|
||||
|
||||
// ─── Shared helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
@@ -38,16 +37,6 @@ 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' },
|
||||
@@ -188,8 +177,8 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
name: 'H.Parsons Funeral Directors',
|
||||
location: 'Wollongong, NSW',
|
||||
verified: true,
|
||||
imageUrl: assetUrl('/images/venues/hparsons-funeral-home-kiama/01.jpg'),
|
||||
logoUrl: assetUrl('/images/providers/hparsons-funeral-directors/logo.png'),
|
||||
imageUrl: '/brandassets/images/venues/hparsons-funeral-home-kiama/01.jpg',
|
||||
logoUrl: '/brandassets/images/providers/hparsons-funeral-directors/logo.png',
|
||||
rating: 4.6,
|
||||
reviewCount: 7,
|
||||
startingPrice: 900,
|
||||
@@ -199,8 +188,8 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
name: 'Rankins Funerals',
|
||||
location: 'Wollongong, NSW',
|
||||
verified: true,
|
||||
imageUrl: assetUrl('/images/venues/rankins-funeral-home-warrawong/01.jpg'),
|
||||
logoUrl: assetUrl('/images/providers/rankins-funerals/logo.png'),
|
||||
imageUrl: '/brandassets/images/venues/rankins-funeral-home-warrawong/01.jpg',
|
||||
logoUrl: '/brandassets/images/providers/rankins-funerals/logo.png',
|
||||
rating: 4.8,
|
||||
reviewCount: 23,
|
||||
startingPrice: 1200,
|
||||
@@ -210,8 +199,8 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
name: 'Easy Funerals',
|
||||
location: 'Sydney, NSW',
|
||||
verified: true,
|
||||
imageUrl: assetUrl('/images/venues/lakeside-memorial-park-chapel/01.jpg'),
|
||||
logoUrl: assetUrl('/images/providers/easy-funerals/logo.png'),
|
||||
imageUrl: '/brandassets/images/venues/lakeside-memorial-park-chapel/01.jpg',
|
||||
logoUrl: '/brandassets/images/providers/easy-funerals/logo.png',
|
||||
rating: 4.5,
|
||||
reviewCount: 42,
|
||||
startingPrice: 850,
|
||||
@@ -220,30 +209,30 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
|
||||
const partnerLogos: PartnerLogo[] = [
|
||||
{
|
||||
src: assetUrl('/images/providers/hparsons-funeral-directors/logo.png'),
|
||||
src: '/brandassets/images/providers/hparsons-funeral-directors/logo.png',
|
||||
alt: 'H.Parsons Funeral Directors',
|
||||
},
|
||||
{ src: assetUrl('/images/providers/rankins-funerals/logo.png'), alt: 'Rankins Funerals' },
|
||||
{ src: assetUrl('/images/providers/easy-funerals/logo.png'), alt: 'Easy Funerals' },
|
||||
{ src: assetUrl('/images/providers/lady-anne-funerals/logo.png'), alt: 'Lady Anne Funerals' },
|
||||
{ src: '/brandassets/images/providers/rankins-funerals/logo.png', alt: 'Rankins Funerals' },
|
||||
{ src: '/brandassets/images/providers/easy-funerals/logo.png', alt: 'Easy Funerals' },
|
||||
{ src: '/brandassets/images/providers/lady-anne-funerals/logo.png', alt: 'Lady Anne Funerals' },
|
||||
{
|
||||
src: assetUrl('/images/providers/killick-family-funerals/logo.png'),
|
||||
src: '/brandassets/images/providers/killick-family-funerals/logo.png',
|
||||
alt: 'Killick Family Funerals',
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/kenneallys-funerals/logo.png'),
|
||||
src: '/brandassets/images/providers/kenneallys-funerals/logo.png',
|
||||
alt: "Kenneally's Funerals",
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/wollongong-city-funerals/logo.png'),
|
||||
src: '/brandassets/images/providers/wollongong-city-funerals/logo.png',
|
||||
alt: 'Wollongong City Funerals',
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/hparsons-funeral-directors-shoalhaven/logo.png'),
|
||||
src: '/brandassets/images/providers/hparsons-funeral-directors-shoalhaven/logo.png',
|
||||
alt: 'H.Parsons Shoalhaven',
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/mackay-family-funerals/logo.webp'),
|
||||
src: '/brandassets/images/providers/mackay-family-funerals/logo.webp',
|
||||
alt: 'Mackay Family Funerals',
|
||||
},
|
||||
];
|
||||
@@ -268,13 +257,13 @@ export const Default: Story = {
|
||||
args: {
|
||||
navigation: nav,
|
||||
footer,
|
||||
heroImageUrl: assetUrl('/images/heroes/hero-couple.jpg'),
|
||||
heroImageUrl: '/brandassets/images/heroes/hero-3.png',
|
||||
heroHeading: 'Compare funeral director pricing near you and arrange with confidence',
|
||||
heroSubheading: 'Transparent pricing \u00B7 No hidden fees \u00B7 Arrange 24/7',
|
||||
stats: trustStats,
|
||||
featuredProviders,
|
||||
discoverMapSlot: React.createElement('img', {
|
||||
src: assetUrl('/images/placeholder/map.png'),
|
||||
src: '/brandassets/images/placeholder/map.png',
|
||||
alt: 'Map showing provider locations',
|
||||
style: { width: '100%', height: '100%', objectFit: 'cover' },
|
||||
}),
|
||||
|
||||
@@ -10,7 +10,6 @@ import { FuneralFinderV4 } from '../../organisms/FuneralFinder/FuneralFinderV4';
|
||||
import React from 'react';
|
||||
import { Navigation } from '../../organisms/Navigation';
|
||||
import { Footer } from '../../organisms/Footer';
|
||||
import { assetUrl } from '../../../utils/assetUrl';
|
||||
|
||||
// ─── Shared helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
@@ -39,16 +38,6 @@ 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' },
|
||||
@@ -189,8 +178,8 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
name: 'H.Parsons Funeral Directors',
|
||||
location: 'Wollongong, NSW',
|
||||
verified: true,
|
||||
imageUrl: assetUrl('/images/venues/hparsons-funeral-home-kiama/01.jpg'),
|
||||
logoUrl: assetUrl('/images/providers/hparsons-funeral-directors/logo.png'),
|
||||
imageUrl: '/brandassets/images/venues/hparsons-funeral-home-kiama/01.jpg',
|
||||
logoUrl: '/brandassets/images/providers/hparsons-funeral-directors/logo.png',
|
||||
rating: 4.6,
|
||||
reviewCount: 7,
|
||||
startingPrice: 900,
|
||||
@@ -200,8 +189,8 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
name: 'Rankins Funerals',
|
||||
location: 'Wollongong, NSW',
|
||||
verified: true,
|
||||
imageUrl: assetUrl('/images/venues/rankins-funeral-home-warrawong/01.jpg'),
|
||||
logoUrl: assetUrl('/images/providers/rankins-funerals/logo.png'),
|
||||
imageUrl: '/brandassets/images/venues/rankins-funeral-home-warrawong/01.jpg',
|
||||
logoUrl: '/brandassets/images/providers/rankins-funerals/logo.png',
|
||||
rating: 4.8,
|
||||
reviewCount: 23,
|
||||
startingPrice: 1200,
|
||||
@@ -211,8 +200,8 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
name: 'Easy Funerals',
|
||||
location: 'Sydney, NSW',
|
||||
verified: true,
|
||||
imageUrl: assetUrl('/images/venues/lakeside-memorial-park-chapel/01.jpg'),
|
||||
logoUrl: assetUrl('/images/providers/easy-funerals/logo.png'),
|
||||
imageUrl: '/brandassets/images/venues/lakeside-memorial-park-chapel/01.jpg',
|
||||
logoUrl: '/brandassets/images/providers/easy-funerals/logo.png',
|
||||
rating: 4.5,
|
||||
reviewCount: 42,
|
||||
startingPrice: 850,
|
||||
@@ -221,30 +210,30 @@ const featuredProviders: FeaturedProvider[] = [
|
||||
|
||||
const partnerLogos: PartnerLogo[] = [
|
||||
{
|
||||
src: assetUrl('/images/providers/hparsons-funeral-directors/logo.png'),
|
||||
src: '/brandassets/images/providers/hparsons-funeral-directors/logo.png',
|
||||
alt: 'H.Parsons Funeral Directors',
|
||||
},
|
||||
{ src: assetUrl('/images/providers/rankins-funerals/logo.png'), alt: 'Rankins Funerals' },
|
||||
{ src: assetUrl('/images/providers/easy-funerals/logo.png'), alt: 'Easy Funerals' },
|
||||
{ src: assetUrl('/images/providers/lady-anne-funerals/logo.png'), alt: 'Lady Anne Funerals' },
|
||||
{ src: '/brandassets/images/providers/rankins-funerals/logo.png', alt: 'Rankins Funerals' },
|
||||
{ src: '/brandassets/images/providers/easy-funerals/logo.png', alt: 'Easy Funerals' },
|
||||
{ src: '/brandassets/images/providers/lady-anne-funerals/logo.png', alt: 'Lady Anne Funerals' },
|
||||
{
|
||||
src: assetUrl('/images/providers/killick-family-funerals/logo.png'),
|
||||
src: '/brandassets/images/providers/killick-family-funerals/logo.png',
|
||||
alt: 'Killick Family Funerals',
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/kenneallys-funerals/logo.png'),
|
||||
src: '/brandassets/images/providers/kenneallys-funerals/logo.png',
|
||||
alt: "Kenneally's Funerals",
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/wollongong-city-funerals/logo.png'),
|
||||
src: '/brandassets/images/providers/wollongong-city-funerals/logo.png',
|
||||
alt: 'Wollongong City Funerals',
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/hparsons-funeral-directors-shoalhaven/logo.png'),
|
||||
src: '/brandassets/images/providers/hparsons-funeral-directors-shoalhaven/logo.png',
|
||||
alt: 'H.Parsons Shoalhaven',
|
||||
},
|
||||
{
|
||||
src: assetUrl('/images/providers/mackay-family-funerals/logo.webp'),
|
||||
src: '/brandassets/images/providers/mackay-family-funerals/logo.webp',
|
||||
alt: 'Mackay Family Funerals',
|
||||
},
|
||||
];
|
||||
@@ -269,7 +258,7 @@ export const Default: Story = {
|
||||
args: {
|
||||
navigation: nav,
|
||||
footer,
|
||||
heroImageUrl: assetUrl('/images/heroes/hero-3.png'),
|
||||
heroImageUrl: '/brandassets/images/heroes/hero-3.png',
|
||||
heroHeading: 'Compare funeral directors pricing near you and arrange with confidence',
|
||||
heroSubheading: 'Transparent pricing \u00B7 No hidden fees \u00B7 Arrange 24/7',
|
||||
finderSlot: React.createElement(FuneralFinderV4, {
|
||||
@@ -278,7 +267,7 @@ export const Default: Story = {
|
||||
stats: trustStats,
|
||||
featuredProviders,
|
||||
discoverMapSlot: React.createElement('img', {
|
||||
src: assetUrl('/images/placeholder/map.png'),
|
||||
src: '/brandassets/images/placeholder/map.png',
|
||||
alt: 'Map showing provider locations',
|
||||
style: { width: '100%', height: '100%', objectFit: 'cover' },
|
||||
}),
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Resolves a static asset path. In local dev the path is served by Storybook's
|
||||
* staticDirs; when STORYBOOK_ASSET_BASE is set (e.g. Chromatic builds) it
|
||||
* prepends the external host URL so images load from Gitea.
|
||||
*/
|
||||
export const assetUrl = (path: string): string => {
|
||||
const base =
|
||||
typeof import.meta !== 'undefined' ? (import.meta.env?.STORYBOOK_ASSET_BASE ?? '') : '';
|
||||
return `${base}${path}`;
|
||||
};
|
||||
Reference in New Issue
Block a user