dc78d8fea3
Componentes React reutilizables: card, dialog, tabs, select, alert, badge, button, input, label, skeleton, tooltip, progress_bar, page_header, form_field, settings_page, crud_page, analytics_page, dashboard_layout. Charts: area, bar, line, sparkline, kpi_card, chart_container. Hooks Wails: use_wails_query, use_wails_mutation, use_wails_stream, use_wails_event, use_animated_canvas. Funciones core: cn, format_compact, chart_colors, get_series_color, wails_cache, theme_config_to_colors. Tipos: chart_series, wails_ipc, theme_config, component_variants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import { cn } from "../core/cn"
|
|
|
|
interface TabItem {
|
|
label: string
|
|
value: string
|
|
icon?: React.ReactNode
|
|
disabled?: boolean
|
|
}
|
|
|
|
interface PageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
title: string
|
|
subtitle?: string
|
|
actions?: React.ReactNode
|
|
onBack?: () => void
|
|
tabs?: TabItem[]
|
|
activeTab?: string
|
|
onTabChange?: (value: string) => void
|
|
badge?: React.ReactNode
|
|
sticky?: boolean
|
|
}
|
|
|
|
function PageHeader({
|
|
title, subtitle, actions, onBack, tabs, activeTab, onTabChange,
|
|
badge, sticky = false, className, ...props
|
|
}: PageHeaderProps) {
|
|
return (
|
|
<header
|
|
data-slot="page-header"
|
|
className={cn("space-y-4 border-b bg-background pb-4", sticky && "sticky top-0 z-20", className)}
|
|
{...props}
|
|
>
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="flex items-start gap-3">
|
|
{onBack && (
|
|
<button onClick={onBack} className="mt-1 inline-flex size-7 shrink-0 items-center justify-center rounded-md hover:bg-muted">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="m15 18-6-6 6-6"/></svg>
|
|
</button>
|
|
)}
|
|
<div className="space-y-1">
|
|
<div className="flex items-center gap-3">
|
|
<h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
|
|
{badge}
|
|
</div>
|
|
{subtitle && <p className="text-sm text-muted-foreground">{subtitle}</p>}
|
|
</div>
|
|
</div>
|
|
{actions && <div className="flex shrink-0 items-center gap-2">{actions}</div>}
|
|
</div>
|
|
{tabs && tabs.length > 0 && (
|
|
<nav className="flex gap-4 border-b -mb-4 pb-0">
|
|
{tabs.map((tab) => (
|
|
<button
|
|
key={tab.value}
|
|
type="button"
|
|
disabled={tab.disabled}
|
|
onClick={() => onTabChange?.(tab.value)}
|
|
className={cn(
|
|
"inline-flex items-center gap-2 border-b-2 px-1 pb-3 text-sm font-medium transition-colors",
|
|
activeTab === tab.value ? "border-primary text-foreground" : "border-transparent text-muted-foreground hover:text-foreground",
|
|
tab.disabled && "pointer-events-none opacity-50"
|
|
)}
|
|
>
|
|
{tab.icon && <span className="size-4">{tab.icon}</span>}
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</nav>
|
|
)}
|
|
</header>
|
|
)
|
|
}
|
|
|
|
interface SimplePageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
title: string
|
|
description?: string
|
|
children?: React.ReactNode
|
|
}
|
|
|
|
function SimplePageHeader({ title, description, children, className, ...props }: SimplePageHeaderProps) {
|
|
return (
|
|
<div className={cn("flex items-center justify-between border-b pb-4", className)} {...props}>
|
|
<div className="space-y-1">
|
|
<h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
|
|
{description && <p className="text-sm text-muted-foreground">{description}</p>}
|
|
</div>
|
|
{children && <div className="flex items-center gap-2">{children}</div>}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export { PageHeader, SimplePageHeader }
|