UNPKG

@fredboulanger/ui-skins-storybook

Version:

Generate Storybook ui-skins configuration from *.ui_skins.themes.yml files

1 lines â€ĸ 12.8 kB
{"version":3,"sources":["../src/dataThemesGenerator.ts","../src/logger.ts","../src/vite-plugin-theme-generator.ts"],"sourcesContent":["import { readFile, writeFile } from 'node:fs/promises'\nimport { glob } from 'glob'\nimport { parse } from 'yaml'\nimport { join, resolve } from 'node:path'\n\nexport interface ThemeConfig {\n key: string\n label: string\n value: string\n target: string\n}\n\nexport interface ThemeGeneratorOptions {\n namespaces?: Record<string, string>\n}\n\n/**\n * Generate Storybook data-themes.ts configuration from *.ui_skins.themes.yml files\n */\nexport async function generateThemes(options: ThemeGeneratorOptions = {}): Promise<void> {\n console.log('🎨 Generating theme configuration from *.ui_skins.themes.yml files...')\n \n try {\n // Find all theme files in current directory and namespaces\n const searchPaths = [process.cwd()]\n \n // Add namespace paths if provided\n if (options.namespaces) {\n for (const [namespaceName, namespacePath] of Object.entries(options.namespaces)) {\n const resolvedPath = resolve(namespacePath)\n searchPaths.push(resolvedPath)\n console.log(`🔍 Searching themes in namespace '${namespaceName}': ${resolvedPath}`)\n }\n }\n \n // Search for theme files in all paths\n const themeFiles: string[] = []\n for (const searchPath of searchPaths) {\n try {\n const files = await glob('**/*.ui_skins.themes.yml', { cwd: searchPath })\n themeFiles.push(...files.map(file => join(searchPath, file)))\n } catch (error) {\n console.log(`âš ī¸ Could not search in path: ${searchPath}`)\n }\n }\n \n if (themeFiles.length === 0) {\n console.log('âš ī¸ No *.ui_skins.themes.yml files found - skipping theme generation')\n return\n }\n \n console.log(`📁 Found ${themeFiles.length} theme file(s):`, themeFiles)\n \n const themes: ThemeConfig[] = []\n \n // Parse each theme file\n for (const themeFile of themeFiles) {\n try {\n const content = await readFile(themeFile, 'utf8')\n const themeData = parse(content)\n \n // Extract theme information\n for (const [themeKey, themeConfig] of Object.entries(themeData)) {\n if (typeof themeConfig === 'object' && themeConfig !== null) {\n const config = themeConfig as any\n \n // Check if theme has required properties: label, key, and target\n if (config.label && config.key && config.target) {\n themes.push({\n key: themeKey,\n label: config.label,\n value: themeKey,\n target: config.target\n })\n console.log(`✅ Added theme: ${themeKey} (${config.label}) -> ${config.target}`)\n } else {\n console.log(`âš ī¸ Skipped theme: ${themeKey} - missing required properties (label, key, target)`)\n }\n }\n }\n \n console.log(`✅ Parsed theme file: ${themeFile}`)\n } catch (error) {\n console.error(`❌ Error parsing ${themeFile}:`, (error as Error).message)\n }\n }\n \n if (themes.length === 0) {\n console.log('âš ī¸ No valid themes found in the files - skipping theme generation')\n // Remove existing data-themes.ts file if it exists\n const themesConfigPath = join(process.cwd(), '.storybook', 'data-themes.ts')\n try {\n await writeFile(themesConfigPath, '', 'utf8')\n console.log(`đŸ—‘ī¸ Cleared existing data-themes.ts file`)\n } catch (error) {\n // File might not exist, which is fine\n }\n return\n }\n \n console.log(`đŸŽ¯ Found ${themes.length} theme(s):`, themes.map(t => t.key))\n \n // Generate the themes configuration file\n const themesConfigContent = generateThemesConfig(themes)\n const themesConfigPath = join(process.cwd(), '.storybook', 'data-themes.ts')\n await writeFile(themesConfigPath, themesConfigContent, 'utf8')\n \n console.log(`✅ Generated data-themes.ts with ${themes.length} theme(s)`)\n console.log(`📝 Updated: ${themesConfigPath}`)\n console.log(`💡 To use themes, add to your preview.ts:`)\n console.log(` import { themeDecorators, themeGlobalTypes } from './data-themes'`)\n console.log(` Then add ...themeDecorators to decorators and ...themeGlobalTypes to globalTypes`)\n \n } catch (error) {\n console.error('❌ Error generating themes:', error)\n throw error\n }\n}\n\n/**\n * Generate the themes configuration file\n */\nexport function generateThemesConfig(themes: ThemeConfig[]): string {\n const themeItems = themes.map(theme => \n ` { value: '${theme.value}', title: '${theme.label}' }`\n ).join(',\\n')\n \n const defaultTheme = themes.length > 0 ? themes[0].value : 'default'\n const defaultTarget = themes.length > 0 ? themes[0].target : 'body'\n \n // Create theme target mapping\n const themeTargets = themes.map(theme => \n ` '${theme.value}': '${theme.target}'`\n ).join(',\\n')\n \n return `// Auto-generated theme configuration from *.ui_skins.themes.yml files\n// This file is automatically generated - do not edit manually\n\n// Theme target mapping\nconst themeTargets = {\n${themeTargets}\n};\n\n// Add a decorator to set data-theme on the correct target element\nexport const themeDecorators = [\n (storyFn, context) => {\n // Wait for the target element to be available\n setTimeout(() => {\n const selectedTheme = context.globals.theme || '${defaultTheme}';\n const targetSelector = themeTargets[selectedTheme] || '${defaultTarget}';\n \n // Remove data-theme from both html and body to clean previous themes\n const html = document.querySelector('html');\n const body = document.querySelector('body');\n if (html) html.removeAttribute('data-theme');\n if (body) body.removeAttribute('data-theme');\n \n // Apply the new theme to the correct target\n const target = document.querySelector(targetSelector);\n if (target) {\n target.setAttribute('data-theme', selectedTheme);\n }\n }, 0);\n return storyFn();\n },\n];\n\nexport const themeGlobalTypes = {\n theme: {\n name: 'Theme',\n description: 'Global theme for components',\n defaultValue: '${defaultTheme}',\n toolbar: {\n icon: 'paintbrush',\n items: [\n${themeItems}\n ],\n },\n },\n};\n`\n}\n","// Simple logger implementation for data-themes-storybook package\nexport const logger = {\n info: (message: string, ...args: any[]) => {\n console.log(`â„šī¸ ${message}`, ...args)\n },\n warn: (message: string, ...args: any[]) => {\n console.warn(`âš ī¸ ${message}`, ...args)\n },\n error: (message: string, ...args: any[]) => {\n console.error(`❌ ${message}`, ...args)\n },\n debug: (message: string, ...args: any[]) => {\n console.debug(`🐛 ${message}`, ...args)\n }\n}\n","import type { Plugin } from 'vite'\nimport { generateThemes, ThemeGeneratorOptions } from './dataThemesGenerator.js'\nimport { logger } from './logger.js'\n\nexport interface ViteThemeGeneratorOptions {\n /**\n * Whether to generate themes on build start\n * @default true\n */\n generateOnStart?: boolean\n \n /**\n * Whether to watch theme files for changes\n * @default true\n */\n watch?: boolean\n \n /**\n * Namespaces to search for theme files\n */\n namespaces?: Record<string, string>\n}\n\n/**\n * Vite plugin for automatic theme generation from *.ui_skins.themes.yml files\n */\nexport default function vitePluginThemeGenerator(options: ViteThemeGeneratorOptions = {}): Plugin {\n const {\n generateOnStart = true,\n watch = true,\n namespaces\n } = options\n\n let hasGenerated = false\n\n return {\n name: 'vite-plugin-theme-generator',\n \n async buildStart() {\n if (generateOnStart && !hasGenerated) {\n try {\n await generateThemes({ namespaces })\n hasGenerated = true\n } catch (error) {\n logger.warn('Failed to generate themes on build start:', error)\n }\n }\n },\n\n async load(id: string) {\n // Generate themes when loading any component.yml file\n if (id.endsWith('component.yml') && !hasGenerated) {\n try {\n await generateThemes({ namespaces })\n hasGenerated = true\n } catch (error) {\n logger.warn('Failed to generate themes:', error)\n }\n }\n },\n\n async handleHotUpdate({ file }) {\n // Regenerate themes when theme files change\n if (watch && file.endsWith('.ui_skins.themes.yml')) {\n try {\n await generateThemes({ namespaces })\n logger.info('🎨 Themes regenerated due to file change:', file)\n } catch (error) {\n logger.warn('Failed to regenerate themes:', error)\n }\n }\n }\n }\n}\n"],"mappings":"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","names":["themesConfigPath"]}