Files

116 lines
3.6 KiB
TypeScript
Raw Permalink Normal View History

import Link from "next/link"
import { LEGAL, LEGAL_PAGES } from "@/lib/legal"
/**
* Shared shell for every legal page. Renders a consistent header (title,
* effective/updated dates), the body, and a cross-link nav to sibling policies.
* `pt-32` clears the fixed marketing navbar.
*/
export function LegalPage({
title,
subtitle,
updated,
children,
}: {
title: string
subtitle?: string
/** Optional per-page override; defaults to the global LEGAL.lastUpdated. */
updated?: string
children: React.ReactNode
}) {
return (
<div className="bg-[#09090b] text-white min-h-screen">
<div className="mx-auto max-w-3xl px-6 pt-32 pb-24">
<nav className="mb-8 text-xs text-white/30">
<Link href="/" className="hover:text-white/60 transition">Home</Link>
<span className="mx-1.5">/</span>
<span className="text-white/50">{title}</span>
</nav>
<header className="mb-10 border-b border-white/[0.06] pb-8">
<h1 className="text-3xl font-bold text-white mb-3">{title}</h1>
{subtitle && <p className="text-sm text-white/50 leading-relaxed">{subtitle}</p>}
<p className="mt-4 text-xs text-white/30">
Effective date: {LEGAL.effectiveDate} · Last updated: {updated ?? LEGAL.lastUpdated}
</p>
</header>
<div className="space-y-9">{children}</div>
<PolicyNav current={title} />
</div>
</div>
)
}
/** A titled section. Pass plain text or JSX children (paragraphs, lists, etc.). */
export function Section({
id,
heading,
children,
}: {
id?: string
heading: string
children: React.ReactNode
}) {
return (
<section id={id} className="scroll-mt-32">
<h2 className="text-lg font-semibold text-white mb-3">{heading}</h2>
<div className="space-y-3 text-sm text-white/50 leading-relaxed [&_a]:text-indigo-300 [&_a:hover]:text-indigo-200 [&_strong]:text-white/80 [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:space-y-1.5 [&_li]:marker:text-white/30">
{children}
</div>
</section>
)
}
/** Highlighted note (e.g. a disclaimer or important caveat). */
export function Callout({ children }: { children: React.ReactNode }) {
return (
<div className="rounded-xl border border-amber-500/20 bg-amber-500/[0.06] px-4 py-3.5 text-sm text-amber-100/80 leading-relaxed">
{children}
</div>
)
}
/** Standard "questions / contact us" block for the bottom of a policy. */
export function LegalContact({
email = LEGAL.contactEmail,
children,
}: {
email?: string
children?: React.ReactNode
}) {
return (
<Section heading="Contact us">
<p>
{children ?? "If you have questions about this policy, contact us at "}
<a href={`mailto:${email}`}>{email}</a>.
</p>
<p className="text-white/30 text-xs">
{LEGAL.entity}
{LEGAL.address && !LEGAL.address.startsWith("[") ? ` · ${LEGAL.address}` : ""}
</p>
</Section>
)
}
/** Cross-links to the other legal documents. */
function PolicyNav({ current }: { current: string }) {
return (
<nav className="mt-14 border-t border-white/[0.06] pt-8">
<p className="text-xs font-semibold uppercase tracking-wider text-white/30 mb-4">
More policies
</p>
<ul className="grid grid-cols-2 gap-x-6 gap-y-2.5 sm:grid-cols-3">
{LEGAL_PAGES.filter((p) => p.label !== current).map((p) => (
<li key={p.href}>
<Link href={p.href} className="text-sm text-white/50 hover:text-white transition">
{p.label}
</Link>
</li>
))}
</ul>
</nav>
)
}