feat: the homepage leads the visitor through as one story
The page was a row of sections to scroll past, and a film in one of them did not change that. It now follows the questions a visitor has, in the order they come up: who is this, can he do what I need, what does it look like, what else, how does it go, has he done it, what is open, how do I start. Each chapter ends by asking the next question as a large link that leads on, and the next chapter answers it. A rail at the edge shows every chapter as a station with a dot travelling along it (on phones: a pill with the current chapter and one tap to the next), and the header names the current question. Where the visitor is, is pure logic in src/domain/chapters.ts. The scroll film section and the bridge sentences are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { BitAura } from "@/src/components/bits/BitAura";
|
||||
import { OrderFilm } from "@/src/components/film/OrderFilm";
|
||||
import { Block } from "@/src/components/home/Block";
|
||||
import { ClosingCta } from "@/src/components/home/ClosingCta";
|
||||
import { Faq } from "@/src/components/home/Faq";
|
||||
@@ -19,9 +18,11 @@ import {
|
||||
} from "@/src/components/illustrations/WebPresentation";
|
||||
import { WorkShowcase } from "@/src/components/illustrations/WorkShowcase";
|
||||
import { Reveal } from "@/src/components/Reveal";
|
||||
import { NextChapter } from "@/src/components/story/Chapter";
|
||||
import { StoryGuide } from "@/src/components/story/StoryGuide";
|
||||
import { SwipeRow } from "@/src/components/SwipeRow";
|
||||
import { contentFor } from "@/src/content";
|
||||
import type { SplitTitle } from "@/src/content/types";
|
||||
import type { ChapterId, SplitTitle } from "@/src/content/types";
|
||||
import { DEFAULT_LOCALE, parseLocale } from "@/src/domain/locale";
|
||||
import { languageAlternates, pathFor } from "@/src/domain/routes";
|
||||
|
||||
@@ -69,11 +70,28 @@ export default async function LandingPage({ params }: Props) {
|
||||
faq,
|
||||
} = content;
|
||||
|
||||
/** What makes a section a chapter, and the hand-over to the one after it. */
|
||||
const chapter = (id: ChapterId) => {
|
||||
const at = story.chapters.findIndex((item) => item.id === id);
|
||||
const own = story.chapters[at];
|
||||
const after = story.chapters[at + 1];
|
||||
return {
|
||||
chapter: own && { id: own.id },
|
||||
next: after && {
|
||||
id: after.id,
|
||||
label: story.next,
|
||||
question: after.question,
|
||||
},
|
||||
};
|
||||
};
|
||||
const afterHello = chapter("hello").next;
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col bg-white">
|
||||
<HomeJsonLd locale={locale} />
|
||||
<HeroStatement hero={content.hero} />
|
||||
<StickyBook />
|
||||
<StoryGuide />
|
||||
|
||||
<PortraitSection
|
||||
id="hello"
|
||||
@@ -101,13 +119,14 @@ export default async function LandingPage({ params }: Props) {
|
||||
{hello.careerLabel}
|
||||
</p>
|
||||
<CareerLine stations={hello.career} />
|
||||
{afterHello && <NextChapter {...afterHello} dark />}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Block
|
||||
index="02"
|
||||
label={services.label}
|
||||
bridge={story.services}
|
||||
{...chapter("services")}
|
||||
title={<Title title={services.title} />}
|
||||
>
|
||||
<Reveal>
|
||||
@@ -115,12 +134,10 @@ export default async function LandingPage({ params }: Props) {
|
||||
</Reveal>
|
||||
</Block>
|
||||
|
||||
<OrderFilm />
|
||||
|
||||
<Block
|
||||
index="03"
|
||||
label={automation.label}
|
||||
bridge={story.automation}
|
||||
{...chapter("automation")}
|
||||
title={<Title title={automation.title} />}
|
||||
>
|
||||
<Reveal>
|
||||
@@ -153,7 +170,7 @@ export default async function LandingPage({ params }: Props) {
|
||||
<Block
|
||||
index="04"
|
||||
label={presentations.label}
|
||||
bridge={story.presentations}
|
||||
{...chapter("presentations")}
|
||||
tone="dark"
|
||||
title={<Title title={presentations.title} muted="text-slate-500" />}
|
||||
>
|
||||
@@ -226,7 +243,7 @@ export default async function LandingPage({ params }: Props) {
|
||||
<Block
|
||||
index="05"
|
||||
label={working.label}
|
||||
bridge={story.working}
|
||||
{...chapter("working")}
|
||||
title={<Title title={working.title} />}
|
||||
>
|
||||
<Reveal>
|
||||
@@ -277,7 +294,7 @@ export default async function LandingPage({ params }: Props) {
|
||||
<Block
|
||||
index="06"
|
||||
label={work.label}
|
||||
bridge={story.work}
|
||||
{...chapter("work")}
|
||||
tone="dark"
|
||||
title={<Title title={work.title} muted="text-slate-500" />}
|
||||
>
|
||||
@@ -292,7 +309,7 @@ export default async function LandingPage({ params }: Props) {
|
||||
<Block
|
||||
index="07"
|
||||
label={faq.label}
|
||||
bridge={story.faq}
|
||||
{...chapter("faq")}
|
||||
title={<Title title={faq.title} />}
|
||||
>
|
||||
<Reveal>
|
||||
|
||||
@@ -1339,6 +1339,23 @@ pre:has(code[class*="language-"]) {
|
||||
}
|
||||
}
|
||||
|
||||
/* The story guide: the dot that travels along the chapter rail, and the header line. */
|
||||
.story-dot {
|
||||
box-shadow:
|
||||
0 0 0 3px rgba(253, 230, 138, 0.35),
|
||||
0 0 14px 3px rgba(251, 191, 36, 0.8);
|
||||
transition: top 200ms linear;
|
||||
}
|
||||
.story-now {
|
||||
animation: story-now-in 400ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
@keyframes story-now-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(6px);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Native feel: the page should behave like a well-made app on every input type.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user