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>
93 lines
3.6 KiB
TypeScript
93 lines
3.6 KiB
TypeScript
"use client";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import * as React from "react";
|
|
|
|
import { pathFor } from "@/src/domain/routes";
|
|
import IconWhite from "../assets/logo/Icon-White-Transparent.svg";
|
|
import { DecodeText } from "./bits/DecodeText";
|
|
import { ScrollBits } from "./bits/ScrollBits";
|
|
import { useContent, useLocale } from "./ContentProvider";
|
|
import { LanguageSwitch } from "./LanguageSwitch";
|
|
import { ChapterNow } from "./story/StoryGuide";
|
|
|
|
/** Header: the logo, the link to the freelance page, the language switch and one action. */
|
|
export const Header: React.FC = () => {
|
|
const { nav } = useContent();
|
|
const locale = useLocale();
|
|
const home = pathFor("home", locale);
|
|
const freelance = pathFor("freelance", locale);
|
|
const [isScrolled, setIsScrolled] = React.useState(false);
|
|
|
|
React.useEffect(() => {
|
|
const handleScroll = () => {
|
|
setIsScrolled(window.scrollY > 20);
|
|
};
|
|
window.addEventListener("scroll", handleScroll);
|
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
}, []);
|
|
|
|
return (
|
|
<header className="sticky top-0 z-[100] w-full">
|
|
{/* Decoupled Background Layer - Prevents backdrop-filter parent context bugs */}
|
|
<div
|
|
className={`absolute inset-0 transition-all duration-500 -z-10 ${
|
|
isScrolled
|
|
? "bg-white/70 backdrop-blur-xl border-b border-slate-100 shadow-sm shadow-slate-100/50"
|
|
: "bg-white/80 backdrop-blur-md border-b border-slate-50"
|
|
}`}
|
|
/>
|
|
|
|
<div className="mx-auto w-full max-w-[1400px] px-5 md:px-12 py-4 flex items-center justify-between relative z-10">
|
|
<Link
|
|
href={home}
|
|
aria-label={nav.logoLabel}
|
|
onClick={(event) => {
|
|
// Already on the homepage: scroll up instead of reloading the route.
|
|
if (window.location.pathname === home) {
|
|
event.preventDefault();
|
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
}
|
|
}}
|
|
className="flex items-center gap-4 group"
|
|
>
|
|
<div className="w-10 h-10 md:w-12 md:h-12 bg-black rounded-xl flex items-center justify-center group-hover:scale-105 transition-all duration-500 shadow-sm shrink-0 relative overflow-hidden">
|
|
<Image
|
|
src={IconWhite}
|
|
alt=""
|
|
width={32}
|
|
height={32}
|
|
className="w-6 h-6 md:w-8 md:h-8 relative z-10"
|
|
/>
|
|
</div>
|
|
</Link>
|
|
|
|
<ChapterNow
|
|
fallback={
|
|
<ScrollBits className="hidden font-mono text-[10px] tracking-[0.3em] text-slate-400 md:block" />
|
|
}
|
|
/>
|
|
|
|
<div className="flex items-center gap-2.5 md:gap-4">
|
|
<Link
|
|
href={freelance}
|
|
className="hidden font-sans text-[10px] font-bold uppercase tracking-[0.2em] text-slate-500 no-underline transition-colors duration-300 hover:text-slate-900 md:block"
|
|
>
|
|
{nav.freelance}
|
|
</Link>
|
|
<LanguageSwitch />
|
|
<Link
|
|
href={`${home}#contact`}
|
|
className="bit-cta bit-cta-quiet font-sans text-[10px] font-bold uppercase tracking-[0.2em] text-slate-900 border border-slate-200 px-5 py-2.5 rounded-full no-underline hover:border-slate-400 hover:bg-slate-50 transition-all duration-500 hover:-translate-y-0.5 hover:shadow-lg hover:shadow-slate-100"
|
|
style={{
|
|
transitionTimingFunction: "cubic-bezier(0.23, 1, 0.32, 1)",
|
|
}}
|
|
>
|
|
<DecodeText text={nav.contact} trigger="hover" />
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
};
|