Files
tenext-next/components/shared/PageTitleBanner.tsx
2026-08-03 14:42:01 +05:30

147 lines
4.8 KiB
TypeScript

import { siteConfig } from "@/data/site-config";
interface BreadcrumbItem {
label: string;
href?: string;
}
interface PageTitleBannerProps {
/** Page title — "About us", "Services", "Contacts" */
title: string;
/** Breadcrumb trail */
breadcrumbs: BreadcrumbItem[];
}
/**
* PageTitleBanner — shared inner-page hero banner.
*
* Used by: About, Services, Contacts pages.
*
* Structure (from reference):
* - Full-width rounded card with gradient background
* - Centered "/ Title /" text
* - Breadcrumbs bottom-left
* - Decorative "tenext" outline text right side
* - Top-left and bottom-right rounded corner decorations
*/
export function PageTitleBanner({ title, breadcrumbs }: PageTitleBannerProps) {
const breadcrumbJsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: breadcrumbs.map((crumb, index) => ({
"@type": "ListItem",
position: index + 1,
name: crumb.label,
...(crumb.href ? { item: `${siteConfig.url}${crumb.href}` } : {}),
})),
};
return (
<div className="relative mx-5 overflow-hidden rounded-[25px] bg-tenext-dark">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbJsonLd) }}
/>
{/* Background image */}
<div
className="absolute inset-0 bg-cover bg-center opacity-80"
style={{
backgroundImage: "url(/images/tenext/page-top-bg-min.png)",
}}
/>
{/* Gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-tenext-dark/60" />
{/* Top-left corner decoration */}
<div className="absolute left-0 top-0 h-20 w-20">
<div className="absolute left-0 top-0 h-full w-full rounded-br-[25px] bg-white" />
<div className="absolute left-0 top-0 h-full w-full rounded-tl-[25px] bg-tenext-dark">
<div
className="absolute inset-0 bg-cover bg-center opacity-80"
style={{
backgroundImage: "url(/images/tenext/page-top-bg-min.png)",
}}
/>
</div>
</div>
{/* Bottom-right corner decoration */}
<div className="absolute bottom-0 right-0 h-20 w-20">
<div className="absolute bottom-0 right-0 h-full w-full rounded-tl-[25px] bg-white" />
<div className="absolute bottom-0 right-0 h-full w-full rounded-br-[25px] bg-tenext-dark">
<div
className="absolute inset-0 bg-cover bg-center opacity-80"
style={{
backgroundImage: "url(/images/tenext/page-top-bg-min.png)",
}}
/>
</div>
</div>
{/* Content */}
<div className="relative z-10 flex min-h-[320px] flex-col items-center justify-center px-8 py-16 md:min-h-[400px] lg:min-h-[460px]">
{/* Title */}
<h1
className="text-center text-white"
style={{
fontFamily: "var(--font-sora)",
fontSize: "clamp(36px, 5vw, 72px)",
fontWeight: 700,
lineHeight: 1.1,
}}
>
<span className="mr-3 text-tenext-text-muted">/</span>
{title}
<span className="ml-3 text-tenext-text-muted">/</span>
</h1>
{/* Breadcrumbs */}
<nav
className="absolute bottom-8 left-8 md:bottom-10 md:left-12"
aria-label="Breadcrumb"
>
<ol className="flex items-center gap-2 text-sm text-white/70">
{breadcrumbs.map((crumb, index) => (
<li key={crumb.label} className="flex items-center gap-2">
{index > 0 && (
<span className="mx-1 inline-block h-1 w-1 rounded-full bg-tenext-teal" />
)}
{index < breadcrumbs.length - 1 && crumb.href ? (
<a
href={crumb.href}
className="transition-colors hover:text-tenext-teal"
>
{crumb.label}
</a>
) : (
<span className="text-white">{crumb.label}</span>
)}
</li>
))}
</ol>
</nav>
{/* Decorative vertical "tenext" text */}
<div
className="absolute bottom-8 right-8 hidden select-none lg:block"
style={{
writingMode: "vertical-rl",
textOrientation: "mixed",
}}
>
<span
className="font-sora text-[clamp(48px,5vw,72px)] font-bold leading-none tracking-tight"
style={{
WebkitTextStroke: "1px rgba(255,255,255,0.1)",
WebkitTextFillColor: "transparent",
}}
>
tenext
</span>
</div>
</div>
</div>
);
}