Files
movieloop-frontend/src/components/layout/PageHeader.tsx
T
TehRiehlDeal 8d0b7f39ee feat(ui): give the app one visual identity as Movie Loop
Gold is the primary in both themes, Bricolage Grotesque carries the
wordmark, titles and the score, and Movie A / Movie B wear the blue and
magenta of three-strip Technicolor on their posters instead of colouring
whole rows. The loop closes on screen - connectors light, a gold line
draws back to Movie A, the row glows, then the result arrives - in place
of confetti, on every play mode, scaled to the chain's length. Every
page shares one header and hairline lists; copy is sentence case with
one verb per flow, and the Home hero shows a real finished loop.

Also clamps link counts at zero: an opponent who had not moved yet
showed "-1 links".
2026-09-12 22:42:55 -07:00

49 lines
1.5 KiB
TypeScript

import type { ReactNode } from 'react';
import { Link } from 'react-router';
import { ArrowLeft } from 'lucide-react';
import { cn } from '@/lib/utils';
interface PageHeaderProps {
title: ReactNode;
/** One line, kept under 65ch. */
description?: ReactNode;
/** Buttons or links that belong to the whole page, right-aligned. */
actions?: ReactNode;
back?: { to: string; label: string };
className?: string;
}
/**
* The one page-title treatment: display face, left-aligned, no icon, no
* eyebrow, no rule. A description sits under it in muted ink; page-level
* actions sit to the right and wrap under on narrow screens.
*/
export default function PageHeader({
title,
description,
actions,
back,
className,
}: PageHeaderProps) {
return (
<div className={cn('mb-6 space-y-2', className)}>
{back && (
<Link
to={back.to}
className="inline-flex items-center gap-1 text-sm text-muted-foreground transition-colors hover:text-foreground"
>
<ArrowLeft className="h-4 w-4" aria-hidden="true" />
{back.label}
</Link>
)}
<div className="flex flex-wrap items-start justify-between gap-x-6 gap-y-3">
<h1 className="font-display text-2xl font-semibold tracking-tight">{title}</h1>
{actions && <div className="flex shrink-0 items-center gap-2">{actions}</div>}
</div>
{description && (
<p className="max-w-prose text-sm text-muted-foreground">{description}</p>
)}
</div>
);
}