177 lines
4.5 KiB
TypeScript
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>
|
|
)
|
|
}
|