UNPKG

superdesign-claude

Version:

SuperDesign Claude v2.2 - AI-Powered Design Pattern Recognition Engine with Code Generation - PHASE 1 + CODE GEN

947 lines (827 loc) 26.3 kB
/** * SuperDesign Code Generation Engine * Transforms wireframes and patterns into production-ready HTML/CSS/JS code */ const fs = require('fs-extra'); const path = require('path'); class CodeGenerationEngine { constructor(logger, errorHandler) { this.logger = logger; this.errorHandler = errorHandler; this.designSystem = this.loadDesignSystem(); this.componentTemplates = this.loadComponentTemplates(); this.layoutEngines = this.loadLayoutEngines(); } /** * Generate complete codebase from SuperDesign result */ async generateCode(designResult, outputOptions = {}) { try { const startTime = performance.now(); const codeGeneration = { html: await this.generateHTML(designResult), css: await this.generateCSS(designResult), javascript: await this.generateJavaScript(designResult), components: await this.generateComponents(designResult), assets: await this.generateAssets(designResult), metadata: { designSystem: 'SuperDesign v2.0', framework: outputOptions.framework || 'vanilla', responsive: true, accessibility: 'WCAG 2.1 AA', performance: 'optimized' } }; // Write files if output directory specified if (outputOptions.outputDir) { await this.writeCodeFiles(codeGeneration, outputOptions.outputDir); } const generationTime = performance.now() - startTime; this.logger.info('Code generation completed', { generationTime: Math.round(generationTime), filesGenerated: Object.keys(codeGeneration).length, framework: outputOptions.framework }); return codeGeneration; } catch (error) { this.logger.error('Code generation failed', error); throw error; } } /** * Generate HTML structure from wireframe and components */ async generateHTML(designResult) { const { pattern, components, layout, intent } = designResult; const htmlStructure = { doctype: '<!DOCTYPE html>', html: { attributes: { lang: 'en', class: `superdesign-${intent.intent.type}` }, head: this.generateHTMLHead(designResult), body: this.generateHTMLBody(designResult) } }; return this.renderHTML(htmlStructure); } /** * Generate HTML head section */ generateHTMLHead(designResult) { const { intent, pattern } = designResult; return ` <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="${intent.intent.type} built with SuperDesign"> <meta name="generator" content="SuperDesign Claude v2.2"> <title>${this.generatePageTitle(intent, pattern)}</title> <link rel="stylesheet" href="styles/main.css"> <link rel="stylesheet" href="styles/components.css"> <link rel="stylesheet" href="styles/responsive.css">`; } /** * Generate HTML body structure */ generateHTMLBody(designResult) { const { pattern, components, layout } = designResult; return ` <body class="layout-${layout.type.replace('css-', '')}"> ${this.buildLayoutStructure(pattern, components, layout)} <script src="scripts/main.js"></script> </body>`; } /** * Build layout structure from pattern and components */ buildLayoutStructure(pattern, components, layout) { let structure = ''; // Header section if (components.required.includes('navigation')) { structure += ` <header class="site-header"> <nav class="navigation"> <a href="#" class="nav-logo">${pattern.selectedPattern.name}</a> <ul class="nav-menu"> <li><a href="#" class="nav-link">Home</a></li> <li><a href="#" class="nav-link">Products</a></li> <li><a href="#" class="nav-link">About</a></li> <li><a href="#" class="nav-link">Contact</a></li> </ul> </nav> </header>`; } // Main content structure += ` <main class="main-content ${layout.type}"> ${this.generateMainContent(pattern, components, layout)} </main>`; // Footer section if (components.required.includes('footer') || components.recommended.includes('footer')) { structure += ` <footer class="site-footer"> <p>&copy; 2025 ${pattern.selectedPattern.name}. Built with SuperDesign.</p> </footer>`; } return structure; } /** * Generate main content based on pattern and components */ generateMainContent(pattern, components, layout) { const { selectedPattern } = pattern; let content = ''; if (selectedPattern.type === 'ecommerce') { content = this.generateEcommerceContent(components); } else if (selectedPattern.type === 'dashboard') { content = this.generateDashboardContent(components); } else if (selectedPattern.type === 'landing') { content = this.generateLandingContent(components); } else if (selectedPattern.type === 'auth') { content = this.generateAuthContent(components); } else { content = this.generateGenericContent(components); } return content; } /** * Generate ecommerce-specific content */ generateEcommerceContent(components) { return ` <div class="hero-section"> <h1>Welcome to Our Store</h1> <p>Discover amazing products at great prices</p> ${components.required.includes('search') ? ` <div class="search-bar"> <input type="text" placeholder="Search products..." class="form-input"> <button class="button button-primary">Search</button> </div>` : ''} </div> <section class="products-section"> <div class="products-grid"> ${this.generateProductCards()} </div> </section>`; } /** * Generate product cards for ecommerce */ generateProductCards() { let cards = ''; for (let i = 1; i <= 6; i++) { cards += ` <div class="card product-card"> <div class="card-image"> <img src="https://via.placeholder.com/300x200" alt="Product ${i}"> </div> <div class="card-content"> <h3 class="card-title">Product ${i}</h3> <p class="product-price">$${(Math.random() * 100 + 20).toFixed(2)}</p> <button class="button button-primary">Add to Cart</button> </div> </div>`; } return cards; } /** * Generate dashboard content */ generateDashboardContent(components) { return ` <div class="dashboard-grid"> <aside class="dashboard-sidebar"> <nav class="sidebar-nav"> <a href="#" class="sidebar-link active">Dashboard</a> <a href="#" class="sidebar-link">Analytics</a> <a href="#" class="sidebar-link">Reports</a> <a href="#" class="sidebar-link">Settings</a> </nav> </aside> <div class="dashboard-main"> <h1>Dashboard</h1> <div class="stats-grid"> ${this.generateStatCards()} </div> ${components.required.includes('chart') ? ` <div class="chart-section"> <div class="card"> <div class="card-header"> <h2 class="card-title">Analytics Overview</h2> </div> <div class="card-content"> <div class="chart-placeholder"> 📊 Chart would be rendered here </div> </div> </div> </div>` : ''} </div> </div>`; } /** * Generate stat cards for dashboard */ generateStatCards() { const stats = [ { title: 'Total Users', value: '12,345', change: '+12%' }, { title: 'Revenue', value: '$45,678', change: '+8%' }, { title: 'Orders', value: '1,234', change: '+15%' }, { title: 'Conversion', value: '3.45%', change: '+2%' } ]; return stats.map(stat => ` <div class="card stat-card"> <div class="card-content"> <h3 class="stat-title">${stat.title}</h3> <div class="stat-value">${stat.value}</div> <div class="stat-change positive">${stat.change}</div> </div> </div>`).join(''); } /** * Generate landing page content */ generateLandingContent(components) { return ` <div class="hero-section"> <div class="hero-content"> <h1 class="hero-title">Welcome to the Future</h1> <p class="hero-subtitle">Transform your workflow with our innovative platform</p> <div class="hero-actions"> <button class="button button-primary">Get Started</button> <button class="button button-secondary">Learn More</button> </div> </div> </div> <section class="features-section"> <h2>Why Choose Us</h2> <div class="features-grid"> ${this.generateFeatureCards()} </div> </section>`; } /** * Generate feature cards for landing page */ generateFeatureCards() { const features = [ { title: 'Fast & Reliable', description: 'Lightning fast performance you can count on' }, { title: 'Secure', description: 'Enterprise-grade security for your data' }, { title: 'Scalable', description: 'Grows with your business needs' } ]; return features.map(feature => ` <div class="card feature-card"> <div class="card-content"> <h3 class="card-title">${feature.title}</h3> <p>${feature.description}</p> </div> </div>`).join(''); } /** * Generate auth content */ generateAuthContent(components) { return ` <div class="auth-container"> <div class="auth-card card"> <div class="card-header"> <h1 class="card-title">Sign In</h1> <p>Welcome back! Please sign in to your account.</p> </div> <form class="auth-form"> <div class="form-group"> <label class="form-label">Email</label> <input type="email" class="form-input" placeholder="Enter your email"> </div> <div class="form-group"> <label class="form-label">Password</label> <input type="password" class="form-input" placeholder="Enter your password"> </div> <button type="submit" class="button button-primary auth-submit">Sign In</button> </form> </div> </div>`; } /** * Generate generic content */ generateGenericContent(components) { return ` <div class="content-section"> <h1>Welcome</h1> <p>This is a generic layout generated by SuperDesign.</p> <div class="cards-grid"> <div class="card"> <div class="card-header"> <h2 class="card-title">Card Title</h2> </div> <div class="card-content"> <p>Card content goes here.</p> <button class="button button-primary">Action</button> </div> </div> </div> </div>`; } /** * Generate CSS styles with design system */ async generateCSS(designResult) { const { layout, components, intent, pattern } = designResult; const cssFiles = { 'main.css': this.generateMainCSS(designResult), 'components.css': this.generateComponentsCSS(components), 'responsive.css': this.generateResponsiveCSS(layout), 'design-system.css': this.generateDesignSystemCSS() }; return cssFiles; } /** * Generate main CSS file */ generateMainCSS(designResult) { const { layout, intent, pattern } = designResult; return `/* SuperDesign Generated CSS - ${intent.intent.type} */ /* Design System: SuperDesign v2.1 */ :root { /* Design System Variables */ --primary-color: #2563eb; --secondary-color: #64748b; --accent-color: #0ea5e9; --background-color: #ffffff; --surface-color: #f8fafc; --text-primary: #0f172a; --text-secondary: #475569; --border-color: #e2e8f0; --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); --radius-sm: 0.375rem; --radius-md: 0.5rem; --radius-lg: 0.75rem; --spacing-xs: 0.5rem; --spacing-sm: 0.75rem; --spacing-md: 1rem; --spacing-lg: 1.5rem; --spacing-xl: 2rem; --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace; } /* Global Styles */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: var(--font-sans); line-height: 1.6; color: var(--text-primary); background-color: var(--background-color); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* Layout System */ ${this.generateLayoutCSS(layout)} /* Accessibility */ @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } } /* Focus Styles */ :focus-visible { outline: 2px solid var(--primary-color); outline-offset: 2px; } `; } /** * Generate layout-specific CSS */ generateLayoutCSS(layout) { if (layout.type === 'css-grid') { return ` /* CSS Grid Layout */ .layout-grid { display: grid; grid-template-columns: repeat(${layout.grid.columns}, 1fr); gap: ${layout.grid.gutters}px; max-width: 1200px; margin: 0 auto; padding: var(--spacing-md); } .site-header { grid-column: 1 / -1; } .main-content { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(${layout.grid.columns}, 1fr); gap: ${layout.grid.gutters}px; } .site-footer { grid-column: 1 / -1; }`; } return ` /* Flexbox Layout */ .layout-flex { display: flex; flex-direction: column; min-height: 100vh; } .main-content { flex: 1; max-width: 1200px; margin: 0 auto; padding: var(--spacing-md); }`; } /** * Generate components CSS */ generateComponentsCSS(components) { let css = '/* SuperDesign Components */\n\n'; const allComponents = [...components.required, ...components.recommended]; for (const component of allComponents) { css += this.getComponentCSS(component); } return css; } /** * Get CSS for specific component */ getComponentCSS(componentName) { const componentStyles = { navigation: ` /* Navigation Component */ .navigation { display: flex; align-items: center; justify-content: space-between; padding: var(--spacing-md) 0; border-bottom: 1px solid var(--border-color); } .nav-logo { font-size: 1.5rem; font-weight: 700; color: var(--primary-color); text-decoration: none; } .nav-menu { display: flex; list-style: none; gap: var(--spacing-lg); } .nav-link { color: var(--text-secondary); text-decoration: none; font-weight: 500; transition: color 0.2s ease; } .nav-link:hover, .nav-link:focus { color: var(--primary-color); } `, card: ` /* Card Component */ .card { background: var(--surface-color); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: var(--spacing-lg); box-shadow: var(--shadow-sm); transition: all 0.2s ease; } .card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); } .card-header { margin-bottom: var(--spacing-md); } .card-title { font-size: 1.25rem; font-weight: 600; margin-bottom: var(--spacing-xs); } .card-content { color: var(--text-secondary); } `, button: ` /* Button Component */ .button { display: inline-flex; align-items: center; justify-content: center; padding: var(--spacing-sm) var(--spacing-lg); border: none; border-radius: var(--radius-md); font-weight: 500; text-decoration: none; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .button-primary { background: var(--primary-color); color: white; } .button-primary:hover { background: color-mix(in srgb, var(--primary-color) 85%, black); } .button-secondary { background: var(--surface-color); color: var(--text-primary); border: 1px solid var(--border-color); } .button-secondary:hover { background: color-mix(in srgb, var(--surface-color) 85%, black); } `, form: ` /* Form Components */ .form { max-width: 400px; margin: 0 auto; } .form-group { margin-bottom: var(--spacing-lg); } .form-label { display: block; margin-bottom: var(--spacing-xs); font-weight: 500; color: var(--text-primary); } .form-input { width: 100%; padding: var(--spacing-sm) var(--spacing-md); border: 1px solid var(--border-color); border-radius: var(--radius-md); font-family: inherit; transition: border-color 0.2s ease; } .form-input:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 10%, transparent); } ` }; return componentStyles[componentName] || `/* ${componentName} component styles */\n`; } /** * Generate responsive CSS */ generateResponsiveCSS(layout) { return `/* Responsive Design */ /* Mobile First Approach */ @media (max-width: ${layout.breakpoints.tablet - 1}px) { .layout-grid { grid-template-columns: 1fr; padding: var(--spacing-sm); } .navigation { flex-direction: column; gap: var(--spacing-md); } .nav-menu { flex-direction: column; gap: var(--spacing-sm); } } /* Tablet */ @media (min-width: ${layout.breakpoints.tablet}px) and (max-width: ${layout.breakpoints.desktop - 1}px) { .layout-grid { grid-template-columns: repeat(${Math.ceil(layout.grid.columns / 2)}, 1fr); } } /* Desktop */ @media (min-width: ${layout.breakpoints.desktop}px) { .layout-grid { grid-template-columns: repeat(${layout.grid.columns}, 1fr); } } /* Large Desktop */ @media (min-width: 1440px) { .layout-grid { max-width: 1400px; } }`; } /** * Generate JavaScript functionality */ async generateJavaScript(designResult) { const { components, intent } = designResult; return `// SuperDesign Generated JavaScript // Design System: SuperDesign v2.1 class SuperDesignApp { constructor() { this.init(); } init() { this.setupEventListeners(); this.initializeComponents(); this.setupAccessibility(); } setupEventListeners() { document.addEventListener('DOMContentLoaded', () => { console.log('SuperDesign app initialized'); }); } initializeComponents() { ${this.generateComponentInitialization(components)} } setupAccessibility() { // Keyboard navigation document.addEventListener('keydown', (e) => { if (e.key === 'Tab') { document.body.classList.add('keyboard-navigation'); } }); // Mouse navigation document.addEventListener('mousedown', () => { document.body.classList.remove('keyboard-navigation'); }); } } // Initialize app new SuperDesignApp();`; } /** * Generate component initialization code */ generateComponentInitialization(components) { const allComponents = [...components.required, ...components.recommended]; let initCode = ''; if (allComponents.includes('navigation')) { initCode += ` // Navigation component this.initNavigation();`; } if (allComponents.includes('form')) { initCode += ` // Form validation this.initFormValidation();`; } if (allComponents.includes('modal')) { initCode += ` // Modal functionality this.initModals();`; } return initCode; } /** * Write generated code to files */ async writeCodeFiles(codeGeneration, outputDir) { try { // Ensure output directory exists await fs.ensureDir(outputDir); // Create directory structure await fs.ensureDir(path.join(outputDir, 'styles')); await fs.ensureDir(path.join(outputDir, 'scripts')); await fs.ensureDir(path.join(outputDir, 'components')); // Write HTML file await fs.writeFile( path.join(outputDir, 'index.html'), codeGeneration.html ); // Write CSS files for (const [filename, content] of Object.entries(codeGeneration.css)) { await fs.writeFile( path.join(outputDir, 'styles', filename), content ); } // Write JavaScript file await fs.writeFile( path.join(outputDir, 'scripts', 'main.js'), codeGeneration.javascript ); // Write component files if any if (codeGeneration.components) { for (const [componentName, componentCode] of Object.entries(codeGeneration.components)) { await fs.writeFile( path.join(outputDir, 'components', `${componentName}.html`), componentCode ); } } this.logger.info('Code files written successfully', { outputDir, filesWritten: Object.keys(codeGeneration).length }); } catch (error) { this.logger.error('Failed to write code files', error); throw error; } } /** * Load design system configuration */ loadDesignSystem() { return { colors: { primary: '#2563eb', secondary: '#64748b', accent: '#0ea5e9', background: '#ffffff', surface: '#f8fafc', text: { primary: '#0f172a', secondary: '#475569' }, border: '#e2e8f0' }, typography: { fontFamily: { sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', mono: '"SF Mono", Monaco, "Cascadia Code", monospace' }, fontSize: { xs: '0.75rem', sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem' } }, spacing: { xs: '0.5rem', sm: '0.75rem', md: '1rem', lg: '1.5rem', xl: '2rem', '2xl': '3rem' }, borderRadius: { sm: '0.375rem', md: '0.5rem', lg: '0.75rem', xl: '1rem' } }; } /** * Load component templates */ loadComponentTemplates() { return { navigation: this.getNavigationTemplate(), card: this.getCardTemplate(), button: this.getButtonTemplate(), form: this.getFormTemplate() }; } /** * Render HTML from structure object */ renderHTML(structure) { return `${structure.doctype} <html${this.renderAttributes(structure.html.attributes)}> <head>${structure.html.head} </head> ${structure.html.body} </html>`; } /** * Render HTML attributes */ renderAttributes(attributes) { if (!attributes) return ''; return Object.entries(attributes) .map(([key, value]) => ` ${key}="${value}"`) .join(''); } // Component template methods would go here... getNavigationTemplate() { return '<nav class="navigation"><!-- Navigation --></nav>'; } getCardTemplate() { return '<div class="card"><!-- Card content --></div>'; } getButtonTemplate() { return '<button class="button button-primary">Button</button>'; } getFormTemplate() { return '<form class="form"><!-- Form fields --></form>'; } loadLayoutEngines() { return {}; } generateDesignSystemCSS() { return '/* Design system styles */'; } generateComponents() { return {}; } generateAssets() { return {}; } generatePageTitle(intent, pattern) { return `${pattern.selectedPattern.name} - ${intent.intent.type.charAt(0).toUpperCase() + intent.intent.type.slice(1)}`; } // Component template methods getNavigationTemplate() { return '<nav class="navigation"><!-- Navigation --></nav>'; } getCardTemplate() { return '<div class="card"><!-- Card content --></div>'; } getButtonTemplate() { return '<button class="button button-primary">Button</button>'; } getFormTemplate() { return '<form class="form"><!-- Form fields --></form>'; } // Helper methods loadLayoutEngines() { return {}; } generateDesignSystemCSS() { return '/* Design system styles */'; } generateComponents() { return {}; } generateAssets() { return {}; } } module.exports = { CodeGenerationEngine };