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
@@ -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>
{/* Center: Technical Links */}
<Stack gap={4}> <Stack direction="row" gap={6} display={{ base: 'none', md: 'flex' }}>
<Text size="xs" weight="bold" variant="high" uppercase letterSpacing="wider">PLATFORM</Text> <Link href="/leagues" variant="secondary" size="xs" underline="none">LEAGUES</Link>
<Stack as="ul" direction="col" gap={2}> <Link href="/teams" variant="secondary" size="xs" underline="none">TEAMS</Link>
<Stack as="li"> <Link href="/docs" variant="secondary" size="xs" underline="none">DOCUMENTATION</Link>
<Link href="/leagues" variant="secondary">
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>
{/* Right: System Status */}
<Stack gap={4}> <Stack direction="row" align="center" gap={4}>
<Text size="xs" weight="bold" variant="high" uppercase letterSpacing="wider">SUPPORT</Text> <Box display="flex" alignItems="center" gap={2}>
<Stack as="ul" direction="col" gap={2}> <Box w="6px" h="6px" rounded="full" bg="var(--ui-color-intent-success)" animate="pulse" />
<Stack as="li"> <Text size="xs" variant="low" font="mono">SYSTEM NOMINAL</Text>
<Link href="/docs" variant="secondary"> </Box>
Documentation <Text size="xs" variant="low" font="mono">v1.0.0</Text>
</Link>
</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>
); );
} }
@@ -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>
); );
} }
+3 -5
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>
); );
+81 -87
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 engineer’s 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 isn’t 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
It’s 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 you’re 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.