style(TrackStatsDisplay): elevate visual fidelity to premium standards

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
senke 2026-02-07 09:07:10 +01:00
parent d444fb3896
commit 8e640400a1
2 changed files with 98 additions and 15 deletions

View file

@ -4,7 +4,15 @@ import { TrackStatsDisplay } from './TrackStatsDisplay';
const meta = {
title: 'Components/Features/Tracks/TrackStatsDisplay',
component: TrackStatsDisplay,
parameters: { layout: 'centered' },
tags: ['autodocs'],
decorators: [
(Story) => (
<div className="p-4 bg-background border border-border rounded-[var(--radius-xl)] min-h-layout-story">
<Story />
</div>
),
],
} satisfies Meta<typeof TrackStatsDisplay>;
export default meta;
@ -17,9 +25,26 @@ export const Horizontal: Story = {
},
};
export const HorizontalWithLabels: Story = {
args: {
trackId: 1,
variant: 'horizontal',
showLabels: true,
},
};
export const Grid: Story = {
args: {
trackId: 1,
variant: 'grid',
},
};
/** Grid + labels to validate chart tokens and transitions. */
export const VisualStressTest: Story = {
args: {
trackId: 1,
variant: 'grid',
showLabels: true,
},
};

View file

@ -53,27 +53,63 @@ export function TrackStatsDisplay({
return `${secs}s`;
};
if (loading) return <div className="flex h-10 items-center gap-2 text-xs font-mono text-primary animate-pulse"><Loader2 className="w-3 h-3 animate-spin" /> SCANNING...</div>;
if (loading) {
return (
<div
className={cn(
'flex h-10 items-center gap-2 text-xs font-mono text-muted-foreground/90 tracking-tight',
'animate-pulse transition-opacity duration-[var(--duration-normal)]',
)}
>
<Loader2 className="w-3 h-3 animate-spin" />
SCANNING...
</div>
);
}
if (error || !stats) return null;
const statsItems = [
{ icon: Eye, value: formatNumber(stats.views), label: 'Views', color: 'text-cyan-500', bg: 'bg-cyan-500/10' },
{ icon: Heart, value: formatNumber(stats.likes), label: 'Likes', color: 'text-magenta-500', bg: 'bg-magenta-500/10' },
{ icon: MessageCircle, value: formatNumber(stats.comments), label: 'Comms', color: 'text-lime-500', bg: 'bg-lime-500/10' },
{ icon: Download, value: formatNumber(stats.downloads), label: 'Data', color: 'text-gold-500', bg: 'bg-gold-500/10' },
{ icon: Eye, value: formatNumber(stats.views), label: 'Views', color: 'text-chart-1', bg: 'bg-chart-1/10' },
{ icon: Heart, value: formatNumber(stats.likes), label: 'Likes', color: 'text-chart-2', bg: 'bg-chart-2/10' },
{ icon: MessageCircle, value: formatNumber(stats.comments), label: 'Comms', color: 'text-chart-3', bg: 'bg-chart-3/10' },
{ icon: Download, value: formatNumber(stats.downloads), label: 'Data', color: 'text-chart-4', bg: 'bg-chart-4/10' },
{ icon: Clock, value: formatDuration(stats.total_play_time), label: 'Pulse', color: 'text-primary', bg: 'bg-primary/10' },
];
if (variant === 'grid') {
return (
<div className={cn("grid grid-cols-2 md:grid-cols-5 gap-3", className)}>
<div
className={cn(
'grid grid-cols-2 md:grid-cols-5 gap-3 transition-opacity duration-[var(--duration-normal)]',
className,
)}
>
{statsItems.map((item, i) => {
const Icon = item.icon;
return (
<Card key={i} variant="glass" className="p-3 bg-black/40 border-white/5 flex flex-col items-center gap-1 group hover:border-white/20 transition-all">
<div className={cn("p-2 rounded-lg mb-1 group-hover:scale-110 transition-transform", item.bg, item.color)}><Icon className="w-4 h-4" /></div>
<div className="text-lg font-display font-bold text-white">{item.value}</div>
<div className="text-[8px] font-mono text-muted-foreground uppercase tracking-widest">{item.label}</div>
<Card
key={i}
variant="outline"
className={cn(
'p-3 border-border flex flex-col items-center gap-1',
'hover:border-primary/30 hover:shadow-md transition-[border-color,box-shadow,transform] duration-[var(--duration-normal)]',
)}
>
<div
className={cn(
'p-2 rounded-[var(--radius-md)] mb-1 transition-transform duration-[var(--duration-normal)] hover:scale-105',
item.bg,
item.color,
)}
>
<Icon className="w-4 h-4" />
</div>
<div className="text-lg font-display font-bold text-foreground tabular-nums tracking-tight">
{item.value}
</div>
<div className="text-xs font-mono text-muted-foreground/90 uppercase tracking-widest">
{item.label}
</div>
</Card>
);
})}
@ -82,15 +118,37 @@ export function TrackStatsDisplay({
}
return (
<div className={cn("flex flex-wrap items-center gap-6", className)}>
<div
className={cn(
'flex flex-wrap items-center gap-6 transition-opacity duration-[var(--duration-normal)]',
className,
)}
>
{statsItems.map((item, i) => {
const Icon = item.icon;
return (
<div key={i} className="flex items-center gap-2 group cursor-default">
<div className={cn("p-1.5 rounded bg-white/5 opacity-60 group-hover:opacity-100 transition-all", item.color)}><Icon className="w-3.5 h-3.5" /></div>
<div
key={i}
className="flex items-center gap-2 group cursor-default"
>
<div
className={cn(
'p-1.5 rounded-[var(--radius-md)] opacity-80 group-hover:opacity-100 transition-[opacity,transform] duration-[var(--duration-normal)]',
item.bg,
item.color,
)}
>
<Icon className="w-3.5 h-3.5" aria-hidden />
</div>
<div className="flex flex-col">
<span className="text-sm font-bold text-white group-hover:text-primary transition-colors">{item.value}</span>
{showLabels && <span className="text-[8px] font-mono text-muted-foreground uppercase tracking-wider">{item.label}</span>}
<span className="text-sm font-bold text-foreground tabular-nums tracking-tight group-hover:text-primary transition-colors duration-[var(--duration-normal)]">
{item.value}
</span>
{showLabels && (
<span className="text-xs font-mono text-muted-foreground/90 uppercase tracking-wider">
{item.label}
</span>
)}
</div>
</div>
);