migrate dashboard to real HeroUI v3 components and neutral theme
The frontend was built against HeroUI v2 props/classes (variant="light"/"flat", color="primary", startContent, text-tiny, <Avatar src=/name=>) while @heroui/react ^3.2.1 is installed, so most styling was silently ignored. Rewrites every page/component onto the actual v3 API (variant/color enums, Tooltip/Dropdown trigger-content structure, Avatar.Image/Fallback via a new AppAvatar helper) and replaces the custom orange branding with HeroUI's neutral default theme tokens. Also compacts the dashboard stat tiles, narrows the sidebar, and swaps the activity stat grid for a single-hue comparison bar chart. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Card, CardContent, Chip } from '@heroui/react';
|
||||
import { Card, CardContent } from '@heroui/react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
type Props = {
|
||||
@@ -6,27 +6,33 @@ type Props = {
|
||||
label: string;
|
||||
value: string | number;
|
||||
trend?: string;
|
||||
color?: 'primary' | 'success' | 'warning' | 'danger' | 'default';
|
||||
color?: 'accent' | 'success' | 'warning' | 'danger' | 'default';
|
||||
};
|
||||
|
||||
export function StatCard({ icon, label, value, trend, color = 'primary' }: Props) {
|
||||
const chipColor = color === 'default' ? 'default' : color;
|
||||
const iconClasses: Record<NonNullable<Props['color']>, string> = {
|
||||
accent: 'bg-accent-soft text-accent-soft-foreground',
|
||||
success: 'bg-success-soft text-success-soft-foreground',
|
||||
warning: 'bg-warning-soft text-warning-soft-foreground',
|
||||
danger: 'bg-danger-soft text-danger-soft-foreground',
|
||||
default: 'bg-default-soft text-muted',
|
||||
};
|
||||
|
||||
export function StatCard({ icon, label, value, trend, color = 'default' }: Props) {
|
||||
return (
|
||||
<Card className="surface-card">
|
||||
<CardContent className="flex flex-col gap-2 p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Chip color={chipColor} size="sm" variant="flat" startContent={icon} className={color === 'primary' ? 'accent-chip' : undefined}>
|
||||
{label}
|
||||
</Chip>
|
||||
{trend && (
|
||||
<span className={`text-tiny font-medium ${trend.startsWith('+') ? 'text-success-400' : trend.startsWith('-') ? 'text-danger-400' : 'text-default-400'}`}>
|
||||
{trend}
|
||||
</span>
|
||||
)}
|
||||
<Card>
|
||||
<CardContent className="flex flex-row items-center gap-3 p-3">
|
||||
<div className={`flex size-8 shrink-0 items-center justify-center rounded-lg ${iconClasses[color]}`}>
|
||||
{icon}
|
||||
</div>
|
||||
<div className="text-2xl font-bold tracking-tight">{value}</div>
|
||||
<div className="text-tiny section-subtle">{label}</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-xs text-muted">{label}</div>
|
||||
<div className="text-lg font-bold leading-tight tracking-tight">{value}</div>
|
||||
</div>
|
||||
{trend && (
|
||||
<span className={`shrink-0 text-xs font-medium ${trend.startsWith('+') ? 'text-success' : trend.startsWith('-') ? 'text-danger' : 'text-muted'}`}>
|
||||
{trend}
|
||||
</span>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user