website refactor
This commit is contained in:
35
apps/website/components/dashboard/ActivityFeedPanel.tsx
Normal file
35
apps/website/components/dashboard/ActivityFeedPanel.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import { Panel } from '@/ui/Panel';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { ActivityFeed } from '../feed/ActivityFeed';
|
||||
|
||||
interface FeedItem {
|
||||
id: string;
|
||||
type: string;
|
||||
headline: string;
|
||||
body?: string;
|
||||
timestamp: string;
|
||||
formattedTime: string;
|
||||
ctaHref?: string;
|
||||
ctaLabel?: string;
|
||||
}
|
||||
|
||||
interface ActivityFeedPanelProps {
|
||||
items: FeedItem[];
|
||||
hasItems: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* ActivityFeedPanel
|
||||
*
|
||||
* A semantic wrapper for the activity feed.
|
||||
*/
|
||||
export function ActivityFeedPanel({ items, hasItems }: ActivityFeedPanelProps) {
|
||||
return (
|
||||
<Panel title="Activity Feed" padding={0}>
|
||||
<Box px={6} pb={6}>
|
||||
<ActivityFeed items={items} hasItems={hasItems} />
|
||||
</Box>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
28
apps/website/components/dashboard/DashboardControlBar.tsx
Normal file
28
apps/website/components/dashboard/DashboardControlBar.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
|
||||
interface DashboardControlBarProps {
|
||||
title: string;
|
||||
actions?: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* DashboardControlBar
|
||||
*
|
||||
* The top header bar for page-level controls and context.
|
||||
* Uses UI primitives to comply with architectural constraints.
|
||||
*/
|
||||
export function DashboardControlBar({ title, actions }: DashboardControlBarProps) {
|
||||
return (
|
||||
<Box display="flex" h="full" alignItems="center" justifyContent="between" px={6}>
|
||||
<Heading level={6} weight="bold">
|
||||
{title}
|
||||
</Heading>
|
||||
<Stack direction="row" align="center" gap={4}>
|
||||
{actions}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { DashboardHero as UiDashboardHero } from '@/ui/DashboardHero';
|
||||
@@ -48,10 +46,10 @@ export function DashboardHero({ currentDriver, activeLeaguesCount }: DashboardHe
|
||||
}
|
||||
stats={
|
||||
<>
|
||||
<StatBox icon={Trophy} label="Wins" value={currentDriver.wins} color="var(--performance-green)" />
|
||||
<StatBox icon={Medal} label="Podiums" value={currentDriver.podiums} color="var(--warning-amber)" />
|
||||
<StatBox icon={Target} label="Consistency" value={currentDriver.consistency} color="var(--primary-blue)" />
|
||||
<StatBox icon={Users} label="Active Leagues" value={activeLeaguesCount} color="var(--neon-purple)" />
|
||||
<StatBox icon={Trophy} label="Wins" value={currentDriver.wins} color="#10b981" />
|
||||
<StatBox icon={Medal} label="Podiums" value={currentDriver.podiums} color="#FFBE4D" />
|
||||
<StatBox icon={Target} label="Consistency" value={currentDriver.consistency} color="#198CFF" />
|
||||
<StatBox icon={Users} label="Active Leagues" value={activeLeaguesCount} color="#a855f7" />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
49
apps/website/components/dashboard/DashboardKpiRow.tsx
Normal file
49
apps/website/components/dashboard/DashboardKpiRow.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Grid } from '@/ui/Grid';
|
||||
|
||||
interface KpiItem {
|
||||
label: string;
|
||||
value: string | number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface DashboardKpiRowProps {
|
||||
items: KpiItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* DashboardKpiRow
|
||||
*
|
||||
* A horizontal row of key performance indicators with telemetry styling.
|
||||
* Uses UI primitives to comply with architectural constraints.
|
||||
*/
|
||||
export function DashboardKpiRow({ items }: DashboardKpiRowProps) {
|
||||
return (
|
||||
<Grid responsiveGridCols={{ base: 2, md: 3, lg: 6 }} gap={4}>
|
||||
{items.map((item, index) => (
|
||||
<Box key={index} borderLeft pl={4} borderColor="var(--color-outline)">
|
||||
<Text
|
||||
size="xs"
|
||||
weight="bold"
|
||||
uppercase
|
||||
letterSpacing="tighter"
|
||||
color="var(--color-text-low)"
|
||||
block
|
||||
>
|
||||
{item.label}
|
||||
</Text>
|
||||
<Text
|
||||
size="xl"
|
||||
font="mono"
|
||||
weight="bold"
|
||||
color={item.color || 'var(--color-text-high)'}
|
||||
>
|
||||
{item.value}
|
||||
</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
20
apps/website/components/dashboard/DashboardRail.tsx
Normal file
20
apps/website/components/dashboard/DashboardRail.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
|
||||
interface DashboardRailProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* DashboardRail
|
||||
*
|
||||
* A thin sidebar rail for high-level navigation and status indicators.
|
||||
* Uses UI primitives to comply with architectural constraints.
|
||||
*/
|
||||
export function DashboardRail({ children }: DashboardRailProps) {
|
||||
return (
|
||||
<Box as="nav" display="flex" h="full" flexDirection="col" alignItems="center" py={4} gap={4}>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
39
apps/website/components/dashboard/DashboardShell.tsx
Normal file
39
apps/website/components/dashboard/DashboardShell.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
|
||||
interface DashboardShellProps {
|
||||
children: React.ReactNode;
|
||||
rail?: React.ReactNode;
|
||||
controlBar?: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* DashboardShell
|
||||
*
|
||||
* The primary layout container for the Telemetry Workspace.
|
||||
* Orchestrates the sidebar rail, top control bar, and main content area.
|
||||
* Uses UI primitives to comply with architectural constraints.
|
||||
*/
|
||||
export function DashboardShell({ children, rail, controlBar }: DashboardShellProps) {
|
||||
return (
|
||||
<Box display="flex" h="screen" overflow="hidden" bg="base-black" color="white">
|
||||
{rail && (
|
||||
<Box as="aside" w="16" flexShrink={0} borderRight bg="surface-charcoal" borderColor="var(--color-outline)">
|
||||
{rail}
|
||||
</Box>
|
||||
)}
|
||||
<Box display="flex" flexGrow={1} flexDirection="col" overflow="hidden">
|
||||
{controlBar && (
|
||||
<Box as="header" h="14" borderBottom bg="surface-charcoal" borderColor="var(--color-outline)">
|
||||
{controlBar}
|
||||
</Box>
|
||||
)}
|
||||
<Box as="main" flexGrow={1} overflow="auto" p={6}>
|
||||
<Box maxWidth="7xl" mx="auto" display="flex" flexDirection="col" gap={6}>
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { Trophy, Users } from 'lucide-react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { QuickActionItem } from '@/ui/QuickActionItem';
|
||||
|
||||
export function QuickActions() {
|
||||
return (
|
||||
<Box>
|
||||
<Heading level={3} mb={4}>Quick Actions</Heading>
|
||||
<Box display="flex" flexDirection="col" gap={2}>
|
||||
<QuickActionItem
|
||||
href={routes.public.leagues}
|
||||
label="Browse Leagues"
|
||||
icon={Users}
|
||||
iconVariant="blue"
|
||||
/>
|
||||
<QuickActionItem
|
||||
href={routes.public.leaderboards}
|
||||
label="View Leaderboards"
|
||||
icon={Trophy}
|
||||
iconVariant="amber"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
74
apps/website/components/dashboard/RecentActivityTable.tsx
Normal file
74
apps/website/components/dashboard/RecentActivityTable.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { StatusDot } from '@/ui/StatusDot';
|
||||
|
||||
export interface ActivityItem {
|
||||
id: string;
|
||||
type: string;
|
||||
description: string;
|
||||
timestamp: string;
|
||||
status?: 'success' | 'warning' | 'critical' | 'info';
|
||||
}
|
||||
|
||||
interface RecentActivityTableProps {
|
||||
items: ActivityItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* RecentActivityTable
|
||||
*
|
||||
* A high-density table for displaying recent events and telemetry logs.
|
||||
* Uses UI primitives to comply with architectural constraints.
|
||||
*/
|
||||
export function RecentActivityTable({ items }: RecentActivityTableProps) {
|
||||
const getStatusColor = (status?: string) => {
|
||||
switch (status) {
|
||||
case 'success': return 'var(--color-success)';
|
||||
case 'warning': return 'var(--color-warning)';
|
||||
case 'critical': return 'var(--color-critical)';
|
||||
default: return 'var(--color-primary)';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box overflow="auto">
|
||||
<Box as="table" w="full" textAlign="left">
|
||||
<Box as="thead">
|
||||
<Box as="tr" borderBottom borderColor="var(--color-outline)">
|
||||
<Box as="th" pb={2}>
|
||||
<Text size="xs" weight="medium" uppercase letterSpacing="wider" color="var(--color-text-low)">Type</Text>
|
||||
</Box>
|
||||
<Box as="th" pb={2}>
|
||||
<Text size="xs" weight="medium" uppercase letterSpacing="wider" color="var(--color-text-low)">Description</Text>
|
||||
</Box>
|
||||
<Box as="th" pb={2}>
|
||||
<Text size="xs" weight="medium" uppercase letterSpacing="wider" color="var(--color-text-low)">Time</Text>
|
||||
</Box>
|
||||
<Box as="th" pb={2}>
|
||||
<Text size="xs" weight="medium" uppercase letterSpacing="wider" color="var(--color-text-low)">Status</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box as="tbody">
|
||||
{items.map((item) => (
|
||||
<Box key={item.id} as="tr" borderBottom borderColor="rgba(35, 39, 43, 0.5)" hoverBg="rgba(255, 255, 255, 0.05)" transition>
|
||||
<Box as="td" py={3}>
|
||||
<Text font="mono" color="var(--color-telemetry)" size="xs">{item.type}</Text>
|
||||
</Box>
|
||||
<Box as="td" py={3}>
|
||||
<Text color="var(--color-text-med)" size="xs">{item.description}</Text>
|
||||
</Box>
|
||||
<Box as="td" py={3}>
|
||||
<Text color="var(--color-text-low)" size="xs">{item.timestamp}</Text>
|
||||
</Box>
|
||||
<Box as="td" py={3}>
|
||||
<StatusDot color={getStatusColor(item.status)} size={1.5} />
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
28
apps/website/components/dashboard/TelemetryPanel.tsx
Normal file
28
apps/website/components/dashboard/TelemetryPanel.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Surface } from '@/ui/Surface';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Box } from '@/ui/Box';
|
||||
|
||||
interface TelemetryPanelProps {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* TelemetryPanel
|
||||
*
|
||||
* A dense, instrument-grade panel for displaying data and controls.
|
||||
* Uses UI primitives to comply with architectural constraints.
|
||||
*/
|
||||
export function TelemetryPanel({ title, children }: TelemetryPanelProps) {
|
||||
return (
|
||||
<Surface variant="dark" border rounded="sm" padding={4} shadow="sm">
|
||||
<Heading level={6} mb={4} color="var(--color-text-low)">
|
||||
{title}
|
||||
</Heading>
|
||||
<Box fontSize="sm">
|
||||
{children}
|
||||
</Box>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user