ruby homepage changes
This commit is contained in:
parent
94ebd0f614
commit
7777d4046e
7 changed files with 312 additions and 223 deletions
|
|
@ -3,11 +3,13 @@ import MapComponent from '../map/Map';
|
|||
import { apiUrl, assertOk, authHeaders, logNonAbortError } from '../../lib/api';
|
||||
import { formatValue } from '../../lib/format';
|
||||
import { zoomToResolution } from '../../lib/map-utils';
|
||||
import { FEATURE_GRADIENT } from '../../lib/consts';
|
||||
import { gradientToCss } from '../../lib/utils';
|
||||
import { SpinnerIcon } from '../ui/icons/SpinnerIcon';
|
||||
import type { FeatureMeta, HexagonData } from '../../types';
|
||||
|
||||
const DEMO_VIEW_START = { longitude: -1.9, latitude: 52.2, zoom: 5.5, pitch: 0 };
|
||||
const DEMO_VIEW_END = { longitude: -1.9, latitude: 52.2, zoom: 12, pitch: 0 };
|
||||
const DEMO_VIEW_START = { longitude: -0.12, latitude: 51.51, zoom: 5.5, pitch: 0 };
|
||||
const DEMO_VIEW_END = { longitude: -0.12, latitude: 51.51, zoom: 7, pitch: 0 };
|
||||
|
||||
function easeOutCubic(t: number): number {
|
||||
return 1 - Math.pow(1 - t, 3);
|
||||
|
|
@ -28,7 +30,7 @@ interface StageDef {
|
|||
|
||||
const STAGES: StageDef[] = [
|
||||
// 0: No filters — the problem
|
||||
{ filters: {} },
|
||||
{ filters: {}, colorFeature: 'Estimated current price' },
|
||||
// 1: Price filter — "affordable price"
|
||||
{
|
||||
filters: { 'Estimated current price': [0, 0.25] },
|
||||
|
|
@ -58,6 +60,7 @@ const STAGES: StageDef[] = [
|
|||
'Good+ primary schools within 5km': [0.3, 1],
|
||||
'Number of restaurants within 2km': [0.15, 1],
|
||||
},
|
||||
colorFeature: 'Number of restaurants within 2km',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -74,27 +77,26 @@ const STEPS: { heading: string | null; body: React.ReactNode }[] = [
|
|||
<strong className="text-navy-950 dark:text-warm-100">
|
||||
£300k–£400k
|
||||
</strong>{' '}
|
||||
on a home. Your research method? Scrolling through listings and hoping for the best.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed mb-4">
|
||||
Listings only show what's on the market <em>right now</em> — a tiny, random
|
||||
slice of what's actually out there. You'll never see the 3-bed Victorian on a
|
||||
quiet street that sold six months ago, or the one that'll list next month.
|
||||
</p>
|
||||
<p className="text-base italic text-warm-500 dark:text-warm-400">
|
||||
Your home is not a box of cereal. Don't let a discount on the wrong property distract
|
||||
you from finding the right one.
|
||||
on a home, somewhere commutable to work in, say, London. Your research method? Picking some areas you think are good based on word of mouth... then hope for the best.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
heading: 'Set your requirements. The map shows you where they intersect.',
|
||||
heading: null,
|
||||
body: (
|
||||
<p className="text-lg leading-relaxed">
|
||||
Say you want a home at an{' '}
|
||||
<strong className="text-navy-950 dark:text-warm-100">affordable price</strong>…
|
||||
</p>
|
||||
<>
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="shrink-0 w-8 h-8 rounded-full bg-teal-600 text-white flex items-center justify-center font-bold text-sm">
|
||||
1
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-navy-950 dark:text-warm-100">Set your must-haves</h3>
|
||||
</div>
|
||||
<p className="text-lg leading-relaxed">
|
||||
Say you want a home at an{' '}
|
||||
<strong className="text-navy-950 dark:text-warm-100">affordable price</strong>…
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
|
@ -110,33 +112,25 @@ const STEPS: { heading: string | null; body: React.ReactNode }[] = [
|
|||
{
|
||||
heading: null,
|
||||
body: (
|
||||
<>
|
||||
<p className="text-lg leading-relaxed mb-4">
|
||||
…and{' '}
|
||||
<strong className="text-navy-950 dark:text-warm-100">
|
||||
restaurants within walking distance
|
||||
</strong>
|
||||
.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed font-semibold text-navy-950 dark:text-warm-100">
|
||||
You haven't opened a single listing yet — and you already know exactly where to
|
||||
focus.
|
||||
</p>
|
||||
</>
|
||||
<p className="text-lg leading-relaxed">
|
||||
…and{' '}
|
||||
<strong className="text-navy-950 dark:text-warm-100">
|
||||
restaurants within walking distance
|
||||
</strong>
|
||||
.
|
||||
</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
heading: null,
|
||||
body: (
|
||||
<>
|
||||
<p className="text-xl font-bold text-navy-950 dark:text-warm-100 mb-2">
|
||||
That's just three filters.
|
||||
<p className="text-lg leading-relaxed mb-4 font-semibold text-navy-950 dark:text-warm-100">
|
||||
No area chosen. No listings browsed. Yet you already know exactly where your needs are met.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed">
|
||||
We've built <strong className="text-navy-950 dark:text-warm-100">43</strong>.
|
||||
Spanning property prices, commute times, school ratings, crime rates, broadband speeds,
|
||||
road noise, energy efficiency, amenities, deprivation scores, demographics, and more. All
|
||||
layered on top of each other, all filterable at once.
|
||||
That's just 3 filters. We've built <strong className="text-navy-950 dark:text-warm-100">56</strong> —
|
||||
covering commute times, crime, broadband, noise, schools, amenities, and more.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
|
|
@ -318,7 +312,7 @@ export default function ScrollStory({ features, theme }: ScrollStoryProps) {
|
|||
const deferredHexData = useDeferredValue(hexData);
|
||||
|
||||
return (
|
||||
<section ref={sectionRef} className="relative">
|
||||
<section ref={sectionRef} className="snap-start relative">
|
||||
{/* Sticky map background */}
|
||||
<div className="sticky top-0 h-[60vh] md:h-[calc(100dvh-3rem)] z-0">
|
||||
<div className="absolute inset-0">
|
||||
|
|
@ -396,6 +390,23 @@ export default function ScrollStory({ features, theme }: ScrollStoryProps) {
|
|||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Color legend */}
|
||||
{viewFeatureName && colorRange && (
|
||||
<div className="pt-4 border-t border-warm-200 dark:border-warm-700 transition-opacity duration-700">
|
||||
<div className="text-xs font-semibold uppercase tracking-wider text-warm-500 dark:text-warm-400 mb-2">
|
||||
Colour
|
||||
</div>
|
||||
<div className="text-sm font-medium text-navy-950 dark:text-warm-100 mb-1.5">
|
||||
{viewFeatureName}
|
||||
</div>
|
||||
<div className="h-2.5 rounded-full overflow-hidden" style={{ background: gradientToCss(FEATURE_GRADIENT) }} />
|
||||
<div className="flex justify-between mt-1 text-xs text-warm-500 dark:text-warm-400">
|
||||
<span>{formatValue(colorRange[0], viewMeta!)}</span>
|
||||
<span>{formatValue(colorRange[1], viewMeta!)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue