106 lines
4.2 KiB
TypeScript
106 lines
4.2 KiB
TypeScript
import { cn } from "@/lib/utils";
|
||
import { flags } from "@/lib/site";
|
||
import { about as aboutDe, type HomeContent } from "@/content/home";
|
||
import { Section } from "@/components/layout/Section";
|
||
import { Lines } from "@/components/motion/Lines";
|
||
import { Reveal } from "@/components/motion/Reveal";
|
||
import { Rule } from "@/components/motion/Rule";
|
||
import { Eyebrow } from "@/components/ui/Eyebrow";
|
||
import { Ledger } from "@/components/ui/Ledger";
|
||
import { Marginalia } from "@/components/ui/Marginalia";
|
||
import { Portrait } from "@/components/ui/Portrait";
|
||
|
||
export interface AboutProps {
|
||
/** `getPhotos().portrait` – `null` renders the documented variant B (no photo). */
|
||
photo: string | null;
|
||
/** Inhalt der Sektion. Ohne Angabe die deutsche Fassung – die englische reicht sie durch. */
|
||
content?: HomeContent["about"];
|
||
}
|
||
|
||
/* H2 on ivory: Playfair 400, max 14ch (spec §3.2 / §6.5). */
|
||
const H2 =
|
||
"font-display text-[clamp(2.25rem,1.4rem+3.2vw,4.75rem)] font-normal leading-[1.02] tracking-[-0.01em] text-fg [text-wrap:balance] max-w-[14ch]";
|
||
|
||
/* Body: Jost 400, 18 px, max 36rem, paragraph gap 1.25em, German hyphenation. */
|
||
const BODY = "max-w-[36rem] font-sans text-[1.125rem] leading-[1.6] text-fg [hyphens:auto]";
|
||
|
||
/**
|
||
* 04 · Über Anelia (ivory – spec §6.5). First person, a portrait that stays
|
||
* in view while reading, the Werdegang as a ledger, marginalia with
|
||
* verifiable facts. No counters, no logos.
|
||
*
|
||
* With photo: Portrait cols 3–6 (sticky) · text + ledger cols 7–12 · marginalia cols 10–12.
|
||
* Without: text cols 3–8 · ledger cols 3–9 · marginalia under the ledger
|
||
* (no monogram vignette – see below).
|
||
*/
|
||
export function About({ photo, content: about = aboutDe }: AboutProps) {
|
||
const paragraphs = about.paragraphs.map((p, i) =>
|
||
i === about.paragraphs.length - 1 && flags.showTwins ? `${p} ${about.twins}` : p,
|
||
);
|
||
const hasPhoto = Boolean(photo);
|
||
|
||
return (
|
||
<div data-theme="light" className="relative bg-transparent text-fg">
|
||
<Rule variant="gold" />
|
||
<Section
|
||
id={about.id}
|
||
theme="light"
|
||
numeral={about.numeral}
|
||
label={about.eyebrow}
|
||
className="py-[clamp(4.5rem,10vh,8rem)] md:py-[clamp(7rem,16vh,14rem)]"
|
||
>
|
||
{hasPhoto && (
|
||
<div className="col-span-12 mb-14 lg:col-span-4 lg:col-start-3 lg:mb-0">
|
||
<Portrait
|
||
src={photo}
|
||
alt={about.alt}
|
||
aspect="4/5"
|
||
caption={about.caption}
|
||
sticky
|
||
parallax
|
||
sizes="(min-width: 1024px) 30vw, 100vw"
|
||
className="w-full max-w-[48svh] lg:max-w-none"
|
||
/>
|
||
</div>
|
||
)}
|
||
|
||
<div className={cn("col-span-12 lg:row-start-1", hasPhoto ? "lg:col-span-6 lg:col-start-7" : "lg:col-span-6 lg:col-start-3")}>
|
||
<Eyebrow className="mb-8">{about.eyebrow}</Eyebrow>
|
||
<Lines as="h2" className={H2}>
|
||
{about.h2.before}
|
||
{about.h2.em && <em className="italic">{about.h2.em}</em>}
|
||
{about.h2.after}
|
||
</Lines>
|
||
<div className="mt-10 flex flex-col gap-[1.25em]">
|
||
{paragraphs.map((text, i) => (
|
||
<Reveal key={i} as="p" delay={i * 0.08} className={BODY}>
|
||
{text}
|
||
</Reveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Werdegang ledger: cols 7–12 beside the photo, cols 3–9 without. */}
|
||
<div className={cn("col-span-12 mt-12 lg:row-start-2 lg:mt-16", hasPhoto ? "lg:col-span-6 lg:col-start-7" : "lg:col-span-7 lg:col-start-3")}>
|
||
<Ledger variant="werdegang" rows={about.werdegang} stagger={0.08} />
|
||
</div>
|
||
|
||
{/* No monogram vignette in variant B: the WOLF-Prinzip closer directly
|
||
above already ends on a full-height mark, and section 04 now carries
|
||
the sticky Bodoni numeral it was missing – a third W in the same
|
||
viewport turned the signature into wallpaper. */}
|
||
<Reveal
|
||
className={cn(
|
||
"col-span-12 mt-12",
|
||
hasPhoto ? "lg:col-span-3 lg:col-start-10 lg:row-start-2" : "lg:col-span-7 lg:col-start-3 lg:row-start-3",
|
||
)}
|
||
>
|
||
<Marginalia items={about.marginalia} />
|
||
</Reveal>
|
||
</Section>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default About;
|