104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
"use client";
|
|
|
|
import { memo, type ReactNode } from "react";
|
|
import { getAssetPath } from "../../../../lib/assetUtils";
|
|
import type {
|
|
CenteredHeaderIcon,
|
|
CenteredHeaderSegment,
|
|
CenteredHeaderViewProps,
|
|
} from "./CenteredHeader.types";
|
|
|
|
const ICON_SRC: Record<CenteredHeaderIcon, string> = {
|
|
arrow: "assets/shapes/about-header-arrow.svg",
|
|
ring: "assets/shapes/about-header-ring.svg",
|
|
};
|
|
|
|
const ICON_CLASS: Record<CenteredHeaderIcon, string> = {
|
|
arrow: "size-10 md:size-[54px] lg:size-20",
|
|
ring: "size-8 md:size-[54px] lg:size-20",
|
|
};
|
|
|
|
/** Poster lines at 1024+, matching the desktop frame. Narrower widths wrap on their own. */
|
|
const DESKTOP_LINES = [[0], [1], [2, 3], [4, 5], [6, 7, 8]] as const;
|
|
|
|
function SegmentView({ segment }: { segment: CenteredHeaderSegment }) {
|
|
if (segment.type === "word") {
|
|
return (
|
|
<span className="font-bricolage-grotesque text-display-m whitespace-nowrap text-[var(--color-content-default-primary)] md:text-display-xl lg:text-display-xxl">
|
|
{segment.text}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<span
|
|
className={`inline-flex shrink-0 items-center justify-center ${ICON_CLASS[segment.icon]}`}
|
|
>
|
|
{/* eslint-disable-next-line @next/next/no-img-element -- decorative Figma mark */}
|
|
<img
|
|
src={getAssetPath(ICON_SRC[segment.icon])}
|
|
alt=""
|
|
width={80}
|
|
height={80}
|
|
className="size-full"
|
|
/>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function CenteredHeaderView({
|
|
accessibleName,
|
|
segments,
|
|
subhead,
|
|
credit,
|
|
}: CenteredHeaderViewProps) {
|
|
const desktopLines: ReactNode = DESKTOP_LINES.map((line) => (
|
|
<div key={line.join("-")} className="flex items-center justify-center gap-4">
|
|
{line.map((index) => {
|
|
const segment = segments[index];
|
|
return segment ? <SegmentView key={index} segment={segment} /> : null;
|
|
})}
|
|
</div>
|
|
));
|
|
|
|
return (
|
|
<section
|
|
data-figma-node="24214:25892"
|
|
className="flex flex-col items-center gap-[var(--space-600)] overflow-hidden bg-black px-[var(--space-600)] py-[var(--space-3000)] md:px-[var(--space-1800)]"
|
|
aria-labelledby="about-centered-header"
|
|
>
|
|
<h1 id="about-centered-header" className="sr-only">
|
|
{accessibleName}
|
|
</h1>
|
|
<div
|
|
aria-hidden
|
|
className="flex w-full flex-wrap items-center justify-center gap-x-3 gap-y-2 lg:hidden"
|
|
>
|
|
{segments.map((segment, index) => (
|
|
<SegmentView key={index} segment={segment} />
|
|
))}
|
|
</div>
|
|
<div
|
|
aria-hidden
|
|
className="hidden w-full max-w-[32rem] flex-col items-center gap-4 lg:flex"
|
|
>
|
|
{desktopLines}
|
|
</div>
|
|
<p className="max-w-[720px] text-center font-inter text-paragraph-m text-[var(--color-content-default-secondary)] md:text-paragraph-xl lg:font-bricolage-grotesque lg:text-display-s">
|
|
{subhead}
|
|
</p>
|
|
<div
|
|
className="h-px w-[295px] bg-[var(--color-border-default-secondary)]"
|
|
aria-hidden
|
|
/>
|
|
<p className="max-w-[720px] text-center font-inter text-label-xs text-[var(--color-content-default-tertiary)] md:text-label-s">
|
|
{credit}
|
|
</p>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
CenteredHeaderView.displayName = "CenteredHeaderView";
|
|
|
|
export default memo(CenteredHeaderView);
|