website refactor

This commit is contained in:
2026-01-19 19:15:21 +01:00
parent 4ce89c1cc4
commit 5715e35790
4 changed files with 117 additions and 156 deletions

View File

@@ -1,77 +1,45 @@
import { AppFooter } from '@/components/app/AppFooter'; import { Surface } from '@/ui/Surface';
import { Grid } from '@/ui/Grid'; import { Container } from '@/ui/Container';
import { Stack } from '@/ui/Stack'; import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text'; import { Text } from '@/ui/Text';
import { Link } from '@/ui/Link'; import { Link } from '@/ui/Link';
import { BrandMark } from '@/ui/BrandMark';
import { Box } from '@/ui/Box'; import { Box } from '@/ui/Box';
import { BrandMark } from '@/ui/BrandMark';
export interface GlobalFooterViewData {} export interface GlobalFooterViewData {}
export function GlobalFooterTemplate(_props: GlobalFooterViewData) { export function GlobalFooterTemplate(_props: GlobalFooterViewData) {
return ( return (
<AppFooter> <Surface as="footer" variant="muted" borderTop paddingY={6}>
<Grid cols={{ base: 1, md: 4 }} gap={12}> <Container size="full">
<Stack colSpan={{ base: 1, md: 2 }} gap={6}> <Box display="flex" flexDirection={{ base: 'col', md: 'row' }} alignItems="center" justifyContent="between" gap={4}>
<Stack direction="row" align="center" gap={4}>
{/* Left: Identity */}
<Stack direction="row" align="center" gap={3}>
<BrandMark /> <BrandMark />
<Box display={{ base: 'none', sm: 'flex' }} alignItems="center" gap={2} borderLeft borderColor="var(--ui-color-border-default)" pl={4}> <Text size="xs" variant="low" font="mono" uppercase letterSpacing="wider">
<Box w="4px" h="4px" rounded="full" bg="var(--ui-color-intent-primary)" animate="pulse" /> // Infrastructure
<Text size="xs" variant="low" weight="bold" font="mono" letterSpacing="0.1em">
INFRASTRUCTURE
</Text>
</Box>
</Stack>
<Stack maxWidth="sm">
<Text variant="low" size="sm">
The professional infrastructure for serious sim racing.
Precision telemetry, automated results, and elite league management.
</Text> </Text>
</Stack> </Stack>
</Stack>
<Stack gap={4}> {/* Center: Technical Links */}
<Text size="xs" weight="bold" variant="high" uppercase letterSpacing="wider">PLATFORM</Text> <Stack direction="row" gap={6} display={{ base: 'none', md: 'flex' }}>
<Stack as="ul" direction="col" gap={2}> <Link href="/leagues" variant="secondary" size="xs" underline="none">LEAGUES</Link>
<Stack as="li"> <Link href="/teams" variant="secondary" size="xs" underline="none">TEAMS</Link>
<Link href="/leagues" variant="secondary"> <Link href="/docs" variant="secondary" size="xs" underline="none">DOCUMENTATION</Link>
Leagues
</Link>
</Stack>
<Stack as="li">
<Link href="/teams" variant="secondary">
Teams
</Link>
</Stack>
<Stack as="li">
<Link href="/leaderboards" variant="secondary">
Leaderboards
</Link>
</Stack>
</Stack> </Stack>
</Stack>
<Stack gap={4}> {/* Right: System Status */}
<Text size="xs" weight="bold" variant="high" uppercase letterSpacing="wider">SUPPORT</Text> <Stack direction="row" align="center" gap={4}>
<Stack as="ul" direction="col" gap={2}> <Box display="flex" alignItems="center" gap={2}>
<Stack as="li"> <Box w="6px" h="6px" rounded="full" bg="var(--ui-color-intent-success)" animate="pulse" />
<Link href="/docs" variant="secondary"> <Text size="xs" variant="low" font="mono">SYSTEM NOMINAL</Text>
Documentation </Box>
</Link> <Text size="xs" variant="low" font="mono">v1.0.0</Text>
</Stack>
<Stack as="li">
<Link href="/status" variant="secondary">
System Status
</Link>
</Stack>
<Stack as="li">
<Link href="/contact" variant="secondary">
Contact
</Link>
</Stack>
</Stack> </Stack>
</Stack>
</Grid> </Box>
</AppFooter> </Container>
</Surface>
); );
} }

