Rocky_Mountain_Vending/components/dropdown-page-shell.tsx

138 lines
4.3 KiB
TypeScript

import type { ReactNode } from "react"
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Breadcrumbs, type BreadcrumbItem } from "@/components/breadcrumbs"
import {
PublicInset,
PublicPageHeader,
PublicProse,
PublicSurface,
} from "@/components/public-surface"
import { cn } from "@/lib/utils"
type ShellAction = {
label: string
href: string
variant?: "default" | "outline"
}
interface DropdownPageShellProps {
breadcrumbs: BreadcrumbItem[]
eyebrow?: string
title: string
description?: string
headerContent?: ReactNode
contentIntro?: ReactNode
content: ReactNode
contentClassName?: string
contentSurfaceClassName?: string
sections?: ReactNode
cta?: {
eyebrow?: string
title: string
description: string
actions: ShellAction[]
note?: ReactNode
}
className?: string
}
export function DropdownPageShell({
breadcrumbs,
eyebrow,
title,
description,
headerContent,
contentIntro,
content,
contentClassName,
contentSurfaceClassName,
sections,
cta,
className,
}: DropdownPageShellProps) {
return (
<div className={cn("public-page", className)}>
<Breadcrumbs className="mb-6" items={breadcrumbs} />
<PublicPageHeader
align="center"
eyebrow={eyebrow}
title={title}
description={description}
>
{headerContent}
</PublicPageHeader>
{contentIntro ? (
<section className="mt-10 grid gap-5 lg:grid-cols-2">{contentIntro}</section>
) : null}
<section className={cn(contentIntro ? "mt-8" : "mt-10")}>
<PublicSurface
className={cn(
"relative overflow-hidden p-0 md:p-0",
contentSurfaceClassName
)}
>
<div className="absolute inset-x-0 top-0 h-24 bg-[radial-gradient(circle_at_top,rgba(41,160,71,0.09),transparent_74%)]" />
<div className="relative p-5 md:p-7 lg:p-10">
<div className="mb-8 flex items-center justify-between gap-4 border-b border-border/55 pb-5">
<div>
<p className="text-[0.72rem] font-semibold uppercase tracking-[0.22em] text-primary/80">
Location Guide
</p>
<p className="mt-2 max-w-2xl text-sm leading-6 text-muted-foreground">
How Rocky Mountain Vending typically approaches this type of
location, from placement fit to service expectations.
</p>
</div>
</div>
<PublicProse className={cn("mx-auto max-w-3xl", contentClassName)}>
{content}
</PublicProse>
</div>
</PublicSurface>
</section>
{sections ? <div className="mt-14 space-y-14">{sections}</div> : null}
{cta ? (
<section className="mt-14">
<PublicSurface className="overflow-hidden text-center">
<div className="absolute inset-x-0 top-0 h-20 bg-[radial-gradient(circle_at_top,rgba(41,160,71,0.10),transparent_70%)]" />
{cta.eyebrow ? (
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-primary/80">
{cta.eyebrow}
</p>
) : null}
<h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance">
{cta.title}
</h2>
<p className="mx-auto mt-4 max-w-2xl text-base leading-7 text-muted-foreground md:text-lg md:leading-8">
{cta.description}
</p>
<div className="mt-6 flex flex-col justify-center gap-3 sm:flex-row">
{cta.actions.map((action) => (
<Button
key={`${action.href}-${action.label}`}
asChild
size="lg"
variant={action.variant ?? "default"}
className="min-h-11 rounded-full px-6"
>
<Link href={action.href}>{action.label}</Link>
</Button>
))}
</div>
{cta.note ? (
<PublicInset className="mx-auto mt-6 max-w-2xl border-primary/10 text-left sm:text-center">
{cta.note}
</PublicInset>
) : null}
</PublicSurface>
</section>
) : null}
</div>
)
}