| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- 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;
- }
- }
- // Get all themes (built-in + custom)
- export async function getAllThemes() {
- const data = await loadThemes();
- return {
- activeTheme: data.activeTheme,
- themes: [...data.builtInThemes, ...data.customThemes]
- };
- }
- // Get active theme
- export async function getActiveTheme() {
- const data = await loadThemes();
- const allThemes = [...data.builtInThemes, ...data.customThemes];
- return allThemes.find(theme => theme.id === data.activeTheme) || 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');
- }
-
- data.activeTheme = themeId;
- await saveThemes(data);
-
- 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
- if (data.activeTheme === themeId) {
- data.activeTheme = '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();
|