View File

@@ -41,16 +41,17 @@ export function RootAppShellTemplate({ children }: RootAppShellViewData) {
</TopNav> </TopNav>
</ControlBar> </ControlBar>
<Box display="flex" flexGrow={1}> <Box display="flex" flexGrow={1} width="full">
{showSidebar && <GlobalSidebarTemplate />} {showSidebar && <GlobalSidebarTemplate />}
<Box as="main" display="flex" flexGrow={1} flexDirection="col"> <Box as="main" display="flex" flexGrow={1} flexDirection="col" minWidth="0">
<ContentViewport fullWidth={!showSidebar}> <ContentViewport fullWidth={!showSidebar}>
{children} {children}
</ContentViewport> </ContentViewport>
<GlobalFooterTemplate />
</Box> </Box>
</Box> </Box>
<GlobalFooterTemplate />
</AppShell> </AppShell>
); );
} }

View File

@@ -21,11 +21,9 @@ export const ContentViewport = ({
}; };
return ( return (
<Box flexGrow={1}> <Box flexGrow={1} width="full">
<Container size={fullWidth ? 'full' : 'xl'}> <Container size={fullWidth ? 'full' : 'xl'} py={paddingMap[padding]}>
<Box paddingY={paddingMap[padding]}> {children}
{children}
</Box>
</Container> </Container>
</Box> </Box>
); );

View File

