'use client' import { ReactNode } from 'react' import clsx from 'clsx' import { ChevronUp, ChevronDown, ChevronsUpDown, Loader2 } from 'lucide-react' // ============================================================================ // PREMIUM TABLE - Elegant, consistent styling for all tables // ============================================================================ interface Column { key: string header: string | ReactNode render?: (item: T, index: number) => ReactNode className?: string headerClassName?: string hideOnMobile?: boolean hideOnTablet?: boolean sortable?: boolean align?: 'left' | 'center' | 'right' width?: string } interface PremiumTableProps { data: T[] columns: Column[] keyExtractor: (item: T) => string | number onRowClick?: (item: T) => void emptyState?: ReactNode emptyIcon?: ReactNode emptyTitle?: string emptyDescription?: string loading?: boolean sortBy?: string sortDirection?: 'asc' | 'desc' onSort?: (key: string) => void compact?: boolean striped?: boolean hoverable?: boolean } export function PremiumTable({ data, columns, keyExtractor, onRowClick, emptyState, emptyIcon, emptyTitle = 'No data', emptyDescription, loading, sortBy, sortDirection = 'asc', onSort, compact = false, striped = false, hoverable = true, }: PremiumTableProps) { const cellPadding = compact ? 'px-4 py-3' : 'px-6 py-4' const headerPadding = compact ? 'px-4 py-3' : 'px-6 py-4' if (loading) { return (
{[...Array(5)].map((_, i) => (
))}
) } if (data.length === 0) { return (
{emptyState || ( <> {emptyIcon &&
{emptyIcon}
}

{emptyTitle}

{emptyDescription &&

{emptyDescription}

} )}
) } return (
{columns.map((col) => ( ))} {data.map((item, index) => { const key = keyExtractor(item) return ( onRowClick?.(item)} className={clsx( "group transition-all duration-200", onRowClick && "cursor-pointer", hoverable && "hover:bg-foreground/[0.02]", striped && index % 2 === 1 && "bg-foreground/[0.01]" )} > {columns.map((col) => ( ))} ) })}
{col.sortable && onSort ? ( ) : ( col.header )}
{col.render ? col.render(item, index) : (item as Record)[col.key] as ReactNode }
) } // ============================================================================ // SORT INDICATOR // ============================================================================ function SortIndicator({ active, direction }: { active: boolean; direction?: 'asc' | 'desc' }) { if (!active) { return } return direction === 'asc' ? : } // ============================================================================ // STATUS BADGE // ============================================================================ type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'accent' | 'info' export function Badge({ children, variant = 'default', size = 'sm', dot = false, pulse = false, }: { children: ReactNode variant?: BadgeVariant size?: 'xs' | 'sm' | 'md' dot?: boolean pulse?: boolean }) { const variants: Record = { default: "bg-foreground/5 text-foreground-muted border-border/50", success: "bg-accent/10 text-accent border-accent/20", warning: "bg-amber-500/10 text-amber-400 border-amber-500/20", error: "bg-red-500/10 text-red-400 border-red-500/20", accent: "bg-accent/10 text-accent border-accent/20", info: "bg-blue-500/10 text-blue-400 border-blue-500/20", } const sizes = { xs: "text-[10px] px-1.5 py-0.5", sm: "text-xs px-2 py-0.5", md: "text-xs px-2.5 py-1", } return ( {dot && ( {pulse && ( )} )} {children} ) } // ============================================================================ // TABLE ACTION BUTTON // ============================================================================ export function TableActionButton({ icon: Icon, onClick, variant = 'default', title, disabled, loading, }: { icon: React.ComponentType<{ className?: string }> onClick?: () => void variant?: 'default' | 'danger' | 'accent' title?: string disabled?: boolean loading?: boolean }) { const variants = { default: "text-foreground-muted hover:text-foreground hover:bg-foreground/5 border-transparent", danger: "text-foreground-muted hover:text-red-400 hover:bg-red-500/10 border-transparent hover:border-red-500/20", accent: "text-accent bg-accent/10 border-accent/20 hover:bg-accent/20", } return ( ) } // ============================================================================ // PLATFORM BADGE (for auctions) // ============================================================================ export function PlatformBadge({ platform }: { platform: string }) { const colors: Record = { 'GoDaddy': 'text-blue-400 bg-blue-400/10 border-blue-400/20', 'Sedo': 'text-orange-400 bg-orange-400/10 border-orange-400/20', 'NameJet': 'text-purple-400 bg-purple-400/10 border-purple-400/20', 'DropCatch': 'text-teal-400 bg-teal-400/10 border-teal-400/20', 'ExpiredDomains': 'text-pink-400 bg-pink-400/10 border-pink-400/20', } return ( {platform} ) } // ============================================================================ // STAT CARD (for page headers) // ============================================================================ export function StatCard({ title, value, subtitle, icon: Icon, accent = false, trend, }: { title: string value: string | number subtitle?: string icon?: React.ComponentType<{ className?: string }> accent?: boolean trend?: { value: number; label?: string } }) { return (
{accent &&
}
{Icon && (
)}

