Promote HomePage V3 to production, redesign layout and refine FuneralFinder

Homepage: add "Why Use FA" text+image section and "Three Ways" feature cards,
reorder sections (logos carousel above discover), apply warm-grey alternating
backgrounds from Figma, unify all section headings to display3 serif, increase
section padding, fix heading hierarchy for SEO, and left-align testimonials.

FuneralFinder V3: responsive CTA (medium on mobile), shorten button to "Search",
bump reassurance text to caption variant, tighten location pin-to-text gap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 23:19:31 +10:00
parent e89ac360e8
commit 5e93f3a0d0
3 changed files with 318 additions and 101 deletions

View File

@@ -561,7 +561,7 @@ export const FuneralFinderV3 = React.forwardRef<HTMLDivElement, FuneralFinderV3P
placeholder="Enter suburb or postcode" placeholder="Enter suburb or postcode"
inputRef={locationInputRef} inputRef={locationInputRef}
startAdornment={ startAdornment={
<InputAdornment position="start" sx={{ ml: 0.5 }}> <InputAdornment position="start" sx={{ ml: 0.25, mr: -0.5 }}>
<LocationOnOutlinedIcon <LocationOnOutlinedIcon
sx={{ sx={{
fontSize: 20, fontSize: 20,
@@ -577,6 +577,7 @@ export const FuneralFinderV3 = React.forwardRef<HTMLDivElement, FuneralFinderV3P
...fieldBaseSx, ...fieldBaseSx,
'& .MuiOutlinedInput-input': { '& .MuiOutlinedInput-input': {
...fieldInputStyles, ...fieldInputStyles,
pl: 0.75,
'&::placeholder': { '&::placeholder': {
color: 'var(--fa-color-text-disabled)', color: 'var(--fa-color-text-disabled)',
opacity: 1, opacity: 1,
@@ -617,12 +618,12 @@ export const FuneralFinderV3 = React.forwardRef<HTMLDivElement, FuneralFinderV3P
loading={loading} loading={loading}
endIcon={!loading ? <ArrowForwardIcon /> : undefined} endIcon={!loading ? <ArrowForwardIcon /> : undefined}
onClick={handleSubmit} onClick={handleSubmit}
sx={{ minHeight: 52 }} sx={{ minHeight: { xs: 40, sm: 52 }, fontSize: { xs: '0.875rem', sm: undefined } }}
> >
Search Local Providers Search
</Button> </Button>
<Typography <Typography
variant="captionSm" variant="caption"
color="text.secondary" color="text.secondary"
sx={{ textAlign: 'center', display: 'block', mt: 1.5 }} sx={{ textAlign: 'center', display: 'block', mt: 1.5 }}
> >

View File

@@ -380,16 +380,109 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
)} )}
{/* ═══════════════════════════════════════════════════════════════════ {/* ═══════════════════════════════════════════════════════════════════
Section 2c: Discover — Map + Featured Providers (V2) Section 2b: Partner Logos Carousel
═══════════════════════════════════════════════════════════════════ */}
{partnerLogos.length > 0 && (
<Box
component="section"
aria-labelledby="partners-heading"
sx={{
bgcolor: 'var(--fa-color-surface-default)',
borderBottom: '1px solid #ebe0d4',
pt: { xs: 22, md: 28 },
pb: { xs: 10, md: 14 },
}}
>
<Container maxWidth="lg">
<Typography
variant="overline"
component="h2"
id="partners-heading"
sx={{
textAlign: 'center',
color: 'var(--fa-color-brand-600)',
mb: { xs: 6, md: 10 },
}}
>
{partnerTrustLine}
</Typography>
</Container>
{/* Carousel track */}
<Box
role="presentation"
sx={{
overflow: 'hidden',
position: 'relative',
'&::before, &::after': {
content: '""',
position: 'absolute',
top: 0,
bottom: 0,
width: 80,
zIndex: 1,
pointerEvents: 'none',
},
'&::before': {
left: 0,
background: 'linear-gradient(to right, #fff, transparent)',
},
'&::after': {
right: 0,
background: 'linear-gradient(to left, #fff, transparent)',
},
}}
>
<Box
aria-label="Partner funeral directors"
sx={{
display: 'flex',
gap: { xs: 8, md: 12 },
alignItems: 'center',
width: 'max-content',
animation: 'logoScroll 35s linear infinite',
'@keyframes logoScroll': {
'0%': { transform: 'translateX(0)' },
'100%': { transform: 'translateX(-50%)' },
},
'&:hover': { animationPlayState: 'paused' },
'@media (prefers-reduced-motion: reduce)': { animation: 'none' },
}}
>
{[...partnerLogos, ...partnerLogos].map((logo, i) => (
<Box
key={`${logo.alt}-${i}`}
component="img"
src={logo.src}
alt={i < partnerLogos.length ? logo.alt : ''}
aria-hidden={i >= partnerLogos.length ? true : undefined}
sx={{
height: { xs: 46, md: 55 },
maxWidth: { xs: 140, md: 184 },
width: 'auto',
objectFit: 'contain',
filter: 'grayscale(100%) brightness(1.2)',
opacity: 0.4,
flexShrink: 0,
}}
/>
))}
</Box>
</Box>
</Box>
)}
{/* ═══════════════════════════════════════════════════════════════════
Section 2c: Discover — Map + Featured Providers
═══════════════════════════════════════════════════════════════════ */} ═══════════════════════════════════════════════════════════════════ */}
{featuredProviders.length > 0 && ( {featuredProviders.length > 0 && (
<Box <Box
component="section" component="section"
aria-labelledby="discover-heading" aria-labelledby="discover-heading"
sx={{ sx={{
bgcolor: 'var(--fa-color-surface-subtle)', bgcolor: '#fdfbf9',
pt: { xs: 22, md: 28 }, pt: { xs: 10, md: 14 },
pb: { xs: 8, md: 12 }, pb: { xs: 10, md: 14 },
}} }}
> >
<Container maxWidth="lg"> <Container maxWidth="lg">
@@ -486,93 +579,208 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
)} )}
{/* ═══════════════════════════════════════════════════════════════════ {/* ═══════════════════════════════════════════════════════════════════
Section 3: Partner Logos Carousel Section 3b: Why Use FA — Text + Image
═══════════════════════════════════════════════════════════════════ */} ═══════════════════════════════════════════════════════════════════ */}
{partnerLogos.length > 0 && (
<Box <Box
component="section" component="section"
aria-label="Trusted partners" aria-labelledby="why-fa-heading"
sx={{ sx={{
bgcolor: 'var(--fa-color-surface-cool)', bgcolor: 'var(--fa-color-surface-default)',
pt: { xs: 10, md: 13 }, borderTop: '1px solid #f3efea',
pb: { xs: 8, md: 10 }, borderBottom: '1px solid #f3efea',
py: { xs: 10, md: 14 },
}} }}
> >
<Container maxWidth="lg"> <Container maxWidth="lg">
<Typography
variant="body1"
color="text.secondary"
sx={{ textAlign: 'center', mb: { xs: 4, md: 6 } }}
>
{partnerTrustLine}
</Typography>
</Container>
{/* Carousel track */}
<Box <Box
role="presentation"
sx={{ sx={{
overflow: 'hidden', display: 'grid',
position: 'relative', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' },
'&::before, &::after': { gap: { xs: 4, md: 8 },
content: '""',
position: 'absolute',
top: 0,
bottom: 0,
width: 80,
zIndex: 1,
pointerEvents: 'none',
},
'&::before': {
left: 0,
background:
'linear-gradient(to right, var(--fa-color-surface-cool), transparent)',
},
'&::after': {
right: 0,
background:
'linear-gradient(to left, var(--fa-color-surface-cool), transparent)',
},
}}
>
<Box
aria-label="Partner funeral directors"
sx={{
display: 'flex',
gap: { xs: 8, md: 12 },
alignItems: 'center', alignItems: 'center',
width: 'max-content',
animation: 'logoScroll 35s linear infinite',
'@keyframes logoScroll': {
'0%': { transform: 'translateX(0)' },
'100%': { transform: 'translateX(-50%)' },
},
'&:hover': { animationPlayState: 'paused' },
'@media (prefers-reduced-motion: reduce)': { animation: 'none' },
}} }}
> >
{[...partnerLogos, ...partnerLogos].map((logo, i) => ( {/* Text */}
<Box>
<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="why-fa-heading"
sx={{ mb: 2.5, color: 'text.primary' }}
>
Making an impossible time a little easier
</Typography>
<Typography variant="body1" color="text.secondary">
Funeral planning doesn&rsquo;t have to be overwhelming. Whether a loved one has
just passed, is imminent, or you&rsquo;re pre-planning the future for yourself.
Compare transparent pricing from local funeral directors. Explore the service
options, coffins and more to personalise a funeral plan in clear, easy steps.
</Typography>
</Box>
{/* Image */}
<Box <Box
key={`${logo.alt}-${i}`}
component="img"
src={logo.src}
alt={i < partnerLogos.length ? logo.alt : ''}
aria-hidden={i >= partnerLogos.length ? true : undefined}
sx={{ sx={{
height: { xs: 46, md: 55 }, borderRadius: 'var(--fa-border-radius-lg, 12px)',
maxWidth: { xs: 140, md: 184 }, overflow: 'hidden',
width: 'auto', '& img': {
objectFit: 'contain', width: '100%',
filter: 'grayscale(100%) brightness(1.2)', height: 'auto',
opacity: 0.4, display: 'block',
flexShrink: 0, },
}}
>
<img
src="/brandassets/images/Homepage/people.png"
alt="Family planning together with care and confidence"
/>
</Box>
</Box>
</Container>
</Box>
{/* ═══════════════════════════════════════════════════════════════════
Section 3c: What You Can Do Here — Three Feature Cards
═══════════════════════════════════════════════════════════════════ */}
<Box
component="section"
aria-labelledby="what-you-can-do-heading"
sx={{
bgcolor: '#f8f5f1',
py: { xs: 10, md: 14 },
}}
>
<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 }}
>
What You Can Do Here
</Typography>
<Typography
variant="display3"
component="h2"
id="what-you-can-do-heading"
sx={{ color: 'text.primary' }}
>
Three ways we can help you today
</Typography>
</Box>
<Box
sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', md: 'repeat(3, 1fr)' },
gap: { xs: 3, md: 4 },
}}
>
{/* Card 1: Compare pricing */}
<Box
sx={{
bgcolor: 'var(--fa-color-surface-default)',
borderRadius: 'var(--fa-card-border-radius-default, 8px)',
boxShadow: 'var(--fa-shadow-md)',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}}
>
<Box
sx={{
height: 200,
background:
'linear-gradient(135deg, var(--fa-color-brand-100) 0%, var(--fa-color-brand-200) 100%)',
}} }}
/> />
))} <Box sx={{ p: 3, flex: 1, display: 'flex', flexDirection: 'column' }}>
<Typography variant="h5" component="h3" sx={{ mb: 1.5, color: 'text.primary' }}>
Compare pricing
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3, flex: 1 }}>
See verified, itemised prices from multiple funeral directors in your area
side by side.
</Typography>
<Button variant="outlined" size="medium" fullWidth>
Compare prices in my area
</Button>
</Box>
</Box>
{/* Card 2: Find a funeral director */}
<Box
sx={{
bgcolor: 'var(--fa-color-surface-default)',
borderRadius: 'var(--fa-card-border-radius-default, 8px)',
boxShadow: 'var(--fa-shadow-md)',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}}
>
<Box
sx={{
height: 200,
background:
'linear-gradient(135deg, var(--fa-color-sage-100, #E8EDEF) 0%, var(--fa-color-sage-200, #D0D8DD) 100%)',
}}
/>
<Box sx={{ p: 3, flex: 1, display: 'flex', flexDirection: 'column' }}>
<Typography variant="h5" component="h3" sx={{ mb: 1.5, color: 'text.primary' }}>
Find a funeral director
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3, flex: 1 }}>
Browse rated, reviewed directors near you with profiles, photos, and contact
details.
</Typography>
<Button variant="outlined" size="medium" fullWidth>
Search near me
</Button>
</Box>
</Box>
{/* Card 3: Arrange a funeral */}
<Box
sx={{
bgcolor: 'var(--fa-color-surface-default)',
borderRadius: 'var(--fa-card-border-radius-default, 8px)',
boxShadow: 'var(--fa-shadow-md)',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}}
>
<Box
sx={{
height: 200,
background:
'linear-gradient(135deg, var(--fa-color-neutral-100) 0%, var(--fa-color-neutral-200) 100%)',
}}
/>
<Box sx={{ p: 3, flex: 1, display: 'flex', flexDirection: 'column' }}>
<Typography variant="h5" component="h3" sx={{ mb: 1.5, color: 'text.primary' }}>
Arrange a funeral
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3, flex: 1 }}>
Build a fully customised quote &mdash; choose coffin, flowers, transport,
venue, and more.
</Typography>
<Button variant="outlined" size="medium" fullWidth>
Start building your quote
</Button>
</Box> </Box>
</Box> </Box>
</Box> </Box>
)} </Container>
</Box>
{/* ═══════════════════════════════════════════════════════════════════ {/* ═══════════════════════════════════════════════════════════════════
Section 4: Why Use Funeral Arranger (Features) Section 4: Why Use Funeral Arranger (Features)
@@ -583,7 +791,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
aria-labelledby="features-heading" aria-labelledby="features-heading"
sx={{ sx={{
bgcolor: 'var(--fa-color-surface-default)', bgcolor: 'var(--fa-color-surface-default)',
py: { xs: 8, md: 12 }, py: { xs: 10, md: 14 },
}} }}
> >
<Container maxWidth="lg"> <Container maxWidth="lg">
@@ -648,8 +856,8 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
component="section" component="section"
aria-labelledby="reviews-heading" aria-labelledby="reviews-heading"
sx={{ sx={{
py: { xs: 8, md: 12 }, py: { xs: 10, md: 14 },
bgcolor: 'var(--fa-color-surface-subtle)', bgcolor: '#f8f5f1',
}} }}
> >
<Container maxWidth="md"> <Container maxWidth="md">
@@ -683,26 +891,29 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
</Box> </Box>
)} )}
{/* Editorial testimonials — alternating alignment with dividers */} {/* Editorial testimonials — left-aligned with dividers */}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0 }}> <Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 0,
maxWidth: 560,
mx: 'auto',
}}
>
{testimonials.map((t, i) => { {testimonials.map((t, i) => {
const isRight = i % 2 === 1;
return ( return (
<React.Fragment key={`${t.name}-${i}`}> <React.Fragment key={`${t.name}-${i}`}>
{i > 0 && <Divider sx={{ my: 4 }} />} {i > 0 && <Divider sx={{ my: 4 }} />}
<Box <Box
sx={{ sx={{
textAlign: isRight ? 'right' : 'left', textAlign: 'left',
maxWidth: '85%',
ml: isRight ? 'auto' : 0,
mr: isRight ? 0 : 'auto',
}} }}
> >
<FormatQuoteIcon <FormatQuoteIcon
sx={{ sx={{
fontSize: 32, fontSize: 32,
color: 'var(--fa-color-brand-300)', color: 'var(--fa-color-brand-300)',
transform: isRight ? 'scaleX(-1)' : 'none',
mb: 1, mb: 1,
}} }}
/> />
@@ -750,7 +961,7 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
sx={{ sx={{
background: background:
'linear-gradient(180deg, var(--fa-color-brand-100, #F5EDE4) 0%, var(--fa-color-surface-warm, #FEF9F5) 100%)', 'linear-gradient(180deg, var(--fa-color-brand-100, #F5EDE4) 0%, var(--fa-color-surface-warm, #FEF9F5) 100%)',
py: { xs: 8, md: 10 }, py: { xs: 10, md: 14 },
}} }}
> >
<Container maxWidth="md" sx={{ textAlign: 'center' }}> <Container maxWidth="md" sx={{ textAlign: 'center' }}>
@@ -777,17 +988,17 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
aria-labelledby="faq-heading" aria-labelledby="faq-heading"
sx={{ sx={{
bgcolor: 'var(--fa-color-surface-default)', bgcolor: 'var(--fa-color-surface-default)',
py: { xs: 8, md: 12 }, py: { xs: 10, md: 14 },
}} }}
> >
<Container maxWidth="lg"> <Container maxWidth="lg">
<Typography <Typography
variant="h2" variant="display3"
component="h2" component="h2"
id="faq-heading" id="faq-heading"
sx={{ textAlign: 'center', mb: { xs: 5, md: 8 }, color: 'text.primary' }} sx={{ textAlign: 'center', mb: { xs: 5, md: 8 }, color: 'text.primary' }}
> >
FAQ Frequently Asked Questions
</Typography> </Typography>
<Box sx={{ maxWidth: 700, mx: 'auto' }}> <Box sx={{ maxWidth: 700, mx: 'auto' }}>
@@ -823,6 +1034,11 @@ export const HomePage = React.forwardRef<HTMLDivElement, HomePageProps>(
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
))} ))}
<Box sx={{ textAlign: 'center', mt: 4 }}>
<Button variant="text" size="medium">
See more
</Button>
</Box>
</Box> </Box>
</Container> </Container>
</Box> </Box>

View File

@@ -240,7 +240,7 @@ const partnerLogos: PartnerLogo[] = [
// ─── Meta ──────────────────────────────────────────────────────────────────── // ─── Meta ────────────────────────────────────────────────────────────────────
const meta: Meta<typeof HomePage> = { const meta: Meta<typeof HomePage> = {
title: 'Archive/HomePage V3', title: 'Pages/HomePage',
component: HomePage, component: HomePage,
parameters: { parameters: {
layout: 'fullscreen', layout: 'fullscreen',
@@ -258,7 +258,7 @@ export const Default: Story = {
navigation: nav, navigation: nav,
footer, footer,
heroImageUrl: '/brandassets/images/heroes/hero-3.png', heroImageUrl: '/brandassets/images/heroes/hero-3.png',
heroHeading: 'Compare funeral directors pricing near you and arrange with confidence', heroHeading: 'Compare funeral director pricing near you and arrange with confidence',
heroSubheading: 'Transparent pricing \u00B7 No hidden fees \u00B7 Arrange 24/7', heroSubheading: 'Transparent pricing \u00B7 No hidden fees \u00B7 Arrange 24/7',
stats: trustStats, stats: trustStats,
featuredProviders, featuredProviders,
@@ -269,7 +269,7 @@ export const Default: Story = {
}), }),
onSelectFeaturedProvider: (id) => console.log('Featured provider:', id), onSelectFeaturedProvider: (id) => console.log('Featured provider:', id),
partnerLogos, partnerLogos,
partnerTrustLine: 'Trusted by hundreds of verified funeral directors across Australia', partnerTrustLine: 'Verified funeral directors on Funeral Arranger',
features, features,
googleRating: 4.9, googleRating: 4.9,
googleReviewCount: 2340, googleReviewCount: 2340,