@@ -1,140 +1,134 @@
🎨 GridPilot Dev Theme — “Precision Racing Minimal” 🎨 GridPilot Theme — “Precision Racing Minimal”
The core idea: A clean, modern racing interface that feels like a cockpit dashboard — calm, sharp, and serious.
A UI that feels like a race engineers dashboard — not a game launcher, not corporate SaaS.
1. Identity & Mood 1. Identity & Mood
The theme should communicate: GridPilot should feel like:
Precision (like telemetry screens) a real motorsport instrument, not a game launcher
Calm intensity (the feeling before a qualifying lap) calm and focused, like the moment before a qualifying lap
Authority without ego (used by serious racers) precise, like a telemetry screen
Modern minimalism (dev-friendly, clean structure) modern and minimal, without visual noise
Soft gaming hints (subtle neon touches, not RGB vomit) slightly futuristic, but never “RGB gamer chaos”
It appeals equally to: It should appeal equally to sim racers, gamers, and casual fans.
• Devs (clean, modular, readable components)
• Gamers (immersive, familiar atmosphere)
• Simracers (motorsport seriousness)
2. Visual Language 2. Visual Style
Primary Look Core Aesthetic
Dark, matte surfaces • matte dark surfaces
Thin, crisp separators thin, crisp separators
Soft glow accents in blue / cyan / purple soft blue/cyan glows on interaction
Avoid aggressive neon or gamer-overload no aggressive neon
Subtle gradient tints (barely visible) subtle gradients for depth
• everything feels instrument-grade, not decorative
Color System Color System
Base: Near-black graphite (#0C0D0F) Graphite Black — base background
Surface: Deep charcoal (#141619) Charcoal — panel surfaces
Outline: Soft steel grey (#23272B) Steel Grey — separators & outlines
Primary Accent: Electric blue (#198CFF) • Electric Blue — primary actions
• Telemetry Accent: Aqua (#4ED4E0) • Telemetry Aqua — interactive highlights
Warning: Motorsport amber (#FFBE4D) • Motorsport Amber — warnings & signals
Everything should feel instrument-grade, not decorative. Colors should feel like motorsport, not corporate SaaS.
3. Component Philosophy 3. Components & Interaction
Cards Panels & Cards
Functional over flashy slightly inset or raised
Slight bevel or inset shadow (hint of cockpit panels) reminiscent of cockpit modules
Dense info, clean hierarchy structured and clean
Tables Tables
High-density information-dense
Thin row dividers instantly scannable
Highlight on hover only • light hover highlights
Telemetry-coded status colors telemetry-style status colors
Buttons Buttons
Flat by default flat by default
Glow + gradient only on hover glow only on hover
Snappy micro-animation (motorsport feedback) snappy, “race-engineer” response speed
Modals Modals
Soft frosted blur soft frosted blur
Fast open/close animation fast open/close
Dimmed pit-lane-lighting vibe subtle pit-lane lighting vibes
4. Motion & Feedback 4. Motion & Feedback
Racing-inspired, but minimal: Motion should feel racing-inspired:
Short accelerations (fast ease-out) short, crisp animations
No bounces — this isnt a game store no bounce or playful movement
Hover = slight lift + color pulse hover = slight lift + color pulse
Loading = progress line (like pit limiter light) loading = a thin progress line (pit limiter style)
Switching tabs = sliding underline (chicane motion) tab switching = sliding underline (chicane motion)
Devs should feel the UI is responsive, not playful. Responsive, not playful.
5. Layout Structure 5. Layout Structure
Think Telemetry Workspace: Think Telemetry Workspace:
• Sidebar = dashboard rail • Sidebar → control rail
• Header = control bar • Header → context + session controls
Content = track map / data table zone Main Area → race tables, session details, track maps
• Right panel = session or context info • Right Panel contextual info, drivers, actions
Everything modular, easily replaceable, easy to reason about. Everything modular, readable, and effortless to navigate.
6. Tone for Dev-Facing Text 6. Tone & Copywriting
• Short
• Neutral The product tone is:
Calm calm
Technical concise
Real-world language (not corporate slang) direct
• technical but human
• zero hype
Examples: Examples:
• “Add race • “Race added.
• “Review protest • “Standings updated.
• “Session updated • “Session ready.
• “Export standings • “Review protest.
• “Sponsor payout queued” • “Sponsor payout queued.
No hype. No marketing tone inside the app. Never corporate. Never salesy. Never loud.
7. Emotional Target 7. Emotional Experience
Users should feel: Users should feel:
In control in control
Supported supported
Efficient efficient
Connected to motorsport culture connected to motorsport culture
Trusting (nothing looks cheap or gimmicky) confident in the system
Its basically: A disciplined, trustworthy tool — not a flashy app.
“A premium cockpit dashboard… built by people who race and code.”
8. UI Layering & Primitives 8. Overall Vibe
To maintain architectural integrity and prevent "div wrapper" abuse, we enforce a strict layering boundary: “A premium cockpit dashboard — for people who actually race.”
• minimal
• precise
• clean
• serious
• attractive without noise
### Semantic UI (`apps/website/ui/`) A tool youre happy to use, because it respects your time and your craft.
- **Building blocks for components**: `Card`, `Panel`, `Button`, `Table`, `Stack`, `Grid`.
- **Restricted flexibility**: Semantic layout components (like `Stack`, `Grid`) are restricted to layout-only props. They do NOT allow styling props (bg, border, etc.).
- **Public API**: These are the only UI elements that should be imported by `components/` or `pages/`.
### Components (`apps/website/components/`)
- **Domain-specific**: `RecentRacesPanel`, `DriverCard`, `LeagueHeader`.
- **No raw HTML**: Components must use semantic UI elements. Direct use of raw HTML tags is forbidden.
**Rule of thumb**: If you need a styled container in a component, use `Panel` or `Card`. If you need a new type of styled container, create it in `ui/` using primitives.