"use client";
import { useRef } from "react";
import type * as React from "react";
import { FadeIn } from "@/components/motion";
import { BrandMark } from "@/components/brand";
import { cn } from "@/lib/cn";
import { gsap, prefersReducedMotion, useGSAP } from "@/lib/motion";
type PageHeaderProps = {
eyebrow: string;
title: React.ReactNode;
description?: React.ReactNode;
leading?: React.ReactNode;
actions?: React.ReactNode;
className?: string;
};
export function PageShell({ className, ...props }: React.ComponentProps<"div">) {
return
;
}
export function PageHeader({
eyebrow,
title,
description,
leading,
actions,
className,
}: PageHeaderProps) {
return (
{leading}
{eyebrow}
{title}
{description &&
{description}
}
{actions}
);
}
type StatePanelProps = React.ComponentProps<"div"> & {
title: React.ReactNode;
description?: React.ReactNode;
icon?: React.ReactNode;
action?: React.ReactNode;
tone?: "default" | "error";
loading?: boolean;
};
export function StatePanel({
title,
description,
icon,
action,
tone = "default",
loading = false,
className,
...props
}: StatePanelProps) {
return (
{loading ? (
) : (
icon &&
{icon}
)}
{title}
{description &&
{description}
}
{action &&
{action}
}
);
}
function LoaderMark({ className }: { className?: string }) {
const ref = useRef(null);
useGSAP(
() => {
const el = ref.current;
if (!el || prefersReducedMotion()) return;
gsap.to(el, {
rotate: 180,
duration: 1.1,
repeat: -1,
yoyo: true,
ease: "power1.inOut",
});
},
{ scope: ref }
);
return (
);
}
export function FullScreenLoader({ label }: { label?: string }) {
const rootRef = useRef(null);
useGSAP(
() => {
const root = rootRef.current;
if (!root || prefersReducedMotion()) return;
const mark = root.querySelector("[data-loader-mark]");
const ring = root.querySelector("[data-loader-ring]");
const copy = root.querySelector("[data-loader-copy]");
gsap.fromTo(
[mark, copy],
{ autoAlpha: 0, y: 8 },
{ autoAlpha: 1, y: 0, duration: 0.45, stagger: 0.08, ease: "power3.out" }
);
gsap.to(mark, {
scale: 1.06,
duration: 0.9,
repeat: -1,
yoyo: true,
ease: "sine.inOut",
});
gsap.to(ring, {
rotate: 360,
duration: 2.4,
repeat: -1,
ease: "none",
});
},
{ scope: rootRef }
);
return (
);
}