website refactor
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
76
apps/website/ui/LeaderboardRow.tsx
Normal file
76
apps/website/ui/LeaderboardRow.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
70
apps/website/ui/RankMedal.tsx
Normal file
70
apps/website/ui/RankMedal.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -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` } : {}),
|
||||
|
||||
Reference in New Issue
Block a user