Interior page header: photo, breadcrumbs, title and optional stats (from Marbrook)
import { Bath, BedDouble, Maximize } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { Fragment } from "react";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { cn } from "@/lib/utils";
import type {
PageHeaderContent,
PageHeaderStatIcon,
} from "../_types/page-header";
import { defaultPageHeader1Content } from "./data";
const statIcons: Record<PageHeaderStatIcon, typeof Bath> = {
area: Maximize,
bath: Bath,
bed: BedDouble,
};
/**
* The interior-page counterpart to a photo hero: the same dual scrim and
* eyebrow, with a title one step down the scale so no interior page ever
* competes with the homepage h1.
*/
export default function PageHeader1({
content = defaultPageHeader1Content,
}: {
content?: PageHeaderContent;
}) {
return (
<section className="relative isolate flex min-h-[62vh] flex-col justify-end pt-28 pb-14 sm:pb-16">
<div className="absolute inset-0 -z-10 overflow-hidden">
<Image
alt={content.image.alt}
className="object-cover object-center"
fill
priority
sizes="100vw"
src={content.image.src}
/>
<div className="absolute inset-0 bg-linear-to-t from-primary/90 via-primary/50 to-primary/30" />
{/* Second pass from the left keeps the title legible over bright façades. */}
<div className="absolute inset-0 bg-linear-to-r from-primary/70 via-primary/20 to-transparent" />
</div>
<div className="mx-auto w-full max-w-7xl px-5 sm:px-8 lg:px-12">
<Breadcrumb>
<BreadcrumbList className="text-white/50 text-xs">
{content.breadcrumbs.map((crumb) => (
// The separator is a sibling <li>, never nested inside one.
<Fragment key={crumb.label}>
<BreadcrumbItem>
{crumb.href ? (
<BreadcrumbLink
className="hover:text-white"
render={<Link href={crumb.href} />}
>
{crumb.label}
</BreadcrumbLink>
) : (
<BreadcrumbPage className="text-white/80">
{crumb.label}
</BreadcrumbPage>
)}
</BreadcrumbItem>
{crumb.href && <BreadcrumbSeparator />}
</Fragment>
))}
</BreadcrumbList>
</Breadcrumb>
<p className="mt-8 inline-flex items-center gap-2 font-medium text-[0.6875rem] text-white/50 uppercase tracking-[0.22em]">
<span className="size-1 bg-secondary" />
{content.eyebrow}
</p>
<h1 className="mt-5 max-w-3xl font-display text-5xl text-white leading-[1.04] sm:text-6xl">
{content.title}
</h1>
{content.description && (
<p className="mt-6 max-w-xl text-white/70 leading-relaxed">
{content.description}
</p>
)}
{content.meta && (
<p className="mt-6 text-sm text-white/60">{content.meta}</p>
)}
{content.stats && content.stats.length > 0 && (
<div className="mt-9 border-white/20 border-t pt-6">
<dl className="grid grid-cols-2 gap-8 sm:grid-cols-4">
{content.stats.map((stat) => {
const Icon = stat.icon ? statIcons[stat.icon] : null;
return (
<div key={stat.label}>
<dd
className={cn(
"font-display text-2xl text-white sm:text-3xl",
Icon && "flex items-center gap-2",
)}
>
{Icon && <Icon className="size-5 text-white/60" />}
{stat.value}
</dd>
<dt className="mt-1 text-white/60 text-xs leading-snug">
{stat.label}
</dt>
</div>
);
})}
</dl>
</div>
)}
</div>
</section>
);
}