import { ReactNode } from 'react';
import { LucideIcon } from 'lucide-react';
import { motion } from 'framer-motion';
import { cn } from '../../lib/utils';
/**
* 777 Wolfpack UI Primitives
* High-performance, high-density components for operational management.
*/
// Page header with title and optional actions
interface PageHeaderProps {
title: string;
subtitle?: string;
actions?: ReactNode;
className?: string;
}
export function PageHeader({ title, subtitle, actions, className }: PageHeaderProps) {
return (
{title}
{subtitle && (
{subtitle}
)}
{actions && (
{actions}
)}
);
}
// Section header for groupings
interface SectionHeaderProps {
icon?: LucideIcon;
title: string;
count?: number;
accent?: 'default' | 'accent' | 'success' | 'warning' | 'destructive';
}
export function SectionHeader({ icon: Icon, title, count, accent = 'default' }: SectionHeaderProps) {
const accentClasses = {
default: 'text-slate-500 bg-slate-100 dark:bg-slate-800/50',
accent: 'text-indigo-500 bg-indigo-500/10',
success: 'text-emerald-500 bg-emerald-500/10',
warning: 'text-amber-500 bg-amber-500/10',
destructive: 'text-rose-500 bg-rose-500/10',
};
return (
{Icon && (
)}
{title}
{count !== undefined && (
{count}
)}
);
}
// Empty state component
interface EmptyStateProps {
icon: LucideIcon;
title: string;
description?: string;
action?: ReactNode;
}
export function EmptyState({ icon: Icon, title, description, action }: EmptyStateProps) {
return (
{title}
{description && (
{description}
)}
{action &&
{action}
}
);
}
// Metric card for dashboards
interface MetricCardProps {
icon: LucideIcon;
label: string;
value: string | number;
subtitle?: string;
accent?: 'default' | 'accent' | 'success' | 'warning' | 'destructive';
trend?: { value: number; positive: boolean };
}
export function MetricCard({ icon: Icon, label, value, subtitle, accent = 'default', trend }: MetricCardProps) {
const accentColor = {
default: 'text-slate-500 dark:text-slate-400',
accent: 'text-indigo-500',
success: 'text-emerald-500',
warning: 'text-amber-500',
destructive: 'text-rose-500',
};
return (
{trend && (
{trend.positive ? '↑' : '↓'} {trend.value}%
)}
{subtitle && (
)}
);
}
// List item for tables/lists
interface ListItemProps {
children: ReactNode;
onClick?: () => void;
active?: boolean;
className?: string;
}
export function ListItem({ children, onClick, active, className }: ListItemProps) {
return (
{children}
);
}
// Action button (icon button)
interface ActionButtonProps {
icon: LucideIcon;
label: string;
onClick: (e: React.MouseEvent) => void;
variant?: 'default' | 'accent' | 'success' | 'warning' | 'destructive';
}
export function ActionButton({ icon: Icon, label, onClick, variant = 'default' }: ActionButtonProps) {
const variants = {
default: 'text-slate-500 hover:bg-slate-100 dark:text-slate-400 dark:hover:bg-slate-800',
accent: 'text-indigo-500 hover:bg-indigo-500/10',
success: 'text-emerald-500 hover:bg-emerald-500/10',
warning: 'text-amber-500 hover:bg-amber-500/10',
destructive: 'text-rose-500 hover:bg-rose-500/10',
};
return (
);
}
// Status badge
interface StatusBadgeProps {
status: 'active' | 'pending' | 'completed' | 'error' | 'default';
label?: string;
className?: string;
}
export function StatusBadge({ status, label, className }: StatusBadgeProps) {
const variants = {
active: 'text-emerald-600 bg-emerald-500/10 border-emerald-500/20',
pending: 'text-amber-600 bg-amber-500/10 border-amber-500/20',
completed: 'text-indigo-600 bg-indigo-500/10 border-indigo-500/20',
error: 'text-rose-600 bg-rose-500/10 border-rose-500/20',
default: 'text-slate-500 bg-slate-100 border-slate-200 dark:bg-slate-800 dark:border-slate-700',
};
return (
{label || status.charAt(0).toUpperCase() + status.slice(1)}
);
}
// Skeleton loader
export function Skeleton({ className }: { className?: string }) {
return ;
}
// Card skeleton
export function CardSkeleton() {
return (
);
}
// Divider
export function Divider({ className }: { className?: string }) {
return ;
}