102 lines
2.7 KiB
TypeScript
102 lines
2.7 KiB
TypeScript
import { cn } from "@/lib/utils";
|
|
import { ChevronRight, Home } from "lucide-react";
|
|
import Link from "next/link";
|
|
|
|
interface Breadcrumb {
|
|
label: string;
|
|
href?: string;
|
|
}
|
|
|
|
interface PageHeaderProps {
|
|
title: string;
|
|
description?: string;
|
|
breadcrumbs?: Breadcrumb[];
|
|
actions?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export function PageHeader({
|
|
title,
|
|
description,
|
|
breadcrumbs,
|
|
actions,
|
|
className,
|
|
}: PageHeaderProps) {
|
|
return (
|
|
<div className={cn("space-y-4", className)}>
|
|
{breadcrumbs && breadcrumbs.length > 0 && (
|
|
<nav className="flex items-center gap-1 text-sm">
|
|
<Link
|
|
href="/"
|
|
className="flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors"
|
|
>
|
|
<Home className="h-4 w-4" />
|
|
<span>Home</span>
|
|
</Link>
|
|
{breadcrumbs.map((crumb, index) => (
|
|
<span key={index} className="flex items-center gap-1">
|
|
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
|
{crumb.href ? (
|
|
<Link
|
|
href={crumb.href}
|
|
className="text-muted-foreground hover:text-foreground transition-colors"
|
|
>
|
|
{crumb.label}
|
|
</Link>
|
|
) : (
|
|
<span className="font-medium text-foreground">
|
|
{crumb.label}
|
|
</span>
|
|
)}
|
|
</span>
|
|
))}
|
|
</nav>
|
|
)}
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="space-y-1">
|
|
<h1 className="text-3xl font-bold tracking-tight">{title}</h1>
|
|
{description && (
|
|
<p className="text-muted-foreground">{description}</p>
|
|
)}
|
|
</div>
|
|
{actions && <div className="flex items-center gap-3">{actions}</div>}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface PageSectionProps {
|
|
title?: string;
|
|
description?: string;
|
|
children: React.ReactNode;
|
|
actions?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export function PageSection({
|
|
title,
|
|
description,
|
|
children,
|
|
actions,
|
|
className,
|
|
}: PageSectionProps) {
|
|
return (
|
|
<section className={cn("space-y-4", className)}>
|
|
{(title || actions) && (
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="space-y-1">
|
|
{title && (
|
|
<h2 className="text-xl font-semibold tracking-tight">{title}</h2>
|
|
)}
|
|
{description && (
|
|
<p className="text-sm text-muted-foreground">{description}</p>
|
|
)}
|
|
</div>
|
|
{actions && <div className="flex items-center gap-2">{actions}</div>}
|
|
</div>
|
|
)}
|
|
{children}
|
|
</section>
|
|
);
|
|
}
|