website refactor

This commit is contained in:
2026-01-18 21:31:08 +01:00
parent 502d4aa092
commit b43a23a48c
96 changed files with 3461 additions and 4067 deletions

View File

@@ -1,115 +1,68 @@
import React, { ReactNode } from 'react';
import { Box } from './primitives/Box';
import { Stack } from './primitives/Stack';
import { Text } from './Text';
import { Card } from './Card';
import { Box } from './primitives/Box';
import { Text } from './Text';
import { Icon } from './Icon';
import { LucideIcon } from 'lucide-react';
interface StatCardProps {
export interface StatCardProps {
label: string;
value: string | number;
icon?: LucideIcon;
intent?: 'primary' | 'success' | 'warning' | 'critical' | 'telemetry';
trend?: {
value: number;
isPositive: boolean;
};
variant?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
className?: string;
onClick?: () => void;
prefix?: string;
suffix?: string;
delay?: number;
footer?: ReactNode;
}
export function StatCard({
label,
value,
icon,
export const StatCard = ({
label,
value,
icon,
intent = 'primary',
trend,
variant = 'default',
className = '',
onClick,
prefix,
suffix,
delay,
}: StatCardProps) {
const variantClasses = {
default: 'bg-panel-gray border-border-gray',
primary: 'bg-primary-accent/5 border-primary-accent/20',
success: 'bg-success-green/5 border-success-green/20',
warning: 'bg-warning-amber/5 border-warning-amber/20',
danger: 'bg-critical-red/5 border-critical-red/20',
info: 'bg-telemetry-aqua/5 border-telemetry-aqua/20',
};
const iconBgClasses = {
default: 'bg-white/5',
primary: 'bg-primary-accent/10',
success: 'bg-success-green/10',
warning: 'bg-warning-amber/10',
danger: 'bg-critical-red/10',
info: 'bg-telemetry-aqua/10',
};
const iconColorClasses = {
default: 'text-gray-400',
primary: 'text-primary-accent',
success: 'text-success-green',
warning: 'text-warning-amber',
danger: 'text-critical-red',
info: 'text-telemetry-aqua',
};
const cardContent = (
<Card variant="default" p={5} className={`${variantClasses[variant]} ${className} h-full`}>
<Stack gap={3}>
<Stack direction="row" align="center" justify="between">
<Text size="xs" weight="bold" color="text-gray-500" uppercase letterSpacing="widest">
footer
}: StatCardProps) => {
return (
<Card variant="default">
<Box display="flex" alignItems="start" justifyContent="between" marginBottom={4}>
<Box>
<Text size="xs" weight="bold" variant="low" uppercase>
{label}
</Text>
{icon && (
<Box
p={2}
rounded="lg"
bg={iconBgClasses[variant]}
className={iconColorClasses[variant]}
>
<Icon icon={icon} size={5} />
</Box>
)}
</Stack>
<Stack gap={1}>
<Text size="3xl" weight="bold" color="text-white">
{prefix}{value}{suffix}
<Text size="2xl" weight="bold" variant="high" block marginTop={1}>
{value}
</Text>
{trend && (
<Stack direction="row" align="center" gap={1}>
<Text
size="xs"
weight="bold"
color={trend.isPositive ? 'text-success-green' : 'text-critical-red'}
>
{trend.isPositive ? '+' : ''}{trend.value}%
</Text>
<Text size="xs" color="text-gray-500">
vs last period
</Text>
</Stack>
)}
</Stack>
</Stack>
</Box>
{icon && (
<Box padding={2} rounded="lg" bg="var(--ui-color-bg-surface-muted)">
<Icon icon={icon} size={5} intent={intent} />
</Box>
)}
</Box>
{trend && (
<Box display="flex" alignItems="center" gap={1} marginBottom={footer ? 4 : 0}>
<Text
size="xs"
weight="bold"
variant={trend.isPositive ? 'success' : 'critical'}
>
{trend.isPositive ? '+' : '-'}{Math.abs(trend.value)}%
</Text>
<Text size="xs" variant="low">
vs last period
</Text>
</Box>
)}
{footer && (
<Box borderTop paddingTop={4}>
{footer}
</Box>
)}
</Card>
);
if (onClick) {
return (
<Box as="button" onClick={onClick} w="full" textAlign="left" className="focus:outline-none">
{cardContent}
</Box>
);
}
return cardContent;
}
};