website refactor
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||
@import '../ui/theme/theme.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
||||
@@ -71,7 +71,7 @@ export default async function RootLayout({
|
||||
const enabledFlags = featureService.getEnabledFlags();
|
||||
|
||||
return (
|
||||
<html lang="en" className="scroll-smooth overflow-x-hidden">
|
||||
<html lang="en" className="scroll-smooth overflow-x-hidden" data-theme="default">
|
||||
<head>
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
</head>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { NotificationProvider } from '@/components/notifications/NotificationPro
|
||||
import { NotificationIntegration } from '@/components/errors/NotificationIntegration';
|
||||
import { EnhancedErrorBoundary } from '@/components/errors/EnhancedErrorBoundary';
|
||||
import { DevToolbar } from '@/components/dev/DevToolbar';
|
||||
import { ThemeProvider } from '@/ui/theme/ThemeProvider';
|
||||
import React from 'react';
|
||||
|
||||
interface AppWrapperProps {
|
||||
@@ -19,17 +20,19 @@ export function AppWrapper({ children, enabledFlags }: AppWrapperProps) {
|
||||
return (
|
||||
<ContainerProvider>
|
||||
<QueryClientProvider>
|
||||
<AuthProvider>
|
||||
<FeatureFlagProvider flags={enabledFlags}>
|
||||
<NotificationProvider>
|
||||
<NotificationIntegration />
|
||||
<EnhancedErrorBoundary enableDevOverlay={process.env.NODE_ENV === 'development'}>
|
||||
{children}
|
||||
{process.env.NODE_ENV === 'development' && <DevToolbar />}
|
||||
</EnhancedErrorBoundary>
|
||||
</NotificationProvider>
|
||||
</FeatureFlagProvider>
|
||||
</AuthProvider>
|
||||
<ThemeProvider>
|
||||
<AuthProvider>
|
||||
<FeatureFlagProvider flags={enabledFlags}>
|
||||
<NotificationProvider>
|
||||
<NotificationIntegration />
|
||||
<EnhancedErrorBoundary enableDevOverlay={process.env.NODE_ENV === 'development'}>
|
||||
{children}
|
||||
{process.env.NODE_ENV === 'development' && <DevToolbar />}
|
||||
</EnhancedErrorBoundary>
|
||||
</NotificationProvider>
|
||||
</FeatureFlagProvider>
|
||||
</AuthProvider>
|
||||
</ThemeProvider>
|
||||
</QueryClientProvider>
|
||||
</ContainerProvider>
|
||||
);
|
||||
|
||||
57
apps/website/ui/theme/Theme.ts
Normal file
57
apps/website/ui/theme/Theme.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export interface ThemeColors {
|
||||
bg: {
|
||||
base: string;
|
||||
surface: string;
|
||||
surfaceMuted: string;
|
||||
};
|
||||
border: {
|
||||
default: string;
|
||||
muted: string;
|
||||
};
|
||||
text: {
|
||||
high: string;
|
||||
med: string;
|
||||
low: string;
|
||||
};
|
||||
intent: {
|
||||
primary: string;
|
||||
telemetry: string;
|
||||
warning: string;
|
||||
success: string;
|
||||
critical: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ThemeRadii {
|
||||
none: string;
|
||||
sm: string;
|
||||
md: string;
|
||||
lg: string;
|
||||
xl: string;
|
||||
full: string;
|
||||
}
|
||||
|
||||
export interface ThemeShadows {
|
||||
none: string;
|
||||
sm: string;
|
||||
md: string;
|
||||
lg: string;
|
||||
xl: string;
|
||||
focus: string;
|
||||
}
|
||||
|
||||
export interface ThemeTypography {
|
||||
fontFamily: {
|
||||
sans: string;
|
||||
mono: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Theme {
|
||||
id: string;
|
||||
name: string;
|
||||
colors: ThemeColors;
|
||||
radii: ThemeRadii;
|
||||
shadows: ThemeShadows;
|
||||
typography: ThemeTypography;
|
||||
}
|
||||
33
apps/website/ui/theme/ThemeProvider.tsx
Normal file
33
apps/website/ui/theme/ThemeProvider.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
'use client';
|
||||
|
||||
import React, { createContext, useContext, ReactNode } from 'react';
|
||||
import { Theme } from './Theme';
|
||||
import { defaultTheme } from './themes/default';
|
||||
|
||||
interface ThemeContextType {
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
||||
|
||||
export function ThemeProvider({ children }: { children: ReactNode }) {
|
||||
// For now, we only have the default theme.
|
||||
// In the future, this could be driven by state, cookies, or user preferences.
|
||||
const value = {
|
||||
theme: defaultTheme,
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={value}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
const context = useContext(ThemeContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useTheme must be used within a ThemeProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
41
apps/website/ui/theme/theme.css
Normal file
41
apps/website/ui/theme/theme.css
Normal file
@@ -0,0 +1,41 @@
|
||||
:root {
|
||||
/* Base tokens mapped to default theme */
|
||||
--ui-color-bg-base: #0C0D0F;
|
||||
--ui-color-bg-surface: #141619;
|
||||
--ui-color-bg-surface-muted: rgba(20, 22, 25, 0.7);
|
||||
|
||||
--ui-color-border-default: #23272B;
|
||||
--ui-color-border-muted: rgba(35, 39, 43, 0.5);
|
||||
|
||||
--ui-color-text-high: #FFFFFF;
|
||||
--ui-color-text-med: #A1A1AA;
|
||||
--ui-color-text-low: #71717A;
|
||||
|
||||
--ui-color-intent-primary: #198CFF;
|
||||
--ui-color-intent-telemetry: #4ED4E0;
|
||||
--ui-color-intent-warning: #FFBE4D;
|
||||
--ui-color-intent-success: #6FE37A;
|
||||
--ui-color-intent-critical: #E35C5C;
|
||||
|
||||
--ui-radius-none: 0;
|
||||
--ui-radius-sm: 0.125rem;
|
||||
--ui-radius-md: 0.375rem;
|
||||
--ui-radius-lg: 0.5rem;
|
||||
--ui-radius-xl: 0.75rem;
|
||||
--ui-radius-full: 9999px;
|
||||
|
||||
--ui-shadow-none: none;
|
||||
--ui-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--ui-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
--ui-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
--ui-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
--ui-shadow-focus: 0 0 0 4px rgba(25, 140, 255, 0.5);
|
||||
|
||||
--ui-font-sans: 'Inter', system-ui, sans-serif;
|
||||
--ui-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* Theme override block */
|
||||
[data-theme='default'] {
|
||||
/* Currently same as root, but allows for future overrides */
|
||||
}
|
||||
51
apps/website/ui/theme/themes/default.ts
Normal file
51
apps/website/ui/theme/themes/default.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Theme } from '../Theme';
|
||||
|
||||
export const defaultTheme: Theme = {
|
||||
id: 'default',
|
||||
name: 'Precision Racing (Dark)',
|
||||
colors: {
|
||||
bg: {
|
||||
base: '#0C0D0F',
|
||||
surface: '#141619',
|
||||
surfaceMuted: 'rgba(20, 22, 25, 0.7)',
|
||||
},
|
||||
border: {
|
||||
default: '#23272B',
|
||||
muted: 'rgba(35, 39, 43, 0.5)',
|
||||
},
|
||||
text: {
|
||||
high: '#FFFFFF',
|
||||
med: '#A1A1AA',
|
||||
low: '#71717A',
|
||||
},
|
||||
intent: {
|
||||
primary: '#198CFF',
|
||||
telemetry: '#4ED4E0',
|
||||
warning: '#FFBE4D',
|
||||
success: '#6FE37A',
|
||||
critical: '#E35C5C',
|
||||
},
|
||||
},
|
||||
radii: {
|
||||
none: '0',
|
||||
sm: '0.125rem',
|
||||
md: '0.375rem',
|
||||
lg: '0.5rem',
|
||||
xl: '0.75rem',
|
||||
full: '9999px',
|
||||
},
|
||||
shadows: {
|
||||
none: 'none',
|
||||
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
||||
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
|
||||
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
||||
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
||||
focus: '0 0 0 4px rgba(25, 140, 255, 0.5)',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: {
|
||||
sans: "'Inter', system-ui, sans-serif",
|
||||
mono: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user