mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
MAESTRO: Create ThemeProvider component for web interface
- Add src/web/components/ThemeProvider.tsx with React context for theming - Provide useTheme and useThemeColors hooks for child components - Include default theme (Dracula) for initial render before WebSocket connection - Update tsconfig.json to include src/web and src/shared directories
This commit is contained in:
141
src/web/components/ThemeProvider.tsx
Normal file
141
src/web/components/ThemeProvider.tsx
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
* ThemeProvider component for Maestro web interface
|
||||||
|
*
|
||||||
|
* Provides theme context to web components. Accepts theme via props
|
||||||
|
* (typically received from WebSocket connection to desktop app).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { createContext, useContext, useMemo } from 'react';
|
||||||
|
import type { Theme, ThemeColors } from '../../shared/theme-types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context value containing the current theme and utility functions
|
||||||
|
*/
|
||||||
|
interface ThemeContextValue {
|
||||||
|
/** Current theme object */
|
||||||
|
theme: Theme;
|
||||||
|
/** Whether the theme is a light theme */
|
||||||
|
isLight: boolean;
|
||||||
|
/** Whether the theme is a dark theme */
|
||||||
|
isDark: boolean;
|
||||||
|
/** Whether the theme is a vibe theme */
|
||||||
|
isVibe: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default theme used when no theme is provided
|
||||||
|
* Matches the Dracula theme from the desktop app
|
||||||
|
*/
|
||||||
|
const defaultTheme: Theme = {
|
||||||
|
id: 'dracula',
|
||||||
|
name: 'Dracula',
|
||||||
|
mode: 'dark',
|
||||||
|
colors: {
|
||||||
|
bgMain: '#0b0b0d',
|
||||||
|
bgSidebar: '#111113',
|
||||||
|
bgActivity: '#1c1c1f',
|
||||||
|
border: '#27272a',
|
||||||
|
textMain: '#e4e4e7',
|
||||||
|
textDim: '#a1a1aa',
|
||||||
|
accent: '#6366f1',
|
||||||
|
accentDim: 'rgba(99, 102, 241, 0.2)',
|
||||||
|
accentText: '#a5b4fc',
|
||||||
|
success: '#22c55e',
|
||||||
|
warning: '#eab308',
|
||||||
|
error: '#ef4444',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ThemeContext = createContext<ThemeContextValue | null>(null);
|
||||||
|
|
||||||
|
export interface ThemeProviderProps {
|
||||||
|
/** Theme object to provide to children. If not provided, uses default theme. */
|
||||||
|
theme?: Theme;
|
||||||
|
/** Children components that will have access to the theme */
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThemeProvider component that provides theme context to the component tree
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* // With theme from WebSocket
|
||||||
|
* <ThemeProvider theme={themeFromServer}>
|
||||||
|
* <App />
|
||||||
|
* </ThemeProvider>
|
||||||
|
*
|
||||||
|
* // Using the context in a child component
|
||||||
|
* const { theme, isDark } = useTheme();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function ThemeProvider({ theme = defaultTheme, children }: ThemeProviderProps) {
|
||||||
|
const contextValue = useMemo<ThemeContextValue>(
|
||||||
|
() => ({
|
||||||
|
theme,
|
||||||
|
isLight: theme.mode === 'light',
|
||||||
|
isDark: theme.mode === 'dark',
|
||||||
|
isVibe: theme.mode === 'vibe',
|
||||||
|
}),
|
||||||
|
[theme]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to access the current theme context
|
||||||
|
*
|
||||||
|
* @throws Error if used outside of a ThemeProvider
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* function MyComponent() {
|
||||||
|
* const { theme, isDark } = useTheme();
|
||||||
|
* return (
|
||||||
|
* <div style={{ backgroundColor: theme.colors.bgMain }}>
|
||||||
|
* {isDark ? 'Dark mode' : 'Light mode'}
|
||||||
|
* </div>
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function useTheme(): ThemeContextValue {
|
||||||
|
const context = useContext(ThemeContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('useTheme must be used within a ThemeProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to access just the theme colors for convenience
|
||||||
|
*
|
||||||
|
* @throws Error if used outside of a ThemeProvider
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* function Button() {
|
||||||
|
* const colors = useThemeColors();
|
||||||
|
* return (
|
||||||
|
* <button style={{
|
||||||
|
* backgroundColor: colors.accent,
|
||||||
|
* color: colors.accentText
|
||||||
|
* }}>
|
||||||
|
* Click me
|
||||||
|
* </button>
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function useThemeColors(): ThemeColors {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
return theme.colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ThemeContext };
|
||||||
|
export type { ThemeContextValue };
|
||||||
13
src/web/components/index.ts
Normal file
13
src/web/components/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Web interface components for Maestro
|
||||||
|
*
|
||||||
|
* Shared components used by both mobile and desktop web interfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {
|
||||||
|
ThemeProvider,
|
||||||
|
useTheme,
|
||||||
|
useThemeColors,
|
||||||
|
ThemeContext,
|
||||||
|
} from './ThemeProvider';
|
||||||
|
export type { ThemeProviderProps, ThemeContextValue } from './ThemeProvider';
|
||||||
9
src/web/index.ts
Normal file
9
src/web/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Maestro Web Interface
|
||||||
|
*
|
||||||
|
* This module contains shared components, hooks, and utilities
|
||||||
|
* for the Maestro web interface (both mobile and desktop web).
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Components
|
||||||
|
export * from './components';
|
||||||
@@ -15,5 +15,5 @@
|
|||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src/renderer"]
|
"include": ["src/renderer", "src/web", "src/shared"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user