MAESTRO: Extract theme types to shared location for web interface

- Create src/shared/theme-types.ts with Theme, ThemeId, ThemeMode, ThemeColors types
- Add isValidThemeId type guard utility function
- Update renderer types to re-export from shared location
- Update main process themes.ts to use shared types
- Update web-server.ts to import Theme from shared instead of defining WebTheme
- This enables the web interface build to access theme types without duplicating code
This commit is contained in:
Pedram Amini
2025-11-27 03:08:15 -06:00
parent 72b847840a
commit 98aebe06f3
5 changed files with 129 additions and 47 deletions

View File

@@ -2,11 +2,12 @@
// This mirrors src/renderer/constants/themes.ts for use in the main process // This mirrors src/renderer/constants/themes.ts for use in the main process
// When themes are updated in the renderer, this file should also be updated // When themes are updated in the renderer, this file should also be updated
import type { WebTheme } from './web-server'; import type { Theme, ThemeId } from '../shared/theme-types';
export type ThemeId = 'dracula' | 'monokai' | 'github-light' | 'solarized-light' | 'nord' | 'tokyo-night' | 'one-light' | 'gruvbox-light' | 'catppuccin-mocha' | 'gruvbox-dark' | 'catppuccin-latte' | 'ayu-light' | 'pedurple' | 'maestros-choice' | 'dre-synth' | 'inquest'; // Re-export types from shared for convenience
export type { Theme, ThemeId } from '../shared/theme-types';
export const THEMES: Record<ThemeId, WebTheme> = { export const THEMES: Record<ThemeId, Theme> = {
// Dark themes // Dark themes
dracula: { dracula: {
id: 'dracula', id: 'dracula',
@@ -320,6 +321,6 @@ export const THEMES: Record<ThemeId, WebTheme> = {
* Get a theme by its ID * Get a theme by its ID
* Returns null if the theme ID is not found * Returns null if the theme ID is not found
*/ */
export function getThemeById(themeId: string): WebTheme | null { export function getThemeById(themeId: string): Theme | null {
return THEMES[themeId as ThemeId] || null; return THEMES[themeId as ThemeId] || null;
} }

View File

@@ -5,6 +5,7 @@ import rateLimit from '@fastify/rate-limit';
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { WebSocket } from 'ws'; import { WebSocket } from 'ws';
import crypto from 'crypto'; import crypto from 'crypto';
import type { Theme } from '../shared/theme-types';
// Types for web client messages // Types for web client messages
interface WebClientMessage { interface WebClientMessage {
@@ -105,29 +106,11 @@ export type WriteToSessionCallback = (sessionId: string, data: string) => boolea
// Returns true if successful, false if session not found or interrupt failed // Returns true if successful, false if session not found or interrupt failed
export type InterruptSessionCallback = (sessionId: string) => boolean; export type InterruptSessionCallback = (sessionId: string) => boolean;
// Theme type for web clients (matches renderer/types/index.ts) // Re-export Theme type from shared for backwards compatibility
export interface WebTheme { export type { Theme } from '../shared/theme-types';
id: string;
name: string;
mode: 'light' | 'dark' | 'vibe';
colors: {
bgMain: string;
bgSidebar: string;
bgActivity: string;
border: string;
textMain: string;
textDim: string;
accent: string;
accentDim: string;
accentText: string;
success: string;
warning: string;
error: string;
};
}
// Callback type for fetching current theme // Callback type for fetching current theme
export type GetThemeCallback = () => WebTheme | null; export type GetThemeCallback = () => Theme | null;
// Default rate limit configuration // Default rate limit configuration
const DEFAULT_RATE_LIMIT_CONFIG: RateLimitConfig = { const DEFAULT_RATE_LIMIT_CONFIG: RateLimitConfig = {
@@ -1002,7 +985,7 @@ export class WebServer {
* Broadcast theme change to all connected web clients * Broadcast theme change to all connected web clients
* Called when the user changes the theme in the desktop app * Called when the user changes the theme in the desktop app
*/ */
broadcastThemeChange(theme: WebTheme) { broadcastThemeChange(theme: Theme) {
this.broadcastToWebClients({ this.broadcastToWebClients({
type: 'theme', type: 'theme',
theme, theme,

View File

@@ -1,34 +1,16 @@
// Type definitions for Maestro renderer // Type definitions for Maestro renderer
// Re-export theme types from shared location
export { Theme, ThemeId, ThemeMode, ThemeColors, isValidThemeId } from '../../shared/theme-types';
export type ToolType = 'claude' | 'aider' | 'opencode' | 'terminal'; export type ToolType = 'claude' | 'aider' | 'opencode' | 'terminal';
export type SessionState = 'idle' | 'busy' | 'waiting_input' | 'connecting' | 'error'; export type SessionState = 'idle' | 'busy' | 'waiting_input' | 'connecting' | 'error';
export type FileChangeType = 'modified' | 'added' | 'deleted'; export type FileChangeType = 'modified' | 'added' | 'deleted';
export type RightPanelTab = 'files' | 'history' | 'scratchpad'; export type RightPanelTab = 'files' | 'history' | 'scratchpad';
export type ScratchPadMode = 'raw' | 'preview' | 'wysiwyg'; export type ScratchPadMode = 'raw' | 'preview' | 'wysiwyg';
export type ThemeId = 'dracula' | 'monokai' | 'github-light' | 'solarized-light' | 'nord' | 'tokyo-night' | 'one-light' | 'gruvbox-light' | 'catppuccin-mocha' | 'gruvbox-dark' | 'catppuccin-latte' | 'ayu-light' | 'pedurple' | 'maestros-choice' | 'dre-synth' | 'inquest';
export type FocusArea = 'sidebar' | 'main' | 'right'; export type FocusArea = 'sidebar' | 'main' | 'right';
export type LLMProvider = 'openrouter' | 'anthropic' | 'ollama'; export type LLMProvider = 'openrouter' | 'anthropic' | 'ollama';
export interface Theme {
id: ThemeId;
name: string;
mode: 'light' | 'dark' | 'vibe';
colors: {
bgMain: string;
bgSidebar: string;
bgActivity: string;
border: string;
textMain: string;
textDim: string;
accent: string;
accentDim: string;
accentText: string;
success: string;
warning: string;
error: string;
};
}
export interface Shortcut { export interface Shortcut {
id: string; id: string;
label: string; label: string;

10
src/shared/index.ts Normal file
View File

@@ -0,0 +1,10 @@
/**
* Shared types and utilities for Maestro
*
* This module exports types that are used across multiple parts of the application:
* - Main process (Electron)
* - Renderer process (Desktop React app)
* - Web interface (Mobile and Desktop web builds)
*/
export * from './theme-types';

106
src/shared/theme-types.ts Normal file
View File

@@ -0,0 +1,106 @@
/**
* Shared theme type definitions for Maestro
*
* This file contains theme types used across:
* - Main process (Electron)
* - Renderer process (Desktop React app)
* - Web interface (Mobile and Desktop web builds)
*
* Keep this file dependency-free to ensure it can be imported anywhere.
*/
/**
* Available theme identifiers
*/
export type ThemeId =
| 'dracula'
| 'monokai'
| 'github-light'
| 'solarized-light'
| 'nord'
| 'tokyo-night'
| 'one-light'
| 'gruvbox-light'
| 'catppuccin-mocha'
| 'gruvbox-dark'
| 'catppuccin-latte'
| 'ayu-light'
| 'pedurple'
| 'maestros-choice'
| 'dre-synth'
| 'inquest';
/**
* Theme mode indicating the overall brightness/style
*/
export type ThemeMode = 'light' | 'dark' | 'vibe';
/**
* Color palette for a theme
* Each color serves a specific purpose in the UI
*/
export interface ThemeColors {
/** Main background color for primary content areas */
bgMain: string;
/** Sidebar background color */
bgSidebar: string;
/** Background for interactive/activity elements */
bgActivity: string;
/** Border color for dividers and outlines */
border: string;
/** Primary text color */
textMain: string;
/** Dimmed/secondary text color */
textDim: string;
/** Accent color for highlights and interactive elements */
accent: string;
/** Dimmed accent (typically with alpha transparency) */
accentDim: string;
/** Text color for accent contexts */
accentText: string;
/** Success state color (green tones) */
success: string;
/** Warning state color (yellow/orange tones) */
warning: string;
/** Error state color (red tones) */
error: string;
}
/**
* Complete theme definition
*/
export interface Theme {
/** Unique identifier for the theme */
id: ThemeId;
/** Human-readable display name */
name: string;
/** Theme mode (light, dark, or vibe) */
mode: ThemeMode;
/** Color palette */
colors: ThemeColors;
}
/**
* Type guard to check if a string is a valid ThemeId
*/
export function isValidThemeId(id: string): id is ThemeId {
const validIds: ThemeId[] = [
'dracula',
'monokai',
'github-light',
'solarized-light',
'nord',
'tokyo-night',
'one-light',
'gruvbox-light',
'catppuccin-mocha',
'gruvbox-dark',
'catppuccin-latte',
'ayu-light',
'pedurple',
'maestros-choice',
'dre-synth',
'inquest',
];
return validIds.includes(id as ThemeId);
}