Rocky_Mountain_Vending/components/public-surface.tsx

177 lines
4.5 KiB
TypeScript

"use client"
import type { ElementType, HTMLAttributes, ReactNode } from "react"
import { cn } from "@/lib/utils"
type PublicSectionProps = {
id?: string
tone?: "default" | "muted" | "warm"
className?: string
containerClassName?: string
children: ReactNode
}
type PublicPageHeaderProps = {
eyebrow?: string
title: string
description?: string
align?: "left" | "center"
className?: string
children?: ReactNode
}
type PublicProseProps = {
className?: string
children: ReactNode
}
export function PublicSection({
id,
tone = "default",
className,
containerClassName,
children,
}: PublicSectionProps) {
return (
<section
id={id}
className={cn(
"py-[var(--public-section-space)]",
tone === "muted" && "bg-muted/30",
tone === "warm" &&
"bg-[linear-gradient(180deg,rgba(247,244,236,0.82),rgba(255,248,235,0.98))]",
className
)}
>
<div
className={cn(
"mx-auto w-full max-w-[var(--public-shell-max)] px-4 sm:px-5 lg:px-6",
containerClassName
)}
>
{children}
</div>
</section>
)
}
export function PublicPageHeader({
eyebrow,
title,
description,
align = "left",
className,
children,
}: PublicPageHeaderProps) {
const isCentered = align === "center"
return (
<header
className={cn(
"space-y-4 md:space-y-5",
isCentered && "mx-auto max-w-3xl text-center",
className
)}
>
{eyebrow ? (
<p className="text-[0.72rem] font-semibold uppercase tracking-[0.24em] text-primary/80">
{eyebrow}
</p>
) : null}
<div className="space-y-3 md:space-y-4">
<h1 className="text-3xl font-bold tracking-tight text-balance text-foreground sm:text-4xl md:text-5xl lg:text-[3.4rem]">
{title}
</h1>
{description ? (
<p
className={cn(
"text-base leading-7 text-muted-foreground md:text-lg md:leading-8",
isCentered ? "mx-auto max-w-3xl" : "max-w-3xl"
)}
>
{description}
</p>
) : null}
</div>
{children}
</header>
)
}
export function PublicSurface({
as: Component = "div",
className,
children,
...props
}: HTMLAttributes<HTMLDivElement> & { as?: ElementType }) {
return (
<Component
className={cn(
"rounded-[var(--public-surface-radius)] border border-border/65 bg-[linear-gradient(180deg,rgba(255,255,255,0.98),rgba(255,249,240,0.96))] p-5 shadow-[0_20px_52px_rgba(15,23,42,0.075)] md:p-7",
className
)}
{...props}
>
{children}
</Component>
)
}
export function PublicInset({
className,
children,
...props
}: HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"rounded-[var(--public-inset-radius)] border border-border/55 bg-[linear-gradient(180deg,rgba(255,255,255,0.94),rgba(255,250,244,0.92))] p-4 shadow-[0_12px_30px_rgba(15,23,42,0.055)]",
className
)}
{...props}
>
{children}
</div>
)
}
type PublicSectionHeaderProps = {
eyebrow: string
title: string
description: string
className?: string
}
export function PublicSectionHeader({
eyebrow,
title,
description,
className,
}: PublicSectionHeaderProps) {
return (
<div className={cn("space-y-2.5", className)}>
<p className="text-[0.72rem] font-semibold uppercase tracking-[0.22em] text-primary/80">
{eyebrow}
</p>
<h2 className="text-xl font-semibold tracking-tight text-foreground md:text-[1.375rem]">
{title}
</h2>
<p className="max-w-2xl text-sm leading-6 text-muted-foreground">
{description}
</p>
</div>
)
}
export function PublicProse({ className, children }: PublicProseProps) {
return (
<div
className={cn(
"prose prose-slate max-w-none prose-headings:font-semibold prose-headings:tracking-tight prose-headings:text-foreground prose-p:text-muted-foreground prose-p:leading-7 prose-li:text-muted-foreground prose-li:leading-7 prose-strong:text-foreground prose-a:text-foreground prose-a:decoration-primary/35 prose-a:underline-offset-4 hover:prose-a:decoration-primary prose-img:rounded-[1.5rem] prose-img:border prose-img:border-border/55 prose-img:shadow-[0_18px_45px_rgba(15,23,42,0.08)] prose-hr:border-border/50 prose-blockquote:border-primary/25 prose-blockquote:text-foreground md:prose-lg",
className
)}
>
{children}
</div>
)
}