UNPKG

muspe-cli

Version:

MusPE Advanced Framework v2.1.3 - Mobile User-friendly Simple Progressive Engine with Enhanced CLI Tools, Specialized E-Commerce Templates, Material Design 3, Progressive Enhancement, Mobile Optimizations, Performance Analysis, and Enterprise-Grade Develo

1,807 lines (1,570 loc) • 85.1 kB
const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); const inquirer = require('inquirer'); const ora = require('ora'); const spawn = require('cross-spawn'); const { execSync } = require('child_process'); const validatePackageName = require('validate-npm-package-name'); async function createProject(projectName, options) { const spinner = ora('Creating MusPE project...').start(); try { // Validate project name const validation = validatePackageName(projectName); if (!validation.validForNewPackages) { spinner.fail('Invalid project name'); console.log(chalk.red('Project name contains invalid characters')); return; } const projectPath = path.join(process.cwd(), projectName); // Check if directory exists if (await fs.pathExists(projectPath)) { spinner.fail('Directory already exists'); console.log(chalk.red(`Directory ${projectName} already exists`)); return; } // Interactive template selection if not specified let template = options.template; let framework = options.framework; if (!options.template || !options.framework) { spinner.stop(); const answers = await inquirer.prompt([ { type: 'list', name: 'template', message: 'Choose your project template:', choices: [ { name: 'ļæ½ E-Commerce - Product catalog with shopping cart', value: 'ecommerce' }, { name: 'šŸ“Š Dashboard - Analytics and data visualization', value: 'dashboard' }, { name: 'šŸ‘„ Social Media - Feed layout with user interactions', value: 'social' }, { name: 'šŸ’¼ Portfolio - Professional showcase website', value: 'portfolio' }, { name: 'šŸ“ Blog - Content management with articles', value: 'blog' }, { name: 'šŸ“± Mobile App - Basic mobile-optimized app', value: 'mobile' }, { name: '🌐 Web App - Traditional web application', value: 'web' }, { name: '⚔ PWA - Progressive Web App', value: 'pwa' }, { name: 'šŸ”€ Hybrid - Mobile + Web hybrid app', value: 'hybrid' } ], default: 'ecommerce' }, { type: 'list', name: 'framework', message: 'Choose your CSS framework:', choices: [ { name: 'šŸŽØ Material Design 3 - Google\'s latest design system', value: 'material' }, { name: '⚔ Tailwind CSS - Utility-first CSS framework', value: 'tailwind' }, { name: 'šŸ…±ļø Bootstrap - Popular CSS framework', value: 'bootstrap' }, { name: 'šŸ“ Custom CSS - Pure CSS (no framework)', value: 'custom' } ], default: 'material' } ]); template = answers.template; framework = answers.framework; spinner.start('Creating project structure...'); } // Create project directory await fs.ensureDir(projectPath); // Generate project files based on template await generateProjectStructure(projectPath, projectName, template, framework); spinner.succeed('Project structure created'); // Install dependencies if (!options.skipInstall) { spinner.start('Installing dependencies...'); await installDependencies(projectPath); spinner.succeed('Dependencies installed'); } // Success message console.log(chalk.green(`\n✨ Successfully created ${projectName}!`)); console.log(chalk.cyan('\nNext steps:')); console.log(` ${chalk.gray('$')} cd ${projectName}`); console.log(` ${chalk.gray('$')} muspe serve`); console.log(chalk.gray('\nHappy coding! šŸš€\n')); } catch (error) { spinner.fail('Failed to create project'); console.error(chalk.red(error.message)); } } async function generateProjectStructure(projectPath, projectName, template, framework) { // Create basic structure const dirs = [ 'src', 'src/components', 'src/pages', 'src/layouts', 'src/templates', 'src/styles', 'src/scripts', 'src/assets', 'src/assets/images', 'src/assets/icons', 'public' ]; // Add template-specific directories if (template === 'ecommerce') { dirs.push( 'src/services', 'src/utils', 'src/data', 'src/components/product', 'src/components/cart', 'src/components/search' ); } else if (template === 'dashboard') { dirs.push( 'src/services', 'src/utils', 'src/data', 'src/components/charts', 'src/components/widgets', 'src/components/analytics' ); } else if (template === 'social') { dirs.push( 'src/services', 'src/utils', 'src/data', 'src/components/feed', 'src/components/user', 'src/components/media' ); } else if (template === 'portfolio') { dirs.push( 'src/utils', 'src/data', 'src/components/gallery', 'src/components/projects', 'src/components/contact' ); } else if (template === 'blog') { dirs.push( 'src/services', 'src/utils', 'src/data', 'src/components/article', 'src/components/author', 'src/components/comments' ); } for (const dir of dirs) { await fs.ensureDir(path.join(projectPath, dir)); } // Generate package.json const packageJson = { name: projectName, version: '1.0.0', description: `A MusPE ${template} application`, main: 'src/index.js', scripts: { start: 'muspe serve', build: 'muspe build', dev: 'muspe serve --open' }, dependencies: {}, devDependencies: {}, muspe: { template, framework, version: '1.0.0' } }; // Add framework-specific dependencies if (framework === 'material') { packageJson.dependencies['@material/web'] = '^1.5.0'; packageJson.dependencies['@material/material-color-utilities'] = '^0.2.7'; packageJson.dependencies['lit'] = '^3.1.0'; } else if (framework === 'tailwind') { packageJson.devDependencies['tailwindcss'] = '^3.3.0'; packageJson.devDependencies['autoprefixer'] = '^10.4.14'; packageJson.devDependencies['postcss'] = '^8.4.24'; } else if (framework === 'bootstrap') { packageJson.dependencies['bootstrap'] = '^5.3.0'; } // Add Swiper.js for slide components (all frameworks) packageJson.dependencies['swiper'] = '^11.0.0'; // Add base Material.io components for layout system (all frameworks) if (framework !== 'material') { packageJson.dependencies['@material/web'] = '^1.5.0'; packageJson.dependencies['@material/material-color-utilities'] = '^0.2.7'; } // Add Vite for CSS imports (if not using a bundler) packageJson.devDependencies['vite'] = '^5.0.0'; // Add template-specific dependencies if (template === 'ecommerce') { packageJson.dependencies['chart.js'] = '^4.4.0'; packageJson.dependencies['date-fns'] = '^2.30.0'; packageJson.dependencies['fuse.js'] = '^7.0.0'; // For search functionality } else if (template === 'dashboard') { packageJson.dependencies['chart.js'] = '^4.4.0'; packageJson.dependencies['chartjs-adapter-date-fns'] = '^3.0.0'; packageJson.dependencies['date-fns'] = '^2.30.0'; packageJson.dependencies['d3'] = '^7.8.5'; } else if (template === 'social') { packageJson.dependencies['date-fns'] = '^2.30.0'; packageJson.dependencies['intersection-observer'] = '^0.12.2'; // For infinite scroll } else if (template === 'portfolio') { packageJson.dependencies['lightbox2'] = '^2.11.4'; packageJson.dependencies['aos'] = '^2.3.4'; // Animate on scroll } else if (template === 'blog') { packageJson.dependencies['markdown-it'] = '^13.0.2'; packageJson.dependencies['highlight.js'] = '^11.9.0'; packageJson.dependencies['date-fns'] = '^2.30.0'; } await fs.writeJSON(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 }); // Generate configuration files await generateConfigFiles(projectPath, template, framework); // Generate template files await generateTemplateFiles(projectPath, projectName, template, framework); // Generate layout system await generateLayoutSystem(projectPath, template, framework); // Generate template system await generateTemplateSystem(projectPath, template, framework); // Copy core utilities await copyUtilities(projectPath); } async function generateConfigFiles(projectPath, template, framework) { // MusPE config const config = `module.exports = { template: '${template}', framework: '${framework}', server: { port: 3000, host: 'localhost', open: true }, build: { outDir: 'dist', minify: true, sourcemap: true }, pwa: { enabled: ${template === 'pwa' || template === 'hybrid'}, manifest: './public/manifest.json', serviceWorker: './src/sw.js' }, mobile: { viewport: 'width=device-width, initial-scale=1.0, user-scalable=no', statusBar: 'default', orientation: 'portrait', touchOptimizations: true, preventZoomOnInput: true, fastClick: true, viewportHeight: 'dynamic', progressiveEnhancement: true }, };`; await fs.writeFile(path.join(projectPath, 'muspe.config.js'), config); // Generate framework-specific configs if (framework === 'material') { const materialConfig = `// Material Design 3 Configuration module.exports = { materialDesign: { theme: { source: '#6750A4', // Primary brand color scheme: 'light', // 'light' | 'dark' | 'auto' }, typography: { fontFamily: 'Roboto, sans-serif', scale: 'standard' // 'standard' | 'large' }, components: { // Import all Material Web components importAll: true, // Or specify individual components components: [ 'button', 'card', 'textfield', 'dialog', 'fab', 'navigation-drawer', 'navigation-rail', 'tabs' ] } } };`; await fs.writeFile(path.join(projectPath, 'material.config.js'), materialConfig); } else if (framework === 'tailwind') { const tailwindConfig = `/** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./src/**/*.{html,js}", "./public/**/*.html" ], theme: { extend: { screens: { 'xs': '475px', }, colors: { primary: { 50: '#eff6ff', 500: '#3b82f6', 600: '#2563eb', } } }, }, plugins: [], }`; await fs.writeFile(path.join(projectPath, 'tailwind.config.js'), tailwindConfig); const postcssConfig = `module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, }`; await fs.writeFile(path.join(projectPath, 'postcss.config.js'), postcssConfig); } } async function generateTemplateFiles(projectPath, projectName, template, framework) { // Generate index.html const htmlContent = generateHTMLTemplate(projectName, template, framework); await fs.writeFile(path.join(projectPath, 'public/index.html'), htmlContent); // Generate main CSS const cssContent = generateCSSTemplate(framework); await fs.writeFile(path.join(projectPath, 'src/styles/main.css'), cssContent); // Generate main JS const jsContent = generateJSTemplate(template, framework); await fs.writeFile(path.join(projectPath, 'src/scripts/main.js'), jsContent); // Generate example component const componentContent = generateComponentTemplate(framework); await fs.writeFile(path.join(projectPath, 'src/components/AppHeader.js'), componentContent); // Generate template-specific files if (template === 'ecommerce') { await generateEcommerceFiles(projectPath, framework); } else if (template === 'dashboard') { await generateDashboardFiles(projectPath, framework); } else if (template === 'social') { await generateSocialFiles(projectPath, framework); } else if (template === 'portfolio') { await generatePortfolioFiles(projectPath, framework); } else if (template === 'blog') { await generateBlogFiles(projectPath, framework); } else if (template === 'web') { await generateWebFiles(projectPath, framework); } else if (template === 'spa') { await generateSPAFiles(projectPath, framework); } else if (template === 'pwa') { await generatePWASpecificFiles(projectPath, framework); } // Copy Cordova demo component and service for mobile/hybrid apps if (template === 'mobile' || template === 'hybrid') { await copyCordovaFiles(projectPath); } // Generate PWA files if needed if (template === 'pwa' || template === 'hybrid') { await generatePWAFiles(projectPath, projectName); } // Generate README const readmeContent = `# ${projectName} A ${template} application built with MusPE Framework v2.1.3 ## Quick Start \`\`\`bash npm install npm start \`\`\` ## Features - šŸ“± Mobile-optimized responsive design - ⚔ Performance optimized - šŸŽØ Material Design 3 components - šŸ“Š Built-in analytics - šŸ”§ Progressive enhancement ## Development \`\`\`bash # Development server npm run dev # Build for production npm run build # Run tests npm test \`\`\` ## Documentation Visit [MusPE Documentation](https://github.com/your-org/muspe) for detailed guides. `; await fs.writeFile(path.join(projectPath, 'README.md'), readmeContent); } async function copyUtilities(projectPath) { const utilsDir = path.join(projectPath, 'src/utils'); await fs.ensureDir(utilsDir); // Copy DOM utilities const domUtilsSource = path.join(__dirname, '../utils/dom.js'); const domUtilsTarget = path.join(utilsDir, 'dom.js'); if (await fs.pathExists(domUtilsSource)) { await fs.copy(domUtilsSource, domUtilsTarget); } // Copy Fetch utilities const fetchUtilsSource = path.join(__dirname, '../utils/fetch.js'); const fetchUtilsTarget = path.join(utilsDir, 'fetch.js'); if (await fs.pathExists(fetchUtilsSource)) { await fs.copy(fetchUtilsSource, fetchUtilsTarget); } // Copy Cordova utilities const cordovaUtilsSource = path.join(__dirname, '../utils/cordova.js'); const cordovaUtilsTarget = path.join(utilsDir, 'cordova.js'); if (await fs.pathExists(cordovaUtilsSource)) { await fs.copy(cordovaUtilsSource, cordovaUtilsTarget); } // Copy core framework const coreDir = path.join(projectPath, 'src/core'); await fs.ensureDir(coreDir); const coreSource = path.join(__dirname, '../core/muspe.js'); const coreTarget = path.join(coreDir, 'muspe.js'); if (await fs.pathExists(coreSource)) { await fs.copy(coreSource, coreTarget); } } async function copyCordovaFiles(projectPath) { // Copy Cordova demo component const componentDir = path.join(projectPath, 'src/components'); const componentSource = path.join(__dirname, '../components/CordovaDemo.js'); const componentTarget = path.join(componentDir, 'CordovaDemo.js'); if (await fs.pathExists(componentSource)) { await fs.copy(componentSource, componentTarget); } // Copy Cordova service const serviceDir = path.join(projectPath, 'src/services'); await fs.ensureDir(serviceDir); const serviceSource = path.join(__dirname, '../services/CordovaService.js'); const serviceTarget = path.join(serviceDir, 'CordovaService.js'); if (await fs.pathExists(serviceSource)) { await fs.copy(serviceSource, serviceTarget); } } function generateHTMLTemplate(projectName, template, framework) { const isFramework7Like = template === 'mobile' || template === 'hybrid'; return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0${isFramework7Like ? ', user-scalable=no' : ''}"> <meta name="description" content="${projectName} - Built with MusPE"> <title>${projectName}</title> <!-- Material Symbols Icons --> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" /> <!-- Material.io Components --> <script type="importmap"> { "imports": { "@material/web/": "https://esm.run/@material/web/" } } </script> <!-- CSS will be imported via JavaScript modules --> ${(template === 'pwa' || template === 'hybrid') ? '<link rel="manifest" href="./manifest.json">' : ''} <!-- Mobile optimizations --> <meta name="theme-color" content="#3b82f6"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="default"> <!-- Prevent zoom on input focus (mobile) --> ${isFramework7Like ? '<meta name="format-detection" content="telephone=no">' : ''} </head> <body> <div id="app"> <!-- App Header --> <header class="app-header"> <h1>Welcome to ${projectName}</h1> <p>Built with MusPE Framework</p> </header> <!-- Main Content --> <main class="app-main"> <div class="container"> <div class="welcome-card"> <h2>šŸš€ Your ${template} app is ready!</h2> <p>Start building amazing ${template === 'mobile' ? 'mobile experiences' : template === 'pwa' ? 'progressive web apps' : 'web applications'}.</p> <div class="features"> <div class="feature"> <span class="icon">šŸ“±</span> <span>Mobile-First</span> </div> <div class="feature"> <span class="icon">⚔</span> <span>Fast & Lightweight</span> </div> <div class="feature"> <span class="icon">šŸŽØ</span> <span>${framework === 'material' ? 'Material Design 3' : framework === 'tailwind' ? 'Tailwind CSS' : framework === 'bootstrap' ? 'Bootstrap' : 'Custom CSS'}</span> </div> <div class="feature"> <span class="icon">🧰</span> <span>DOM & Fetch Utils</span> </div> </div> <button class="cta-button" onclick="showInfo()">Get Started</button> <button class="demo-button" onclick="demoFeatures()">Try Features</button> </div> </div> </main> </div> <!-- Load MusPE Core and Utilities --> <script src="./src/utils/dom.js"></script> <script src="./src/utils/fetch.js"></script> <script src="./src/core/muspe.js"></script> <!-- Load Layout System --> <script src="./src/layouts/index.js"></script> <!-- Load Template System --> <script src="./src/templates/index.js"></script> <!-- Load Main App --> <script src="./src/scripts/main.js"></script> ${framework === 'bootstrap' ? '<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>' : ''} </body> </html>`; } function generateCSSTemplate(framework) { if (framework === 'material') { return `/* Material Design 3 CSS Framework */ /* Import Material Symbols font */ @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200'); @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap'); /* Material Design 3 Tokens */ :root { /* Primary colors */ --md-sys-color-primary: #6750A4; --md-sys-color-on-primary: #FFFFFF; --md-sys-color-primary-container: #EADDFF; --md-sys-color-on-primary-container: #21005D; /* Surface colors */ --md-sys-color-surface: #FFFBFE; --md-sys-color-on-surface: #1C1B1F; --md-sys-color-surface-variant: #E7E0EC; --md-sys-color-on-surface-variant: #49454F; /* Background */ --md-sys-color-background: #FFFBFE; --md-sys-color-on-background: #1C1B1F; /* Typography */ --md-sys-typescale-display-large-font: 'Roboto'; --md-sys-typescale-display-large-size: 57px; --md-sys-typescale-display-large-weight: 400; --md-sys-typescale-headline-large-font: 'Roboto'; --md-sys-typescale-headline-large-size: 32px; --md-sys-typescale-headline-large-weight: 400; --md-sys-typescale-body-large-font: 'Roboto'; --md-sys-typescale-body-large-size: 16px; --md-sys-typescale-body-large-weight: 400; } /* Base styles */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--md-sys-typescale-body-large-font), sans-serif; font-size: var(--md-sys-typescale-body-large-size); line-height: 1.5; color: var(--md-sys-color-on-background); background-color: var(--md-sys-color-background); } /* App Structure with Material Design */ .app-header { background-color: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); padding: 24px; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .app-header h1 { font-size: var(--md-sys-typescale-headline-large-size); font-weight: var(--md-sys-typescale-headline-large-weight); margin-bottom: 8px; } .app-main { min-height: 100vh; background-color: var(--md-sys-color-background); padding: 24px 0; } .container { max-width: 400px; margin: 0 auto; padding: 0 16px; } .welcome-card { background-color: var(--md-sys-color-surface); border-radius: 12px; padding: 24px; text-align: center; box-shadow: 0 1px 3px rgba(0,0,0,0.12); margin-bottom: 16px; } .features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 24px 0; } .feature { display: flex; flex-direction: column; align-items: center; gap: 8px; } .icon { font-size: 24px; } /* Material Design 3 style buttons */ .cta-button, .demo-button { font-family: var(--md-sys-typescale-body-large-font); font-size: 14px; font-weight: 500; padding: 10px 24px; border: none; border-radius: 20px; cursor: pointer; transition: all 0.2s ease; margin: 4px; } .cta-button { background-color: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); } .cta-button:hover { box-shadow: 0 2px 8px rgba(103, 80, 164, 0.3); } .demo-button { background-color: var(--md-sys-color-surface-variant); color: var(--md-sys-color-on-surface-variant); } .demo-button:hover { background-color: var(--md-sys-color-on-surface-variant); color: var(--md-sys-color-surface-variant); }`; } else if (framework === 'tailwind') { return `@tailwind base; @tailwind components; @tailwind utilities; /* Custom components */ @layer components { .app-header { @apply bg-primary-500 text-white p-6 text-center; } .app-main { @apply min-h-screen bg-gray-50 py-8; } .container { @apply max-w-md mx-auto px-4; } .welcome-card { @apply bg-white rounded-xl shadow-lg p-6 text-center; } .features { @apply grid grid-cols-3 gap-4 my-6; } .feature { @apply flex flex-col items-center space-y-2; } .icon { @apply text-2xl; } .cta-button { @apply bg-primary-500 hover:bg-primary-600 text-white font-bold py-3 px-6 rounded-lg transition-colors mr-2; } .demo-button { @apply bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition-colors; } }`; } return `/* MusPE Framework - Mobile-First CSS */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; background-color: #f8f9fa; } /* App Structure */ .app-header { background: linear-gradient(135deg, #3b82f6, #2563eb); color: white; padding: 2rem; text-align: center; } .app-header h1 { font-size: 1.8rem; margin-bottom: 0.5rem; } .app-main { min-height: 100vh; padding: 2rem 1rem; } .container { max-width: 400px; margin: 0 auto; } /* Welcome Card */ .welcome-card { background: white; border-radius: 1rem; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 2rem; text-align: center; } .welcome-card h2 { color: #1f2937; margin-bottom: 1rem; } .welcome-card p { color: #6b7280; margin-bottom: 2rem; } /* Features */ .features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin: 2rem 0; } .feature { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; } .icon { font-size: 1.5rem; } /* Button */ .cta-button { background: #3b82f6; color: white; border: none; padding: 0.75rem 1.5rem; border-radius: 0.5rem; font-weight: 600; cursor: pointer; transition: background-color 0.2s; margin-right: 0.5rem; } .cta-button:hover { background: #2563eb; } .demo-button { background: #6b7280; color: white; border: none; padding: 0.75rem 1.5rem; border-radius: 0.5rem; font-weight: 600; cursor: pointer; transition: background-color 0.2s; } .demo-button:hover { background: #4b5563; } /* Mobile Optimizations */ @media (max-width: 480px) { .app-header { padding: 1.5rem; } .app-header h1 { font-size: 1.5rem; } .container { padding: 0 1rem; } .welcome-card { padding: 1.5rem; } .features { gap: 0.75rem; } } /* Touch-friendly interactions */ @media (hover: none) { .cta-button:hover { background: #3b82f6; } .cta-button:active { background: #1d4ed8; transform: scale(0.98); } } /* Material Symbols Icons Utility Classes */ .material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; user-select: none; vertical-align: middle; } /* Icon size variations */ .icon-xs { font-size: 16px; } .icon-sm { font-size: 20px; } .icon-md { font-size: 24px; } .icon-lg { font-size: 32px; } .icon-xl { font-size: 48px; } /* Icon color variations */ .icon-primary { color: #3b82f6; } .icon-secondary { color: #6b7280; } .icon-success { color: #10b981; } .icon-warning { color: #f59e0b; } .icon-error { color: #ef4444; } /* Basic Swiper Customizations */ .swiper { width: 100%; height: 100%; } .swiper-slide { display: flex; justify-content: center; align-items: center; background: #f8fafc; border-radius: 0.5rem; } .swiper-button-next, .swiper-button-prev { color: #3b82f6; } .swiper-pagination-bullet { background: #d1d5db; } .swiper-pagination-bullet-active { background: #3b82f6; } /* Material.io Components Integration */ md-filled-button, md-outlined-button, md-text-button { --md-sys-color-primary: #3b82f6; --md-sys-color-on-primary: #ffffff; --md-sys-color-surface-variant: #f1f5f9; } md-card { --md-sys-color-surface-container-highest: #ffffff; --md-sys-color-outline: #e2e8f0; margin: 1rem 0; } md-top-app-bar { --md-sys-color-surface-container: #3b82f6; --md-sys-color-on-surface: #ffffff; } md-navigation-drawer { --md-sys-color-surface-container-low: #f8fafc; } md-fab { --md-sys-color-primary-container: #3b82f6; --md-sys-color-on-primary-container: #ffffff; } md-dialog { --md-sys-color-surface-container-highest: #ffffff; } md-list { --md-sys-color-surface: #ffffff; } md-list-item { --md-sys-color-on-surface: #1e293b; --md-sys-color-surface-variant: #f1f5f9; } md-text-field, md-outlined-text-field { --md-sys-color-primary: #3b82f6; --md-sys-color-outline: #cbd5e1; margin: 0.5rem 0; width: 100%; } md-checkbox, md-radio { --md-sys-color-primary: #3b82f6; } md-switch { --md-sys-color-primary: #3b82f6; --md-sys-color-outline: #cbd5e1; } md-chip-set { margin: 0.5rem 0; } md-assist-chip, md-filter-chip, md-input-chip, md-suggestion-chip { --md-sys-color-primary: #3b82f6; --md-sys-color-surface-variant: #f1f5f9; } md-linear-progress, md-circular-progress { --md-sys-color-primary: #3b82f6; } md-slider { --md-sys-color-primary: #3b82f6; width: 100%; margin: 1rem 0; } md-tabs { --md-sys-color-primary: #3b82f6; --md-sys-color-surface: #ffffff; } md-primary-tab { --md-sys-color-primary: #3b82f6; } /* Material.io Layout Helpers */ .material-layout { display: flex; flex-direction: column; min-height: 100vh; } .material-header { position: sticky; top: 0; z-index: 100; } .material-main { flex: 1; display: flex; } .material-sidebar { width: 280px; border-right: 1px solid #e2e8f0; } .material-content { flex: 1; padding: 1rem; max-width: 100%; overflow-x: auto; } .material-footer { background: #f8fafc; padding: 1rem; text-align: center; border-top: 1px solid #e2e8f0; } /* Material.io responsive grid */ .material-grid { display: grid; gap: 1rem; padding: 1rem; } .material-grid-2 { grid-template-columns: repeat(2, 1fr); } .material-grid-3 { grid-template-columns: repeat(3, 1fr); } .material-grid-4 { grid-template-columns: repeat(4, 1fr); } @media (max-width: 768px) { .material-grid-2, .material-grid-3, .material-grid-4 { grid-template-columns: 1fr; } .material-sidebar { width: 100%; border-right: none; border-bottom: 1px solid #e2e8f0; } .material-main { flex-direction: column; } } /* Hero slider specific styles */ .hero-slider { height: 300px; margin: 2rem 0; border-radius: 1rem; overflow: hidden; } .hero-slider .swiper-slide { background: linear-gradient(45deg, #3b82f6, #10b981); color: white; text-align: center; padding: 2rem; } /* Card slider styles */ .card-slider { padding: 1rem 0; } .card-slider .swiper-slide { background: white; border-radius: 0.75rem; padding: 1.5rem; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); margin: 0.5rem; height: auto; }`; } function generateJSTemplate(template, framework) { const materialImports = framework === 'material' ? ` // Import Material Design 3 Components import '@material/web/button/filled-button.js'; import '@material/web/button/outlined-button.js'; import '@material/web/button/text-button.js'; import '@material/web/card/card.js'; import '@material/web/textfield/filled-text-field.js'; import '@material/web/textfield/outlined-text-field.js'; import '@material/web/fab/fab.js'; import '@material/web/checkbox/checkbox.js'; import '@material/web/radio/radio.js'; import '@material/web/switch/switch.js'; import '@material/web/chips/chip-set.js'; import '@material/web/chips/assist-chip.js'; import '@material/web/progress/linear-progress.js'; import '@material/web/progress/circular-progress.js'; import '@material/web/dialog/dialog.js'; import '@material/web/list/list.js'; import '@material/web/list/list-item.js'; // Material Design 3 Theme Configuration import { argbFromHex, themeFromSourceColor, applyTheme } from '@material/material-color-utilities'; // Apply Material Design 3 Theme function initMaterialTheme() { // Get theme from source color const theme = themeFromSourceColor(argbFromHex('#6750A4')); // Apply the theme to the body by updating custom properties applyTheme(theme, {target: document.body, dark: false}); } // Initialize theme on load document.addEventListener('DOMContentLoaded', initMaterialTheme);` : ` // Import basic Material.io Components for layout system import '@material/web/button/filled-button.js'; import '@material/web/button/outlined-button.js'; import '@material/web/card/card.js'; import '@material/web/fab/fab.js';`; return `// MusPE Framework - Main Application Script with CSS imports and Swiper.js // Import CSS files through JavaScript (works with bundlers like Vite) import './styles/main.css'; ${framework === 'tailwind' ? "import './styles/tailwind.css';" : ''} ${framework === 'bootstrap' ? "import 'bootstrap/dist/css/bootstrap.min.css';" : ''} // Import Swiper CSS and JS import 'swiper/css'; import 'swiper/css/navigation'; import 'swiper/css/pagination'; import 'swiper/css/scrollbar'; import { Swiper, Navigation, Pagination, Scrollbar, Autoplay } from 'swiper'; ${materialImports} // Configure Swiper with desired modules Swiper.use([Navigation, Pagination, Scrollbar, Autoplay]); // Make Swiper globally available window.Swiper = Swiper; // Global Swiper utility functions window.createSwiper = function(container, options = {}) { const defaultOptions = { modules: [Navigation, Pagination], slidesPerView: 1, spaceBetween: 20, navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, pagination: { el: '.swiper-pagination', clickable: true, }, ...options }; return new Swiper(container, defaultOptions); }; // Example Swiper initialization function initializeSliders() { // Hero slider example const heroSlider = document.querySelector('.hero-slider'); if (heroSlider) { createSwiper(heroSlider, { modules: [Navigation, Pagination, Autoplay], autoplay: { delay: 5000, disableOnInteraction: false, }, loop: true }); } // Card slider example const cardSlider = document.querySelector('.card-slider'); if (cardSlider) { createSwiper(cardSlider, { slidesPerView: 1, spaceBetween: 20, breakpoints: { 640: { slidesPerView: 2 }, 768: { slidesPerView: 3 }, 1024: { slidesPerView: 4 } } }); } } // Global functions demonstrating MusPE utilities function showInfo() { // Create modal using Material Icons const modal = MusPE.dom.create('div', { class: 'modal-overlay', style: { position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(0, 0, 0, 0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1000' }, events: { click: (e) => { if (e.target === modal) { MusPE.dom.fadeOut(modal, 200).then(() => MusPE.dom.remove(modal)); } } } }); const content = MusPE.dom.create('div', { class: 'modal-content', style: { background: 'white', borderRadius: '1rem', padding: '2rem', maxWidth: '500px', margin: '1rem' }, html: \` <div style="display: flex; align-items: center; margin-bottom: 1rem;"> <span class="material-symbols-outlined" style="margin-right: 0.5rem; color: #3b82f6; font-size: 2rem;">rocket_launch</span> <h3 style="margin: 0;">Welcome to MusPE!</h3> </div> <p><strong>Your app includes:</strong></p> <ul style="margin: 1rem 0;"> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">palette</span> CSS imports via JavaScript</li> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">view_carousel</span> Swiper.js for slide components</li> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">widgets</span> Material.io web components</li> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">grid_view</span> Advanced layout system</li> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">description</span> Dynamic template engine</li> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">apps</span> Material Symbols icons</li> <li><span class="material-symbols-outlined" style="font-size: 1rem; vertical-align: middle;">code</span> Modern development setup</li> </ul> <p><strong>Quick Examples:</strong></p> <div style="margin: 1rem 0;"> <md-filled-button onclick="demoTemplates()"> <span slot="icon" class="material-symbols-outlined">auto_awesome</span> Try Templates </md-filled-button> <md-outlined-button onclick="demoLayouts()" style="margin-left: 0.5rem;"> <span slot="icon" class="material-symbols-outlined">dashboard</span> Try Layouts </md-outlined-button> </div> <p><strong>Next steps:</strong></p> <ul style="margin: 1rem 0;"> <li>Edit <code>src/layouts</code> for page layouts</li> <li>Use <code>src/templates</code> for reusable UI patterns</li> <li>Create Material.io components with <code>&lt;md-*&gt;</code> tags</li> <li>Use <code>Templates.render()</code> for dynamic content</li> <li>Run <code>muspe build</code> when ready to deploy</li> </ul> <md-filled-button onclick="MusPE.dom.fadeOut(this.closest('.modal-overlay'), 200).then(() => MusPE.dom.remove(this.closest('.modal-overlay')))" style="display: flex; align-items: center; gap: 0.5rem; margin-top: 1rem;"> <span slot="icon" class="material-symbols-outlined">check</span> Got it! </md-filled-button> \` }); MusPE.dom.append(modal, content); MusPE.dom.append('body', modal); MusPE.dom.fadeIn(modal, 200); } async function demoFeatures() { try { const demoContainer = MusPE.$('.welcome-card'); // Demo Swiper creation const swiperDemo = MusPE.dom.create('div', { class: 'swiper-demo', style: { background: '#f0f9ff', border: '2px solid #3b82f6', borderRadius: '0.5rem', padding: '1rem', margin: '1rem 0' }, html: \` <div style="display: flex; align-items: center; margin-bottom: 1rem;"> <span class="material-symbols-outlined" style="margin-right: 0.5rem; color: #3b82f6;">view_carousel</span> <strong>Swiper Demo</strong> </div> <div class="swiper demo-swiper" style="height: 200px;"> <div class="swiper-wrapper"> <div class="swiper-slide" style="background: linear-gradient(45deg, #3b82f6, #10b981); color: white; display: flex; align-items: center; justify-content: center; border-radius: 0.5rem;"> <div style="text-align: center;"> <span class="material-symbols-outlined" style="font-size: 3rem; margin-bottom: 0.5rem;">star</span> <h3>Slide 1</h3> <p>Beautiful slide components</p> </div> </div> <div class="swiper-slide" style="background: linear-gradient(45deg, #f59e0b, #ef4444); color: white; display: flex; align-items: center; justify-content: center; border-radius: 0.5rem;"> <div style="text-align: center;"> <span class="material-symbols-outlined" style="font-size: 3rem; margin-bottom: 0.5rem;">speed</span> <h3>Slide 2</h3> <p>High performance</p> </div> </div> <div class="swiper-slide" style="background: linear-gradient(45deg, #8b5cf6, #ec4899); color: white; display: flex; align-items: center; justify-content: center; border-radius: 0.5rem;"> <div style="text-align: center;"> <span class="material-symbols-outlined" style="font-size: 3rem; margin-bottom: 0.5rem;">devices</span> <h3>Slide 3</h3> <p>Responsive design</p> </div> </div> </div> <div class="swiper-pagination"></div> <div class="swiper-button-next"></div> <div class="swiper-button-prev"></div> </div> \` }); MusPE.dom.append(demoContainer, swiperDemo); await MusPE.dom.fadeIn(swiperDemo, 300); // Initialize the demo swiper setTimeout(() => { createSwiper('.demo-swiper', { modules: [Navigation, Pagination, Autoplay], autoplay: { delay: 3000, disableOnInteraction: false, }, loop: true }); }, 100); // Clean up after 10 seconds setTimeout(() => { MusPE.dom.fadeOut(swiperDemo, 300).then(() => MusPE.dom.remove(swiperDemo)); }, 10000); } catch (error) { console.error('Demo error:', error); } } class MusPEApp { constructor() { this.init(); } init() { console.log('šŸš€ MusPE App initialized with Material.io and advanced template system'); console.log('šŸ“¦ Available features:', { dom: 'MusPE.dom or MusPE.$', http: 'MusPE.http or MusPE.fetch', swiper: 'createSwiper() or new Swiper()', material: 'Material.io web components', layouts: 'BaseLayout, MaterialLayout, MobileLayout, DashboardLayout', templates: 'Templates.render() and common templates', icons: 'Material Symbols (material-symbols-outlined)', css: 'Imported via JavaScript modules' }); this.setupEventListeners(); this.detectDevice(); this.initializeSliders(); this.setupLayoutSystem(); this.demoTemplateSystem(); ${template === 'pwa' || template === 'hybrid' ? 'this.registerServiceWorker();' : ''} } setupEventListeners() { MusPE.ready(() => { console.log('šŸ“± DOM Content Loaded'); // Initialize any existing sliders this.initializeSliders(); // Demo event delegation with Material Icons MusPE.dom.on(document, 'click', '.feature', (e) => { const feature = e.target.closest('.feature'); MusPE.dom.addClass(feature, 'clicked'); setTimeout(() => MusPE.dom.removeClass(feature, 'clicked'), 200); }); }); // Handle touch events for mobile if ('ontouchstart' in window) { this.setupTouchEvents(); } } initializeSliders() { // Initialize any Swiper sliders found in the page initializeSliders(); } setupTouchEvents() { // Prevent double-tap zoom let lastTouchEnd = 0; document.addEventListener('touchend', (event) => { const now = (new Date()).getTime(); if (now - lastTouchEnd <= 300) { event.preventDefault(); } lastTouchEnd = now; }, false); } detectDevice() { const device = MusPE.env; console.log(\`šŸ“± Device Info:\`, { mobile: device.isMobile, tablet: device.isTablet, touch: device.hasTouch, online: device.isOnline, pwa: device.isPWA }); } setupLayoutSystem() { // Demo layout setup console.log('šŸ—ļø Setting up layout system...'); // You can uncomment and modify these to use different layouts: // const layout = LayoutFactory.create('material', { // title: 'My App', // hasSidebar: false, // fabAction: { // icon: 'add', // label: 'Add Item', // handler: () => alert('FAB clicked!') // } // }); // layout.applyTo('#app', document.querySelector('#app').innerHTML); } demoTemplateSystem() { // Demo template usage console.log('šŸ“„ Template system ready'); // Example: Add a stats widget after 3 seconds setTimeout(() => { const statsHtml = Templates.statsWidget({ title: 'App Users', value: '1,234', icon: 'people', color: 'primary', change: '+5.2%', changeType: 'positive', subtitle: 'Active users this month' }); // Uncomment to add to page: // const container = document.querySelector('.welcome-card'); // if (container) { // container.insertAdjacentHTML('afterend', statsHtml); // } }, 3000); } ${template === 'pwa' || template === 'hybrid' ? ` async registerServiceWorker() { if ('serviceWorker' in navigator) { try { const registration = await navigator.serviceWorker.register('./sw.js'); console.log('šŸ”§ ServiceWorker registered:', registration); } catch (error) { console.log('āŒ ServiceWorker registration failed:', error); } } }` : ''} } // Initialize app when MusPE is ready MusPE.ready(() => { const app = new MusPEApp(); // Example of using MusPE features MusPE.on('app:background', () => console.log('šŸ“± App went to background')); MusPE.on('app:foreground', () => console.log('šŸ“± App came to foreground')); MusPE.on('online', () => console.log('🌐 App is online')); MusPE.on('offline', () => console.log('šŸ“” App is offline')); }); // Export for module usage if (typeof module !== 'undefined' && module.exports) { module.exports = MusPEApp; } // Demo Templates Function window.demoTemplates = function() { const container = document.querySelector('.welcome-card'); if (!container) return; // Demo various templates const templates = [ { name: 'User Profile', html: Templates.userProfile({ name: 'Sarah Wilson', email: 'sarah@example.com', role: 'Designer', id: '123' }) }, { name: 'Stats Widget', html: Templates.statsWidget({ title: 'Active Users', value: '2,451', icon: 'people', color: 'success', change: '+12%', changeType: 'positive' }) }, { name: 'Alert Message', html: Templates.alert({ type: 'success', title: 'Success!', message: 'Template system is working perfectly.', dismissible: true }) } ]; templates.forEach((template, index) => { setTimeout(() => { const demo = MusPE.dom.create('div', { style: { margin: '1rem 0', opacity: '0' }, html: \` <h4 style="color: #3b82f6; margin: 0.5rem 0;">šŸ“„ \${template.name} Template</h4> \${template.html} \` }); container.insertAdjacentElement('afterend', demo); MusPE.dom.fadeIn(demo, 300); // Clean up after 8 seconds setTimeout(() => { MusPE.dom.fadeOut(demo, 300).then(() => MusPE.dom.remove(demo)); }, 8000); }, index * 1000); }); }; // Demo Layouts Function window.demoLayouts = function() { const originalContent = document.querySelector('#app').innerHTML; // Demo Material Layout const materialLayout = LayoutFactory.create('material', { title: 'Material Layout Demo', hasSidebar: true, fabAction: { icon: 'refresh', label: 'Restore', handler: () => { document.querySelector('#app').innerHTML = originalContent; // Re-initialize the app setTimeout(() => { const app = new MusPEApp(); }, 100); } } }); const demoContent = \` <div style="padding: 2rem;"> <h2>šŸ—ļø Material Layout Demo</h2> <p>This demonstrates the Material Design layout with sidebar and FAB.</p> <div class="material-grid material-grid-2" style="margin: 2rem 0;"> \${Templates.statsWidget({ title: 'Dashboard Views', value: '1,234', icon: 'visibility', color: 'primary' })} \${Templates.statsWidget({ title: 'Active Users', value: '567', icon: 'people', color: 'success' })} </div> \${Templates.alert({ type: 'info', title: 'Layout Demo', message: 'Click the refresh FAB (bottom-right) to return to the original layout.', dismissible: false })} <div style="margin-top: 2rem;"> <md-outlined-button onclick="document.querySelector('#app').innerHTML = \`\${originalContent.replace(/'/g, '\\\\\'')}\`; setTimeout(() => new MusPEApp(), 100);"> <span slot="icon" class="material-symbols-outlined">arrow_back</span> Back to Original </md-outlined-button> </div> </div> \`; materialLayout.applyTo('#app', demoContent); };`; } function generateComponentTemplate(framework) { return `// MusPE Component - AppHeader class AppHeader { constructor(options = {}) { this.title = options.title || 'MusPE App'; this.subtitle = options.subtitle || 'Mobile-First Framework'; this.element = null; } render() { this.element = document.createElement('header'); this.element.className = 'app-header'; this.element.innerHTML = \` <h1>\${this.title}</h1> <p>\${this.subtitle}</p> \`; return this.element; } update(title, subtitle) { if (this.element) { this.title = title; this.subtitle = subtitle; this.element.querySelector('h1').textContent = title; this.element.querySelector('p').textContent = subtitle; } } destroy() { if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } } } // Export for module usage if (typeof module !== 'undefined' && module.exports) { module.exports = AppHeader; }`; } async function generatePWAFiles(projectPath, projectName) { // Generate manifest.json const manifest = { name: projectName, short_name: projectName, description: `${projectName} - Built with MusPE`, start_url: '/', display: 'standalone', background_color: '#ffffff', theme_color: '#3b82f6', icons: [ { src: './assets/icons/icon-192x192.png', sizes: '192x192', type: 'image/png' }, { src: './assets/icons/icon-512x512.png', sizes: '512x512', type: 'image/png' } ] }; await fs.writeJSON(path.join(projectPath, 'public/manifest.json'), manifest, { spaces: 2 }); // Generate service worker const serviceWorker = `// MusPE Service Worker const CACHE_NAME = '${projectName}-v1'; const urlsToCache = [ '