windowpp 0.1.3 → 0.1.5

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.
package/bin/windowpp.js CHANGED
@@ -51,7 +51,10 @@ switch (command) {
51
51
  }
52
52
  const flags = parseFlags(args.slice(2));
53
53
  const { create } = require('../lib/create');
54
- create(name, { template: flags.template, outDir: flags.outDir });
54
+ create(name, { template: flags.template, outDir: flags.outDir }).catch((err) => {
55
+ console.error(err.message || err);
56
+ process.exit(1);
57
+ });
55
58
  break;
56
59
  }
57
60
 
package/lib/create.js CHANGED
@@ -5,8 +5,45 @@
5
5
 
6
6
  const path = require('path');
7
7
  const fs = require('fs');
8
+ const readline = require('readline');
8
9
  const { execSync } = require('child_process');
9
10
 
11
+ // ─── Interactive template picker ─────────────────────────────────────────────
12
+ function listTemplates(cliDir) {
13
+ const templatesDir = path.join(cliDir, 'templates');
14
+ if (!fs.existsSync(templatesDir)) return [];
15
+ return fs.readdirSync(templatesDir, { withFileTypes: true })
16
+ .filter(d => d.isDirectory())
17
+ .map(d => d.name)
18
+ .sort();
19
+ }
20
+
21
+ function promptTemplate(templates) {
22
+ return new Promise((resolve) => {
23
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
24
+
25
+ console.log('\nAvailable templates:');
26
+ templates.forEach((t, i) => console.log(` [${i + 1}] ${t}`));
27
+ console.log();
28
+
29
+ const ask = () => {
30
+ rl.question(`Pick a template [1-${templates.length}] (default: 1): `, (answer) => {
31
+ const trimmed = answer.trim();
32
+ if (trimmed === '') { rl.close(); resolve(templates[0]); return; }
33
+ const idx = parseInt(trimmed, 10) - 1;
34
+ if (idx >= 0 && idx < templates.length) {
35
+ rl.close();
36
+ resolve(templates[idx]);
37
+ } else {
38
+ console.log(` Please enter a number between 1 and ${templates.length}.`);
39
+ ask();
40
+ }
41
+ });
42
+ };
43
+ ask();
44
+ });
45
+ }
46
+
10
47
  const TEXT_EXTENSIONS = new Set([
11
48
  '.cpp', '.h', '.ts', '.tsx', '.js', '.json', '.html',
12
49
  '.css', '.md', '.txt', '.cmake', '.sh', '.env',
@@ -38,9 +75,8 @@ function copyDir(src, dest, tokens) {
38
75
  }
39
76
  }
40
77
 
41
- function create(name, options = {}) {
78
+ async function create(name, options = {}) {
42
79
  const {
43
- template = 'solid',
44
80
  outDir = process.cwd(),
45
81
  installDeps = true,
46
82
  } = options;
@@ -50,13 +86,29 @@ function create(name, options = {}) {
50
86
  process.exit(1);
51
87
  }
52
88
 
89
+ const cliDir = path.resolve(__dirname, '..');
90
+ const templates = listTemplates(cliDir);
91
+
92
+ // Resolve template — prompt if none given
93
+ let template = options.template;
94
+ if (!template) {
95
+ if (templates.length === 0) {
96
+ console.error('Error: no templates found in ' + path.join(cliDir, 'templates'));
97
+ process.exit(1);
98
+ }
99
+ if (templates.length === 1) {
100
+ template = templates[0];
101
+ } else {
102
+ template = await promptTemplate(templates);
103
+ }
104
+ }
105
+
53
106
  const appDir = path.join(outDir, name);
54
107
  if (fs.existsSync(appDir)) {
55
108
  console.error(`Error: directory "${appDir}" already exists.`);
56
109
  process.exit(1);
57
110
  }
58
111
 
59
- const cliDir = path.resolve(__dirname, '..');
60
112
  const templateDir = path.join(cliDir, 'templates', template);
61
113
  if (!fs.existsSync(templateDir)) {
62
114
  console.error(`Error: template "${template}" not found in ${path.join(cliDir, 'templates')}`);
@@ -73,9 +125,7 @@ function create(name, options = {}) {
73
125
  '{{APP_NAME}}': name,
74
126
  '{{APP_TITLE}}': appTitle,
75
127
  '{{CMAKE_TARGET}}': cmakeTarget,
76
- // Resolved at create-time so vite.config / API.ts can import from the
77
- // installed framework's src/ tree via the @wpp alias.
78
- '{{REPO_ROOT}}': path.join(cliDir, 'framework').replace(/\\/g, '/'),
128
+ '{{REPO_ROOT}}': path.join(cliDir, 'framework').replace(/\\/g, '/'),
79
129
  };
80
130
 
81
131
  console.log(`\n=== WindowPP Create --- ${name} (template: ${template}) ===\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windowpp",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "WindowPP CLI — build, dev, and scaffold for WindowPP apps",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>{{APP_TITLE}}</title>
7
+ <script>
8
+ window.addEventListener('dragover', function(e) { e.preventDefault(); }, false);
9
+ window.addEventListener('drop', function(e) { e.preventDefault(); }, false);
10
+ </script>
11
+ </head>
12
+ <body>
13
+ <div id="root"></div>
14
+ <script src="/src/index.tsx" type="module"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,8 @@
1
+ export default function App() {
2
+ return (
3
+ <div class="min-h-screen flex flex-col items-center justify-center bg-slate-100 text-slate-900 gap-4">
4
+ <h1 class="text-4xl font-bold">{{APP_TITLE}}</h1>
5
+ <p class="text-slate-500 text-sm">Edit <code class="bg-slate-200 px-1 rounded">frontend/src/App.tsx</code> to get started.</p>
6
+ </div>
7
+ );
8
+ }
@@ -0,0 +1 @@
1
+ @import 'tailwindcss';
@@ -0,0 +1,12 @@
1
+ /* @refresh reload */
2
+ import './index.css';
3
+ import { render } from 'solid-js/web';
4
+ import App from './App';
5
+
6
+ const root = document.getElementById('root');
7
+
8
+ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
9
+ throw new Error('Root element not found. Did you forget to add it to your index.html?');
10
+ }
11
+
12
+ render(() => <App />, root!);
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "preserve",
4
+ "jsxImportSource": "solid-js",
5
+ "target": "ESNext",
6
+ "allowSyntheticDefaultImports": true,
7
+ "esModuleInterop": true,
8
+ "isolatedModules": true,
9
+ "module": "ESNext",
10
+ "moduleResolution": "bundler",
11
+ "noEmit": true,
12
+ "strict": true,
13
+ "types": ["vite/client"]
14
+ }
15
+ }