const fs = require('fs'); const path = require('path'); /** * WARN: This script is generated by our good friend Chat Jippity * It may contain errors and weird behaviors... * Use at your own discretion */ const THEMES_DIR = path.join(__dirname, '../themes'); /** * Swaps the .icon and .text (or .total) properties with the .background property for a given base path. * @param {Object} themeData - The original theme JSON data. * @param {String} basePath - The base path of the properties to swap (e.g., 'theme.bar.buttons.volume'). * @param {Array} additionalTextKeys - Additional property keys to treat as 'text' (e.g., ['total']). */ function swapProperties(themeData, basePath, additionalTextKeys = []) { const iconKey = `${basePath}.icon`; const backgroundKey = `${basePath}.background`; const textKeys = additionalTextKeys.map((suffix) => `${basePath}.${suffix}`); if (themeData.hasOwnProperty(iconKey) && themeData.hasOwnProperty(backgroundKey)) { const originalIcon = themeData[iconKey]; const originalBackground = themeData[backgroundKey]; themeData[iconKey] = originalBackground; console.log(`✅ Updated '${iconKey}': '${originalIcon}' -> '${themeData[iconKey]}'`); themeData[backgroundKey] = originalIcon; console.log(`✅ Updated '${backgroundKey}': '${originalBackground}' -> '${themeData[backgroundKey]}'`); textKeys.forEach((textKey) => { if (themeData.hasOwnProperty(textKey)) { const originalText = themeData[textKey]; themeData[textKey] = originalBackground; console.log(`✅ Updated '${textKey}': '${originalText}' -> '${themeData[textKey]}'`); } else { console.warn(`⚠️ Property '${textKey}' not found in the theme. Skipping.`); } }); console.log(''); } else { console.warn(`⚠️ Missing '.icon' or '.background' for '${basePath}'. Skipping swap.\n`); } } /** * Identifies all base paths that match "theme.bar.buttons.*" and "theme.bar.buttons.modules.*" * and have necessary properties to perform swaps. * @param {Object} themeData - The original theme JSON data. * @returns {Array} - An array of objects containing basePath and any additional text-like keys. */ function identifyBasePaths(themeData) { const basePathsMap = new Map(); Object.keys(themeData).forEach((key) => { const regex = /^theme\.bar\.buttons(?:\.modules)?\.\w+\.(icon|background|text|total)$/; const match = key.match(regex); if (match) { const property = match[1]; const basePath = key.substring(0, key.lastIndexOf('.')); if (!basePathsMap.has(basePath)) { basePathsMap.set(basePath, []); } if (property === 'text' || property === 'total') { basePathsMap.get(basePath).push(property); } } }); const basePaths = []; basePathsMap.forEach((additionalTextKeys, basePath) => { basePaths.push({ basePath, additionalTextKeys }); }); return basePaths; } /** * Generates a vivid variant of the given theme by swapping specified properties. * @param {String} originalThemePath - Path to the original theme JSON file. * @param {String} vividThemePath - Path to save the vivid variant JSON file. */ function generateVividTheme(originalThemePath, vividThemePath) { try { const data = fs.readFileSync(originalThemePath, 'utf8'); const theme = JSON.parse(data); const basePathObjects = identifyBasePaths(theme); if (basePathObjects.length === 0) { console.warn(`⚠️ No swappable property groups found in '${path.basename(originalThemePath)}'. Skipping.\n`); return; } const vividTheme = { ...theme }; basePathObjects.forEach(({ basePath, additionalTextKeys }) => { swapProperties(vividTheme, basePath, additionalTextKeys); }); fs.writeFileSync(vividThemePath, JSON.stringify(vividTheme, null, 4), 'utf8'); console.log(`✅ Created vivid variant: '${path.basename(vividThemePath)}'\n`); } catch (error) { console.error(`❌ Error processing '${path.basename(originalThemePath)}': ${error.message}\n`); } } /** * Main function to process all themes and generate their vivid variants. */ function main() { if (!fs.existsSync(THEMES_DIR)) { console.error( `❌ Themes directory not found at '${THEMES_DIR}'. Please ensure it exists and contains theme JSON files.\n`, ); process.exit(1); } const files = fs.readdirSync(THEMES_DIR); const originalThemes = files.filter((file) => { return file.endsWith('.json') && !file.includes('_vivid') && !file.includes('_split'); }); if (originalThemes.length === 0) { console.log('ℹ️ No eligible theme files found to process.\n'); return; } originalThemes.forEach((themeFile) => { const themeName = path.parse(themeFile).name; const originalThemePath = path.join(THEMES_DIR, themeFile); const vividThemeFile = `${themeName}_vivid.json`; const vividThemePath = path.join(THEMES_DIR, vividThemeFile); if (fs.existsSync(vividThemePath)) { console.log(`ℹ️ Vivid variant already exists for '${themeFile}'. Skipping.\n`); return; } console.log(`🔄 Processing '${themeFile}'...`); generateVividTheme(originalThemePath, vividThemePath); }); console.log('🎉 All eligible vivid themes have been processed.\n'); } main();