website refactor

This commit is contained in:
2026-01-20 23:50:29 +01:00
parent 7cbec00474
commit 4516427a19
30 changed files with 735 additions and 772 deletions

View File

@@ -3,7 +3,7 @@ import { Grid } from './Grid';
interface FeatureGridProps {
children: ReactNode;
columns?: number | { base: number; md?: number; lg?: number };
columns?: number | { base: number; md?: number; lg?: number; xl?: number };
gap?: number;
}

View File

@@ -8,11 +8,9 @@ export interface LeaderboardListProps {
export const LeaderboardList = ({ children }: LeaderboardListProps) => {
return (
<Surface variant="muted" rounded="xl" style={{ border: '1px solid var(--ui-color-border-default)', overflow: 'hidden' }}>
<Box display="flex" flexDirection="col">
{children}
</Box>
</Surface>
<Box display="flex" flexDirection="col">
{children}
</Box>
);
};

View File

@@ -32,19 +32,19 @@ export const LeaderboardPreviewShell = ({
viewFullLabel
}: LeaderboardPreviewShellProps) => {
return (
<Surface variant="default" rounded="xl" style={{ border: '1px solid var(--ui-color-border-default)', overflow: 'hidden' }}>
<Box padding={6} borderBottom>
<Box display="flex" alignItems="center" justifyContent="between" marginBottom={4}>
<Box display="flex" alignItems="center" gap={4}>
<Box padding={2} rounded="lg" bg={iconBgGradient || "var(--ui-color-bg-surface-muted)"} style={iconColor ? { color: iconColor } : undefined}>
<Icon icon={icon} size={5} intent={iconColor ? undefined : intent} />
<Surface variant="precision" rounded="xl" style={{ overflow: 'hidden' }}>
<Box padding={6} borderBottom borderColor="var(--ui-color-border-muted)">
<Box display="flex" alignItems="center" justifyContent="between" marginBottom={6}>
<Box display="flex" alignItems="center" gap={5}>
<Box padding={3} rounded="xl" bg={iconBgGradient || "var(--ui-color-bg-surface-muted)"} style={iconColor ? { color: iconColor } : undefined}>
<Icon icon={icon} size={6} intent={iconColor ? undefined : intent} />
</Box>
<Box>
<Text size="lg" weight="bold" variant="high" block>
<Text size="xl" weight="bold" variant="high" block>
{title}
</Text>
{subtitle && (
<Text size="sm" variant="low">
<Text size="sm" variant="low" uppercase weight="bold" letterSpacing="widest">
{subtitle}
</Text>
)}
@@ -63,7 +63,7 @@ export const LeaderboardPreviewShell = ({
</Box>
{footer && (
<Box padding={4} borderTop bg="rgba(255,255,255,0.02)">
<Box padding={4} borderTop borderColor="var(--ui-color-border-muted)" bg="rgba(255,255,255,0.02)">
{footer}
</Box>
)}

View File

@@ -0,0 +1,76 @@
import { ReactNode } from 'react';
import { Box } from './Box';
import { Surface } from './Surface';
import { Group } from './Group';
export interface LeaderboardRowProps {
rank: ReactNode;
identity: ReactNode;
stats: ReactNode;
onClick?: () => void;
}
/**
* LeaderboardRow is a semantic UI component for displaying an entry in a leaderboard.
* It follows the "Modern Precision" theme with obsessive detail.
*/
export const LeaderboardRow = ({
rank,
identity,
stats,
onClick
}: LeaderboardRowProps) => {
return (
<Surface
as={onClick ? 'button' : 'div'}
variant="precision"
onClick={onClick}
padding="none"
cursor={onClick ? 'pointer' : 'default'}
width="full"
textAlign="left"
transition="all 0.2s cubic-bezier(0.4, 0, 0.2, 1)"
hoverBg="rgba(25, 140, 255, 0.04)"
display="block"
style={{
border: 'none',
borderBottom: '1px solid var(--ui-color-border-muted)',
background: 'transparent',
position: 'relative'
}}
className="group"
>
<Box
display="flex"
alignItems="center"
gap={6}
paddingX={6}
paddingY={4}
className="transition-transform duration-200 group-hover:translate-x-1"
>
<Box width="10" display="flex" justifyContent="center" flexShrink={0}>
{rank}
</Box>
<Box flexGrow={1} minWidth="0">
{identity}
</Box>
<Group gap={8}>
{stats}
</Group>
</Box>
{/* Hover indicator */}
<Box
position="absolute"
left={0}
top={0}
bottom={0}
width={1}
bg="var(--ui-color-intent-primary)"
className="opacity-0 transition-opacity duration-200 group-hover:opacity-100"
/>
</Surface>
);
};

View File

@@ -9,7 +9,7 @@ export interface LeaderboardTableShellProps {
export const LeaderboardTableShell = ({ children, columns }: LeaderboardTableShellProps) => {
return (
<Surface variant="default" rounded="xl" style={{ border: '1px solid var(--ui-color-border-default)', overflow: 'hidden' }}>
<Surface variant="precision" rounded="xl" style={{ overflow: 'hidden' }} marginBottom={8}>
<Box>
{children}
</Box>

View File

@@ -1,7 +1,6 @@
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text';
import Link from 'next/link';
import { LucideIcon, ChevronRight } from 'lucide-react';
interface NavLinkProps {
@@ -14,7 +13,7 @@ interface NavLinkProps {
LinkComponent?: React.ComponentType<{ href: string; children: React.ReactNode; className?: string }>;
}
export function NavLink({ href, label, icon, isActive, variant = 'sidebar', collapsed = false, LinkComponent = Link as any }: NavLinkProps) {
export function NavLink({ href, label, icon, isActive, variant = 'sidebar', collapsed = false, LinkComponent }: NavLinkProps) {
const isTop = variant === 'top';
// Radical "Game Menu" Style
@@ -72,12 +71,23 @@ export function NavLink({ href, label, icon, isActive, variant = 'sidebar', coll
</Box>
);
if (LinkComponent) {
return (
<LinkComponent
href={href}
className={`w-full group block ${!isTop ? '' : ''}`}
>
{content}
</LinkComponent>
);
}
return (
<LinkComponent
<a
href={href}
className={`w-full group block ${!isTop ? '' : ''}`}
>
{content}
</LinkComponent>
</a>
);
}

View File

@@ -13,12 +13,14 @@ interface PageHeaderProps {
title: string;
description?: string;
action?: React.ReactNode;
icon?: LucideIcon;
}
export function PageHeader({
title,
description,
action,
icon,
}: PageHeaderProps) {
return (
<Box
@@ -33,7 +35,11 @@ export function PageHeader({
>
<Box>
<Box display="flex" alignItems="center" gap={3} marginBottom={2}>
<Box width={1} height={8} backgroundColor="var(--ui-color-intent-primary)" />
{icon ? (
<Icon icon={icon} size={8} intent="primary" />
) : (
<Box width={1} height={8} backgroundColor="var(--ui-color-intent-primary)" />
)}
<Heading level={1} weight="bold" uppercase>{title}</Heading>
</Box>
{description && (

View File

@@ -0,0 +1,70 @@
import { Icon } from './Icon';
import { Text } from './Text';
import { Surface } from './Surface';
import { Crown, Medal } from 'lucide-react';
import React from 'react';
export interface RankMedalProps {
rank: number;
size?: 'sm' | 'md' | 'lg';
showIcon?: boolean;
variant?: 'primary' | 'success' | 'warning' | 'critical' | 'telemetry' | 'default';
bg?: string;
color?: string;
}
/**
* RankMedal is a semantic UI component for displaying a rank with a medal icon or number.
* It follows the "Modern Precision" theme.
*/
export const RankMedal = ({
rank,
size = 'md',
showIcon = true,
variant,
bg,
color
}: RankMedalProps) => {
const isTop3 = rank <= 3;
const sizePx = {
sm: '1.75rem',
md: '2rem',
lg: '2.5rem',
};
const textSizeMap = {
sm: 'xs',
md: 'xs',
lg: 'sm',
} as const;
const iconSize = {
sm: 3,
md: 3.5,
lg: 4.5,
};
return (
<Surface
variant="muted"
rounded="full"
style={{
height: sizePx[size],
width: sizePx[size],
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: '1px solid var(--ui-color-border-default)',
backgroundColor: bg,
color: color
}}
>
{isTop3 && showIcon ? (
<Icon icon={rank === 1 ? Crown : Medal} size={iconSize[size] as any} intent={variant as any} />
) : (
<Text weight="bold" size={textSizeMap[size]} variant={variant as any}>{rank}</Text>
)}
</Surface>
);
};

View File

@@ -73,8 +73,11 @@ export const TableHeaderCell = ({ children, textAlign, w, className }: TableHead
const alignClass = textAlign === 'center' ? 'text-center' : (textAlign === 'right' ? 'text-right' : 'text-left');
return (
<th
className={`px-4 py-3 text-xs font-bold uppercase tracking-wider text-[var(--ui-color-text-low)] ${alignClass} ${className || ''}`}
style={w ? { width: w } : undefined}
className={`px-6 py-4 text-[10px] font-bold uppercase tracking-[0.15em] text-[var(--ui-color-text-low)] border-b border-[var(--ui-color-border-muted)] ${alignClass} ${className || ''}`}
style={{
width: w,
background: 'rgba(255, 255, 255, 0.01)'
}}
>
{children}
</th>
@@ -96,7 +99,7 @@ export const TableCell = ({ children, textAlign, className, py, colSpan, w, posi
const alignClass = textAlign === 'center' ? 'text-center' : (textAlign === 'right' ? 'text-right' : 'text-left');
return (
<td
className={`px-4 py-3 text-sm text-[var(--ui-color-text-high)] ${alignClass} ${className || ''}`}
className={`px-6 py-4 text-sm text-[var(--ui-color-text-high)] ${alignClass} ${className || ''}`}
colSpan={colSpan}
style={{
...(py !== undefined ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}),