a reactive (signals based) hypermedia web framework (wip) stormlightlabs.github.io/volt/
hypermedia frontend signals
at main 4.8 kB view raw
1import { 2 generateMinimalCSS, 3 generateMinimalHTML, 4 generateMinimalPackageJSON, 5 generateMinimalREADME, 6} from "$templates/minimal.js"; 7import { 8 generateStylesCSS, 9 generateStylesHTML, 10 generateStylesPackageJSON, 11 generateStylesREADME, 12} from "$templates/styles.js"; 13import { 14 generatePluginsCSS, 15 generatePluginsHTML, 16 generatePluginsPackageJSON, 17 generatePluginsREADME, 18} from "$templates/with-plugins.js"; 19import { 20 generateRouterCSS, 21 generateRouterHTML, 22 generateRouterPackageJSON, 23 generateRouterREADME, 24} from "$templates/with-router.js"; 25import { downloadFile, getCDNUrls } from "$utils/download.js"; 26import { echo } from "$utils/echo.js"; 27import { createFile, isEmptyOrMissing } from "$utils/files.js"; 28import { input, select } from "@inquirer/prompts"; 29import path from "node:path"; 30 31type Template = "minimal" | "with-router" | "with-plugins" | "styles"; 32 33/** 34 * Download VoltX.js assets to the project directory. 35 */ 36async function downloadAssets(projectDir: string, template: Template): Promise<void> { 37 const urls = getCDNUrls(); 38 39 echo.info("Downloading VoltX.js assets..."); 40 41 const cssPath = path.join(projectDir, "voltx.min.css"); 42 await downloadFile(urls.css, cssPath); 43 echo.ok(` Downloaded: voltx.min.css`); 44 45 if (template !== "styles") { 46 const jsPath = path.join(projectDir, "voltx.min.js"); 47 await downloadFile(urls.js, jsPath); 48 echo.ok(` Downloaded: voltx.min.js`); 49 } 50} 51 52/** 53 * Generate project files based on the selected template. 54 */ 55async function generateProjectFiles(projectDir: string, projectName: string, template: Template): Promise<void> { 56 echo.info("Generating project files..."); 57 58 let htmlContent: string; 59 let cssContent: string; 60 let packageJsonContent: string; 61 let readmeContent: string; 62 63 switch (template) { 64 case "minimal": 65 htmlContent = generateMinimalHTML(projectName); 66 cssContent = generateMinimalCSS(); 67 packageJsonContent = generateMinimalPackageJSON(projectName); 68 readmeContent = generateMinimalREADME(projectName); 69 break; 70 71 case "styles": 72 htmlContent = generateStylesHTML(projectName); 73 cssContent = generateStylesCSS(); 74 packageJsonContent = generateStylesPackageJSON(projectName); 75 readmeContent = generateStylesREADME(projectName); 76 break; 77 78 case "with-router": 79 htmlContent = generateRouterHTML(projectName); 80 cssContent = generateRouterCSS(); 81 packageJsonContent = generateRouterPackageJSON(projectName); 82 readmeContent = generateRouterREADME(projectName); 83 break; 84 85 case "with-plugins": 86 htmlContent = generatePluginsHTML(projectName); 87 cssContent = generatePluginsCSS(); 88 packageJsonContent = generatePluginsPackageJSON(projectName); 89 readmeContent = generatePluginsREADME(projectName); 90 break; 91 } 92 93 await createFile(path.join(projectDir, "index.html"), htmlContent); 94 echo.ok(` Created: index.html`); 95 96 await createFile(path.join(projectDir, "styles.css"), cssContent); 97 echo.ok(` Created: styles.css`); 98 99 await createFile(path.join(projectDir, "package.json"), packageJsonContent); 100 echo.ok(` Created: package.json`); 101 102 await createFile(path.join(projectDir, "README.md"), readmeContent); 103 echo.ok(` Created: README.md`); 104} 105 106/** 107 * Init command implementation. 108 * 109 * Creates a new VoltX.js project with the selected template. 110 */ 111export async function initCommand(projectName?: string): Promise<void> { 112 echo.title("\n⚡ Create VoltX.js App\n"); 113 114 if (!projectName) { 115 projectName = await input({ message: "Project name:", default: "my-voltx-app" }); 116 117 if (!projectName) { 118 echo.err("Project name is required"); 119 process.exit(1); 120 } 121 } 122 123 const projectDir = path.resolve(process.cwd(), projectName); 124 125 if (!(await isEmptyOrMissing(projectDir))) { 126 echo.err(`Directory ${projectName} already exists and is not empty`); 127 process.exit(1); 128 } 129 130 const template = await select<Template>({ 131 message: "Select a template:", 132 choices: [ 133 { name: "Minimal", value: "minimal", description: "Basic VoltX.js app with counter" }, 134 { name: "With Router", value: "with-router", description: "Multi-page app with routing" }, 135 { name: "With Plugins", value: "with-plugins", description: "All plugins demo" }, 136 { name: "Styles Only", value: "styles", description: "Just HTML + CSS, no framework" }, 137 ], 138 }); 139 140 try { 141 echo.text(""); 142 await generateProjectFiles(projectDir, projectName, template); 143 144 echo.text(""); 145 await downloadAssets(projectDir, template); 146 147 echo.success(`\n✓ Project created successfully!\n`); 148 echo.info(`Next steps:\n`); 149 echo.text(` cd ${projectName}`); 150 echo.text(` pnpm install`); 151 echo.text(` pnpm dev\n`); 152 } catch (error) { 153 echo.err("Failed to create project:", error); 154 process.exit(1); 155 } 156}