import fs from 'fs-extra'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const THEMES_FILE = path.join(__dirname, 'themes.json'); // Default theme configuration const DEFAULT_THEME = { name: 'Default', id: 'default', colors: { primary: '#3b82f6', // blue-500 primaryHover: '#2563eb', // blue-600 secondary: '#6b7280', // gray-500 background: '#ffffff', // white surface: '#f9fafb', // gray-50 text: '#1f2937', // gray-800 textSecondary: '#6b7280', // gray-500 border: '#e5e7eb', // gray-200 accent: '#10b981', // emerald-500 error: '#ef4444', // red-500 warning: '#f59e0b', // amber-500 success: '#10b981' // emerald-500 }, typography: { fontFamily: 'Inter, system-ui, sans-serif', headingFontFamily: 'Inter, system-ui, sans-serif', fontSize: { xs: '0.75rem', sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem', '4xl': '2.25rem' }, lineHeight: { tight: '1.25', normal: '1.5', relaxed: '1.625', loose: '2' } }, layout: { borderRadius: { sm: '0.125rem', base: '0.25rem', md: '0.375rem', lg: '0.5rem', xl: '0.75rem', '2xl': '1rem' }, spacing: { xs: '0.5rem', sm: '0.75rem', base: '1rem', lg: '1.5rem', xl: '2rem', '2xl': '3rem' }, shadows: { sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)', base: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)', md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)', lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)' } }, customCSS: '', createdAt: new Date().toISOString(), isBuiltIn: true }; // Built-in theme variations const BUILT_IN_THEMES = [ DEFAULT_THEME, { ...DEFAULT_THEME, name: 'Dark Mode', id: 'dark', colors: { ...DEFAULT_THEME.colors, background: '#111827', // gray-900 surface: '#1f2937', // gray-800 text: '#f9fafb', // gray-50 textSecondary: '#9ca3af', // gray-400 border: '#374151' // gray-700 } }, { ...DEFAULT_THEME, name: 'Ocean Blue', id: 'ocean', colors: { ...DEFAULT_THEME.colors, primary: '#0ea5e9', // sky-500 primaryHover: '#0284c7', // sky-600 accent: '#06b6d4', // cyan-500 surface: '#f0f9ff' // sky-50 } }, { ...DEFAULT_THEME, name: 'Forest Green', id: 'forest', colors: { ...DEFAULT_THEME.colors, primary: '#059669', // emerald-600 primaryHover: '#047857', // emerald-700 accent: '#10b981', // emerald-500 surface: '#ecfdf5' // emerald-50 } }, { ...DEFAULT_THEME, name: 'Minimalist', id: 'minimal', colors: { ...DEFAULT_THEME.colors, primary: '#000000', primaryHover: '#374151', secondary: '#6b7280', accent: '#000000' }, layout: { ...DEFAULT_THEME.layout, borderRadius: { sm: '0', base: '0', md: '0', lg: '0', xl: '0', '2xl': '0' } } } ]; // Initialize themes file async function initializeThemes() { try { if (!(await fs.pathExists(THEMES_FILE))) { const initialData = { activeTheme: 'default', customThemes: [], builtInThemes: BUILT_IN_THEMES }; await fs.writeJSON(THEMES_FILE, initialData, { spaces: 2 }); console.log('🎨 Initialized theme system with built-in themes'); } } catch (error) { console.error('Error initializing themes:', error); } } // Load themes data async function loadThemes() { try { if (await fs.pathExists(THEMES_FILE)) { return await fs.readJSON(THEMES_FILE); } return { activeTheme: 'default', customThemes: [], builtInThemes: BUILT_IN_THEMES }; } catch (error) { console.error('Error loading themes:', error); return { activeTheme: 'default', customThemes: [], builtInThemes: BUILT_IN_THEMES }; } } // Save themes data async function saveThemes(themesData) { try { await fs.writeJSON(THEMES_FILE, themesData, { spaces: 2 }); } catch (error) { console.error('Error saving themes:', error); throw error; } } import { getActiveThemeId, setActiveThemeId } from './config.js'; // ... existing imports ... // ... (keep constants and loadThemes/saveThemes as is, but remove activeTheme from their logic if possible, // strictly speaking we just need to ensure getActiveTheme/setActiveTheme use the new system) // Get all themes (built-in + custom) export async function getAllThemes() { const data = await loadThemes(); const activeThemeId = await getActiveThemeId(); return { activeTheme: activeThemeId, themes: [...data.builtInThemes, ...data.customThemes] }; } // Get active theme export async function getActiveTheme() { const data = await loadThemes(); const activeThemeId = await getActiveThemeId(); const allThemes = [...data.builtInThemes, ...data.customThemes]; return allThemes.find(theme => theme.id === activeThemeId) || DEFAULT_THEME; } // Set active theme export async function setActiveTheme(themeId) { const data = await loadThemes(); const allThemes = [...data.builtInThemes, ...data.customThemes]; if (!allThemes.find(theme => theme.id === themeId)) { throw new Error('Theme not found'); } await setActiveThemeId(themeId); return allThemes.find(theme => theme.id === themeId); } // Create custom theme export async function createCustomTheme(themeData) { const data = await loadThemes(); // Validate required fields if (!themeData.name || !themeData.id) { throw new Error('Theme name and id are required'); } // Check if theme ID already exists const allThemes = [...data.builtInThemes, ...data.customThemes]; if (allThemes.find(theme => theme.id === themeData.id)) { throw new Error('Theme ID already exists'); } const newTheme = { ...DEFAULT_THEME, ...themeData, createdAt: new Date().toISOString(), isBuiltIn: false }; data.customThemes.push(newTheme); await saveThemes(data); return newTheme; } // Update custom theme export async function updateCustomTheme(themeId, themeData) { const data = await loadThemes(); const themeIndex = data.customThemes.findIndex(theme => theme.id === themeId); if (themeIndex === -1) { throw new Error('Custom theme not found'); } data.customThemes[themeIndex] = { ...data.customThemes[themeIndex], ...themeData, id: themeId, // Prevent ID changes updatedAt: new Date().toISOString() }; await saveThemes(data); return data.customThemes[themeIndex]; } // Delete custom theme export async function deleteCustomTheme(themeId) { const data = await loadThemes(); const themeIndex = data.customThemes.findIndex(theme => theme.id === themeId); if (themeIndex === -1) { throw new Error('Custom theme not found'); } // If this was the active theme, switch to default const activeThemeId = await getActiveThemeId(); if (activeThemeId === themeId) { await setActiveThemeId('default'); } data.customThemes.splice(themeIndex, 1); await saveThemes(data); } // Export theme configuration export async function exportTheme(themeId) { const data = await loadThemes(); const allThemes = [...data.builtInThemes, ...data.customThemes]; const theme = allThemes.find(theme => theme.id === themeId); if (!theme) { throw new Error('Theme not found'); } // Remove internal fields for export const { createdAt, updatedAt, isBuiltIn, ...exportData } = theme; return exportData; } // Initialize themes on module load await initializeThemes();