{title}

{typeof value === 'number' ? value.toLocaleString() : value}

{subtitle &&

{subtitle}

} {trend && (
0 ? "text-accent bg-accent/10" : trend.value < 0 ? "text-red-400 bg-red-400/10" : "text-foreground-muted bg-foreground/5" )}> {trend.value > 0 ? '+' : ''}{trend.value}% {trend.label && {trend.label}}
)}
) } // ============================================================================ // PAGE CONTAINER (consistent max-width) // ============================================================================ export function PageContainer({ children, className }: { children: ReactNode; className?: string }) { return (
{children}
) } // ============================================================================ // SECTION HEADER // ============================================================================ export function SectionHeader({ title, subtitle, icon: Icon, action, compact = false, }: { title: string subtitle?: string icon?: React.ComponentType<{ className?: string }> action?: ReactNode compact?: boolean }) { return (
{Icon && (
)}

{title}

{subtitle &&

{subtitle}

}
{action}
) } // ============================================================================ // SEARCH INPUT (consistent search styling) // ============================================================================ import { Search, X } from 'lucide-react' export function SearchInput({ value, onChange, placeholder = 'Search...', onClear, className, }: { value: string onChange: (value: string) => void placeholder?: string onClear?: () => void className?: string }) { return (
onChange(e.target.value)} placeholder={placeholder} className="w-full h-10 pl-10 pr-9 bg-background-secondary/50 border border-border/40 rounded-xl text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:border-accent/50 focus:bg-background-secondary/80 transition-all" /> {value && (onClear || onChange) && ( )}
) } // ============================================================================ // TAB BAR (consistent tab styling) // ============================================================================ interface TabItem { id: string label: string icon?: React.ComponentType<{ className?: string }> count?: number color?: 'default' | 'accent' | 'warning' } export function TabBar({ tabs, activeTab, onChange, className, }: { tabs: TabItem[] activeTab: string onChange: (id: string) => void className?: string }) { return (
{tabs.map((tab) => { const isActive = activeTab === tab.id const Icon = tab.icon return ( ) })}
) } // ============================================================================ // FILTER BAR (row of filters: search + select + buttons) // ============================================================================ export function FilterBar({ children, className, }: { children: ReactNode className?: string }) { return (
{children}
) } // ============================================================================ // SELECT DROPDOWN (consistent select styling) // ============================================================================ import { ChevronDown } from 'lucide-react' export function SelectDropdown({ value, onChange, options, className, }: { value: string onChange: (value: string) => void options: { value: string; label: string }[] className?: string }) { return (
) } // ============================================================================ // ACTION BUTTON (consistent button styling) // ============================================================================ export function ActionButton({ children, onClick, disabled, variant = 'primary', size = 'default', icon: Icon, className, }: { children: ReactNode onClick?: () => void disabled?: boolean variant?: 'primary' | 'secondary' | 'ghost' size?: 'small' | 'default' icon?: React.ComponentType<{ className?: string }> className?: string }) { return ( ) }