Translate pages
This commit is contained in:
parent
a7aaf5effa
commit
96402228e3
49 changed files with 1458 additions and 926 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useFadeInRef } from '../../hooks/useFadeIn';
|
||||
import HexCanvas from './HexCanvas';
|
||||
import BottomIllustration from './BottomIllustration';
|
||||
|
|
@ -17,6 +18,7 @@ export default function HomePage({
|
|||
theme?: 'light' | 'dark';
|
||||
hidePricing?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [statsActive, setStatsActive] = useState(false);
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => setStatsActive(true), 300);
|
||||
|
|
@ -66,16 +68,15 @@ export default function HomePage({
|
|||
<div className="relative z-10 max-w-4xl mx-auto px-6 md:px-10 pt-16 md:pt-24 backdrop-blur-[2px] flex-1 flex flex-col">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-5xl font-extrabold text-white mb-4 leading-[1.1] tracking-tight">
|
||||
Maximum <span className="text-teal-400">Value</span>.
|
||||
{t('home.heroTitle1')} <span className="text-teal-400">{t('home.heroTitle2')}</span>.
|
||||
<br />
|
||||
Minimum Compromise.
|
||||
{t('home.heroTitle3')}
|
||||
</h1>
|
||||
<p className="text-lg text-warm-300 mb-6 leading-relaxed max-w-xl">
|
||||
House hunting? Make your biggest investment your smartest move.
|
||||
{t('home.heroSubtitle')}
|
||||
</p>
|
||||
<p className="text-lg text-warm-400 mb-8 max-w-xl">
|
||||
So many options - choosing the right one can feel overwhelming. Our interactive map
|
||||
makes it simple: select your must-haves and instantly see the areas that fit.
|
||||
{t('home.heroDescription')}
|
||||
</p>
|
||||
<div className="flex items-center gap-4 mb-10">
|
||||
<button
|
||||
|
|
@ -85,7 +86,7 @@ export default function HomePage({
|
|||
}}
|
||||
className="px-7 py-3.5 bg-coral-500 text-white rounded-lg font-semibold hover:bg-coral-600 transition-colors text-base shadow-lg shadow-coral-500/25"
|
||||
>
|
||||
Explore the map
|
||||
{t('home.exploreTheMap')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
@ -105,16 +106,16 @@ export default function HomePage({
|
|||
let startTime: number;
|
||||
const step = (time: number) => {
|
||||
if (!startTime) startTime = time;
|
||||
const t = Math.min((time - startTime) / duration, 1);
|
||||
const ease = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
||||
const p = Math.min((time - startTime) / duration, 1);
|
||||
const ease = p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;
|
||||
scroller.scrollTop = start + distance * ease;
|
||||
if (t < 1) requestAnimationFrame(step);
|
||||
if (p < 1) requestAnimationFrame(step);
|
||||
};
|
||||
requestAnimationFrame(step);
|
||||
}}
|
||||
className="px-[26px] py-[12px] border-2 border-teal-400 text-teal-400 rounded-lg font-semibold hover:bg-teal-400/10 transition-colors text-base"
|
||||
>
|
||||
See the difference
|
||||
{t('home.seeTheDifference')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex gap-12 pt-3 border-t border-white/10">
|
||||
|
|
@ -122,17 +123,17 @@ export default function HomePage({
|
|||
<div className="text-2xl md:text-3xl font-bold text-white">
|
||||
<TickerValue text="13M" active={statsActive} />
|
||||
</div>
|
||||
<div className="text-sm text-warm-400">properties</div>
|
||||
<div className="text-sm text-warm-400">{t('home.statProperties')}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl md:text-3xl font-bold text-white">
|
||||
<TickerValue text="56" active={statsActive} />
|
||||
</div>
|
||||
<div className="text-sm text-warm-400">filters</div>
|
||||
<div className="text-sm text-warm-400">{t('home.statFilters')}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl md:text-3xl font-bold text-white">Every</div>
|
||||
<div className="text-sm text-warm-400">postcode in England</div>
|
||||
<div className="text-2xl md:text-3xl font-bold text-white">{t('home.statEvery')}</div>
|
||||
<div className="text-sm text-warm-400">{t('home.statPostcodeInEngland')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -143,17 +144,14 @@ export default function HomePage({
|
|||
{/* Our philosophy */}
|
||||
<div className="px-6 md:px-12 lg:px-20 pt-20 pb-4">
|
||||
<h2 className="text-3xl font-bold text-navy-950 dark:text-warm-100 mb-6">
|
||||
Our philosophy
|
||||
{t('home.ourPhilosophy')}
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg md:text-xl leading-relaxed text-warm-700 dark:text-warm-300">
|
||||
<p>
|
||||
On Rightmove, you pick an area first, then hope it's good. You end up
|
||||
cross-referencing crime stats, school reports, and broadband checkers across a dozen
|
||||
tabs, one postcode at a time.
|
||||
{t('home.philosophyP1')}
|
||||
</p>
|
||||
<p>
|
||||
We flip that. Tell us what you need (budget, commute, schools, safety) and we show you
|
||||
every area in England that qualifies. No guesswork. No wasted viewings.
|
||||
{t('home.philosophyP2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -165,10 +163,15 @@ export default function HomePage({
|
|||
{/* Left: How to use it */}
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold text-navy-950 dark:text-warm-100 mb-10">
|
||||
How to use it
|
||||
{t('home.howToUseIt')}
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{HOW_STEPS.map((step, i) => (
|
||||
{[
|
||||
{ title: t('home.howStep1Title'), desc: t('home.howStep1Desc') },
|
||||
{ title: t('home.howStep2Title'), desc: t('home.howStep2Desc') },
|
||||
{ title: t('home.howStep3Title'), desc: t('home.howStep3Desc') },
|
||||
{ title: t('home.howStep4Title'), desc: t('home.howStep4Desc') },
|
||||
].map((step, i) => (
|
||||
<div key={i} className="flex gap-5">
|
||||
<div className="shrink-0 w-10 h-10 rounded-full bg-teal-600 text-white flex items-center justify-center font-bold text-lg">
|
||||
{i + 1}
|
||||
|
|
@ -178,7 +181,7 @@ export default function HomePage({
|
|||
{step.title}
|
||||
</h3>
|
||||
<p className="text-warm-600 dark:text-warm-400 leading-relaxed">
|
||||
{step.description}
|
||||
{step.desc}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -188,9 +191,9 @@ export default function HomePage({
|
|||
{/* Right: Comparison table */}
|
||||
<div id="comparison">
|
||||
<h2 className="text-3xl font-bold text-navy-950 dark:text-warm-100 mb-10">
|
||||
Others vs{' '}
|
||||
{t('home.othersVs')}{' '}
|
||||
<span className="inline-flex items-baseline gap-3 whitespace-nowrap">
|
||||
Perfect Postcode{' '}
|
||||
{t('header.appName')}{' '}
|
||||
<LogoIcon className="w-8 h-8 text-teal-600 dark:text-teal-400" />
|
||||
</span>
|
||||
</h2>
|
||||
|
|
@ -200,25 +203,30 @@ export default function HomePage({
|
|||
<tr className="border-b border-warm-200 dark:border-warm-700 bg-warm-50 dark:bg-warm-800">
|
||||
<th className="px-2 md:px-5 py-3 md:py-4 text-xs md:text-sm font-bold text-navy-950 dark:text-warm-100" />
|
||||
<th className="px-1.5 md:px-3 py-3 md:py-4 text-[10px] md:text-xs font-bold text-navy-950 dark:text-warm-100 text-center">
|
||||
Listing portals
|
||||
{t('home.listingPortals')}
|
||||
</th>
|
||||
<th className="px-1.5 md:px-3 py-3 md:py-4 text-[10px] md:text-xs font-bold text-navy-950 dark:text-warm-100 text-center">
|
||||
{'\u201CCheck my postcode\u201D'}
|
||||
{t('home.checkMyPostcode')}
|
||||
</th>
|
||||
<th className="px-1.5 md:px-3 py-3 md:py-4 text-[10px] md:text-xs font-bold text-navy-950 dark:text-warm-100 text-center">
|
||||
Area guides
|
||||
{t('home.areaGuides')}
|
||||
</th>
|
||||
<th className="px-1.5 md:px-3 py-3 md:py-4 text-[10px] md:text-xs font-extrabold text-navy-950 dark:text-warm-100 text-center bg-teal-50 dark:bg-teal-900/30">
|
||||
Perfect Postcode
|
||||
{t('header.appName')}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{FEATURE_ROWS.map((row, i) => (
|
||||
{[
|
||||
{ feature: t('home.compSearchWithout'), subtitle: t('home.compSearchWithoutSub'), listings: false, postcode: false, guides: false },
|
||||
{ feature: t('home.compAreaData'), subtitle: t('home.compAreaDataSub'), listings: false, postcode: true, guides: true },
|
||||
{ feature: t('home.compPropertyData'), subtitle: t('home.compPropertyDataSub'), listings: true, postcode: false, guides: false },
|
||||
{ feature: t('home.compFilters'), subtitle: t('home.compFiltersSub'), listings: false, postcode: false, guides: false },
|
||||
].map((row, i, arr) => (
|
||||
<tr
|
||||
key={row.feature}
|
||||
key={i}
|
||||
className={
|
||||
i < FEATURE_ROWS.length - 1
|
||||
i < arr.length - 1
|
||||
? 'border-b border-warm-100 dark:border-warm-800'
|
||||
: ''
|
||||
}
|
||||
|
|
@ -256,10 +264,10 @@ export default function HomePage({
|
|||
<div className="max-w-4xl mx-auto px-6 pt-20 pb-12">
|
||||
<div ref={ctaRef} className="fade-in-section text-center">
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-navy-950 dark:text-warm-100 mb-4 leading-snug">
|
||||
Make your biggest investment your smartest move.
|
||||
{t('home.ctaTitle')}
|
||||
</h2>
|
||||
<p className="text-warm-600 dark:text-warm-400 mb-8 max-w-xl mx-auto leading-relaxed">
|
||||
This deserves proper tools behind it, don't leave it to luck.
|
||||
{t('home.ctaDescription')}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
@ -268,7 +276,7 @@ export default function HomePage({
|
|||
}}
|
||||
className="px-8 py-4 bg-coral-500 text-white rounded-lg font-semibold hover:bg-coral-600 transition-colors text-lg shadow-lg shadow-coral-500/25"
|
||||
>
|
||||
Explore the map
|
||||
{t('home.exploreTheMap')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -280,54 +288,3 @@ export default function HomePage({
|
|||
);
|
||||
}
|
||||
|
||||
const FEATURE_ROWS = [
|
||||
// listings postcode guides
|
||||
{
|
||||
feature: 'Search without choosing an area first',
|
||||
subtitle: '(start with needs, not a location)',
|
||||
listings: false,
|
||||
postcode: false,
|
||||
guides: false,
|
||||
},
|
||||
{
|
||||
feature: 'Area data',
|
||||
subtitle: '(crime, schools, noise, broadband)',
|
||||
listings: false,
|
||||
postcode: true,
|
||||
guides: true,
|
||||
},
|
||||
{
|
||||
feature: 'Property-specific data',
|
||||
subtitle: '(price, EPC, floor area)',
|
||||
listings: true,
|
||||
postcode: false,
|
||||
guides: false,
|
||||
},
|
||||
{
|
||||
feature: '56 combinable filters in one place',
|
||||
subtitle: '(all insights, one interactive map)',
|
||||
listings: false,
|
||||
postcode: false,
|
||||
guides: false,
|
||||
},
|
||||
];
|
||||
|
||||
const HOW_STEPS = [
|
||||
{
|
||||
title: 'Set your must-haves',
|
||||
description: 'Budget, commute, schools \u2014 the map shows only what qualifies.',
|
||||
},
|
||||
{
|
||||
title: 'Explore areas and discover hidden gems',
|
||||
description: 'Zoom in, dig into details and nice to haves.',
|
||||
},
|
||||
{
|
||||
title: 'Drill into postcodes',
|
||||
description: 'See individual properties, sale prices, floor area, and compare.',
|
||||
},
|
||||
{
|
||||
title: 'Shortlist with confidence',
|
||||
description:
|
||||
'Every area on your list meets your actual criteria \u2014 not just what was listed that week.',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue