mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
123 lines
3.5 KiB
TypeScript
123 lines
3.5 KiB
TypeScript
import React from 'react';
|
|
import { clsx } from 'clsx';
|
|
import { ArrowLeft, MoreVertical } from 'lucide-react';
|
|
import { Button, Breadcrumbs, DropdownMenu } from '@/components/ui';
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
export interface PageHeaderAction {
|
|
label: string;
|
|
icon?: React.ReactNode;
|
|
onClick: () => void;
|
|
variant?: 'primary' | 'outline' | 'ghost' | 'destructive';
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export interface PageHeaderProps {
|
|
title: string;
|
|
subtitle?: string;
|
|
breadcrumbs?: Array<{ label: string; href?: string; icon?: React.ReactNode }>;
|
|
actions?: PageHeaderAction[];
|
|
onBack?: () => void;
|
|
backLabel?: string;
|
|
className?: string;
|
|
}
|
|
|
|
/**
|
|
* Enhanced page header component for admin pages
|
|
*/
|
|
export const PageHeader = ({
|
|
title,
|
|
subtitle,
|
|
breadcrumbs,
|
|
actions = [],
|
|
onBack,
|
|
backLabel = 'Back',
|
|
className,
|
|
}: PageHeaderProps) => {
|
|
const navigate = useNavigate();
|
|
|
|
const handleBack = () => {
|
|
if (onBack) {
|
|
onBack();
|
|
} else {
|
|
navigate(-1);
|
|
}
|
|
};
|
|
|
|
const primaryActions = actions.filter((a) => a.variant === 'primary' || !a.variant);
|
|
const secondaryActions = actions.filter((a) => a.variant !== 'primary' && a.variant !== 'destructive');
|
|
const destructiveActions = actions.filter((a) => a.variant === 'destructive');
|
|
|
|
const menuActions = [...secondaryActions, ...destructiveActions];
|
|
|
|
return (
|
|
<div className={clsx('mb-6 space-y-4', className)}>
|
|
{/* Breadcrumbs */}
|
|
{breadcrumbs && breadcrumbs.length > 0 && (
|
|
<Breadcrumbs items={breadcrumbs} showHome={false} />
|
|
)}
|
|
|
|
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-3">
|
|
{onBack && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={handleBack}
|
|
className="shrink-0"
|
|
aria-label={backLabel}
|
|
>
|
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
{backLabel}
|
|
</Button>
|
|
)}
|
|
<div>
|
|
<h1 className="text-2xl font-bold tracking-tight">{title}</h1>
|
|
{subtitle && (
|
|
<p className="mt-1 text-sm text-muted-foreground">{subtitle}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
{actions.length > 0 && (
|
|
<div className="flex items-center gap-2 flex-shrink-0">
|
|
{primaryActions.map((action, index) => (
|
|
<Button
|
|
key={index}
|
|
variant={action.variant || 'primary'}
|
|
onClick={action.onClick}
|
|
disabled={action.disabled}
|
|
>
|
|
{action.icon && <span className="mr-2">{action.icon}</span>}
|
|
{action.label}
|
|
</Button>
|
|
))}
|
|
|
|
{menuActions.length > 0 && (
|
|
<DropdownMenu
|
|
trigger={
|
|
<Button variant="outline" size="sm" className="h-9 w-9 p-0">
|
|
<MoreVertical className="h-4 w-4" />
|
|
</Button>
|
|
}
|
|
items={menuActions.map((action, index) => ({
|
|
label: action.label,
|
|
value: `action-${index}`,
|
|
icon: action.icon,
|
|
onClick: action.onClick,
|
|
disabled: action.disabled,
|
|
}))}
|
|
align="right"
|
|
/>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|