@hobui/viui-cli 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +155 -27
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -281,6 +281,87 @@ function addPostinstallScript(cwd, pm) {
281
281
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
282
282
  return true;
283
283
  }
284
+ const VIUI_THEME_IDS = ['minimalist-2', 'neo-brutalism', 'material'];
285
+ function setEnvTheme(cwd, themeId) {
286
+ const envPath = path.join(cwd, '.env');
287
+ const examplePath = path.join(cwd, '.env.example');
288
+ const line = `VITE_VIUI_THEME=${themeId}`;
289
+ const targets = [envPath, examplePath].filter((p) => fs.existsSync(p));
290
+ if (targets.length === 0) {
291
+ fs.writeFileSync(envPath, line + '\n', 'utf8');
292
+ console.log('Created .env with', line);
293
+ return;
294
+ }
295
+ for (const p of targets) {
296
+ let content = fs.readFileSync(p, 'utf8');
297
+ const re = /^\s*VITE_VIUI_THEME=.*/m;
298
+ if (re.test(content)) {
299
+ content = content.replace(re, line);
300
+ }
301
+ else {
302
+ content = content.trimEnd() + '\n' + line + '\n';
303
+ }
304
+ fs.writeFileSync(p, content, 'utf8');
305
+ console.log('Set', line, 'in', path.basename(p));
306
+ }
307
+ }
308
+ function ensureApplyThemeBodyInVuetify(cwd) {
309
+ const vuetifyPath = path.join(cwd, 'src', 'plugins', 'vuetify.ts');
310
+ if (!fs.existsSync(vuetifyPath))
311
+ return false;
312
+ const content = fs.readFileSync(vuetifyPath, 'utf8');
313
+ if (/apply-theme-body|applyThemeBody/.test(content))
314
+ return false;
315
+ const importLine = "import './viui-conf/apply-theme-body'";
316
+ const defaultsImportMatch = content.match(/import\s+.+\s+from\s+['"]\.\/viui-conf\/defaults[^'"]*['"]/);
317
+ const insert = defaultsImportMatch
318
+ ? content.replace(defaultsImportMatch[0], defaultsImportMatch[0] + '\n' + importLine)
319
+ : content.trimStart().replace(/^(\s*)/, `$1${importLine}\n$1`);
320
+ fs.writeFileSync(vuetifyPath, insert, 'utf8');
321
+ console.log('Added apply-theme-body import to src/plugins/vuetify.ts');
322
+ return true;
323
+ }
324
+ function showHelpDocs(cwd) {
325
+ console.log('\n--- Design system setup ---');
326
+ console.log('Design themes (viui-themes) are in: src/assets/styles/viui-themes/');
327
+ console.log('Available theme ids: minimalist-2 (default), neo-brutalism, material');
328
+ console.log('To use a theme: set VITE_VIUI_THEME in .env and add in vuetify.ts:');
329
+ console.log(" import './viui-conf/apply-theme-body'");
330
+ console.log('Details: src/plugins/viui-conf/defaults/README.md');
331
+ console.log('CLI docs: pnpm exec viui-cli --help');
332
+ console.log('---\n');
333
+ }
334
+ async function runConfigureTheme(cwd, rl, opts) {
335
+ console.log('\n Design theme (viui-themes)');
336
+ console.log(' Available: minimalist-2 (default), neo-brutalism, material\n');
337
+ console.log(' a) Use minimalist-2 (default) — thin borders, flat');
338
+ console.log(' b) Use neo-brutalism — thick borders, hard shadow');
339
+ console.log(' c) Use material — elevated, standard Material');
340
+ console.log(' d) Skip / configure manually — set .env yourself\n');
341
+ const a = await rl.question(' Choose (a-d, or Enter for a): ');
342
+ const choice = (a.trim().toLowerCase() || 'a')[0];
343
+ const map = {
344
+ a: 'minimalist-2',
345
+ b: 'neo-brutalism',
346
+ c: 'material',
347
+ d: 'skip',
348
+ };
349
+ const themeId = map[choice] ?? map.a;
350
+ if (themeId === 'skip') {
351
+ console.log(' Skipped. Set VITE_VIUI_THEME in .env and add import in vuetify.ts. See src/plugins/viui-conf/defaults/README.md');
352
+ return;
353
+ }
354
+ setEnvTheme(cwd, themeId);
355
+ const vuetifyPath = path.join(cwd, 'src', 'plugins', 'vuetify.ts');
356
+ const hasImport = fs.existsSync(vuetifyPath) && /apply-theme-body|applyThemeBody/.test(fs.readFileSync(vuetifyPath, 'utf8'));
357
+ if (!hasImport && fs.existsSync(vuetifyPath)) {
358
+ const ans = await rl.question(' Add apply-theme-body import to vuetify.ts? (Y/n): ');
359
+ const add = opts.yes || (ans.trim().toLowerCase() === '' || ans.trim().toLowerCase() === 'y' || ans.trim().toLowerCase() === 'yes');
360
+ if (add)
361
+ ensureApplyThemeBodyInVuetify(cwd);
362
+ }
363
+ console.log(' Theme configured:', themeId);
364
+ }
284
365
  async function runSetup(cwd, assetsDir, opts) {
285
366
  const isPostinstall = opts.postinstall === true;
286
367
  if (isPostinstall && !process.stdin.isTTY) {
@@ -294,50 +375,97 @@ async function runSetup(cwd, assetsDir, opts) {
294
375
  }
295
376
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
296
377
  const ask = async (q, defaultYes) => {
297
- const def = defaultYes ? 'Y/n' : 'y/N';
298
- const a = await rl.question(`${q} (${def}): `);
378
+ const a = await rl.question(`${q} (${defaultYes ? 'Y/n' : 'y/N'}): `);
299
379
  const s = a.trim().toLowerCase();
300
380
  if (s === '')
301
381
  return defaultYes;
302
382
  return s === 'y' || s === 'yes';
303
383
  };
304
384
  console.log(`\n${pkg.name ?? '@viui/cli'} — Setup i-design-system in this repo\n`);
385
+ console.log(' This will: sync .cursor, viui-conf, viui-themes; optional @viui/web, theme config, postinstall.\n');
305
386
  const runNow = opts.yes || (await ask('Run setup now?', true));
306
387
  if (!runNow) {
307
388
  console.log('Skipped. Run later: pnpm exec viui-cli setup');
308
389
  rl.close();
309
390
  return;
310
391
  }
392
+ const pm = detectPackageManager(cwd);
311
393
  const cursorDir = path.join(cwd, '.cursor');
312
- const hasCursor = fs.existsSync(cursorDir);
313
- if (!hasCursor) {
314
- console.log('Step 1: Initializing .cursor (rules, plans) and src/plugins/viui-conf...');
315
- runInit(cwd, assetsDir, { yes: true, dryRun: false, noPlans: false });
316
- }
317
- else {
318
- const doSync = opts.yes || (await ask('Step 1: .cursor exists. Sync from design system?', true));
319
- if (doSync) {
320
- runSync(cwd, assetsDir, { dryRun: false, backup: false });
394
+ for (;;) {
395
+ console.log('\n What do you want to do?\n');
396
+ console.log(' 1) Full setup (recommended) init/sync .cursor + viui-conf + viui-themes, install @viui/web, configure theme, add postinstall');
397
+ console.log(' 2) Sync only — update .cursor, viui-conf, viui-themes (no npm install)');
398
+ console.log(' 3) Install @viui/web only — add Vi* components dependency');
399
+ console.log(' 4) Configure design theme — set VITE_VIUI_THEME in .env and ensure body class is applied');
400
+ console.log(' 5) Add postinstall script — auto-sync on every pnpm install');
401
+ console.log(' 6) Show help / docs — print links and next steps\n');
402
+ const choiceInput = await rl.question(' Choose (1-6, or Enter for 1): ');
403
+ const choice = (choiceInput.trim() || '1').replace(/[^1-6]/, '1');
404
+ const n = parseInt(choice, 10);
405
+ if (n < 1 || n > 6)
406
+ continue;
407
+ if (n === 1) {
408
+ if (!fs.existsSync(cursorDir)) {
409
+ console.log('\nStep: Initializing .cursor, viui-conf, viui-themes...');
410
+ runInit(cwd, assetsDir, { yes: true, dryRun: false, noPlans: false });
411
+ }
412
+ else {
413
+ console.log('\nStep: Syncing .cursor, viui-conf, viui-themes...');
414
+ runSync(cwd, assetsDir, { dryRun: false, backup: false });
415
+ }
416
+ console.log('\nStep: Installing @viui/web...');
417
+ const { execSync } = await import('node:child_process');
418
+ const addCmd = pm === 'pnpm' ? 'pnpm add @viui/web' : pm === 'yarn' ? 'yarn add @viui/web' : 'npm install @viui/web';
419
+ execSync(addCmd, { cwd, stdio: 'inherit' });
420
+ await runConfigureTheme(cwd, rl, { yes: opts.yes });
421
+ if (!isPostinstall && (opts.yes || (await ask('\nAdd postinstall to auto-sync on install?', false)))) {
422
+ if (addPostinstallScript(cwd, pm))
423
+ console.log('Added postinstall script to package.json.');
424
+ }
425
+ console.log('\nDone. Use: import { ViButton, ViInput, ... } from \'@viui/web\'');
426
+ console.log('Design themes: src/assets/styles/viui-themes/ — set VITE_VIUI_THEME in .env; see src/plugins/viui-conf/defaults/README.md');
427
+ break;
321
428
  }
322
- }
323
- const pm = detectPackageManager(cwd);
324
- const doWeb = opts.yes || (await ask('Step 2: Install @viui/web for Vi* components?', true));
325
- if (doWeb) {
326
- const { execSync } = await import('node:child_process');
327
- const addCmd = pm === 'pnpm' ? 'pnpm add @viui/web' : pm === 'yarn' ? 'yarn add @viui/web' : 'npm install @viui/web';
328
- console.log(`Running: ${addCmd}`);
329
- execSync(addCmd, { cwd, stdio: 'inherit' });
330
- }
331
- const doPostinstall = !isPostinstall && (opts.yes || (await ask('Step 3: Add postinstall to auto-sync on install?', false)));
332
- if (doPostinstall) {
333
- if (addPostinstallScript(cwd, pm)) {
334
- console.log('Added postinstall script to package.json.');
429
+ if (n === 2) {
430
+ if (!fs.existsSync(cursorDir)) {
431
+ console.log('\nInitializing .cursor, viui-conf, viui-themes...');
432
+ runInit(cwd, assetsDir, { yes: true, dryRun: false, noPlans: false });
433
+ }
434
+ else {
435
+ console.log('\nSyncing .cursor, viui-conf, viui-themes...');
436
+ runSync(cwd, assetsDir, { dryRun: false, backup: false });
437
+ }
438
+ console.log('Sync done.');
439
+ break;
335
440
  }
336
- else {
337
- console.log('postinstall already contains viui-cli or package.json not found.');
441
+ if (n === 3) {
442
+ const { execSync } = await import('node:child_process');
443
+ const addCmd = pm === 'pnpm' ? 'pnpm add @viui/web' : pm === 'yarn' ? 'yarn add @viui/web' : 'npm install @viui/web';
444
+ console.log('\nRunning:', addCmd);
445
+ execSync(addCmd, { cwd, stdio: 'inherit' });
446
+ console.log('Done. Use: import { ViButton, ViInput, ... } from \'@viui/web\'');
447
+ break;
448
+ }
449
+ if (n === 4) {
450
+ await runConfigureTheme(cwd, rl, { yes: opts.yes });
451
+ break;
452
+ }
453
+ if (n === 5) {
454
+ if (addPostinstallScript(cwd, pm)) {
455
+ console.log('\nAdded postinstall script to package.json.');
456
+ }
457
+ else {
458
+ console.log('\npostinstall already contains viui-cli or package.json not found.');
459
+ }
460
+ break;
461
+ }
462
+ if (n === 6) {
463
+ showHelpDocs(cwd);
464
+ const again = opts.yes || (await ask('Show menu again?', true));
465
+ if (!again)
466
+ break;
338
467
  }
339
468
  }
340
- console.log('\nDone. Use: import { ViButton, ViInput, ... } from \'@viui/web\'');
341
469
  rl.close();
342
470
  }
343
471
  const result = parseArgs({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hobui/viui-cli",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "CLI to sync i-design-system .cursor (rules, skills, commands) into consumer repos",
5
5
  "type": "module",
6
6
  "files": [