create-asterui 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ import * as p from '@clack/prompts';
3
+ import { spawn } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import pc from 'picocolors';
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const DAISYUI_THEMES = [
10
+ 'light', 'dark', 'cupcake', 'bumblebee', 'emerald', 'corporate',
11
+ 'synthwave', 'retro', 'cyberpunk', 'valentine', 'halloween', 'garden',
12
+ 'forest', 'aqua', 'lofi', 'pastel', 'fantasy', 'wireframe', 'black',
13
+ 'luxury', 'dracula', 'cmyk', 'autumn', 'business', 'acid', 'lemonade',
14
+ 'night', 'coffee', 'winter', 'dim', 'nord', 'sunset'
15
+ ];
16
+ function detectPackageManager() {
17
+ const userAgent = process.env.npm_config_user_agent || '';
18
+ if (userAgent.includes('pnpm'))
19
+ return 'pnpm';
20
+ if (userAgent.includes('yarn'))
21
+ return 'yarn';
22
+ return 'npm';
23
+ }
24
+ function getInstallCommand(pm) {
25
+ return pm === 'yarn' ? 'yarn' : `${pm} install`;
26
+ }
27
+ function getRunCommand(pm) {
28
+ return pm === 'npm' ? 'npm run' : pm;
29
+ }
30
+ async function main() {
31
+ console.log();
32
+ p.intro(pc.bgCyan(pc.black(' create-asterui ')));
33
+ const detectedPm = detectPackageManager();
34
+ const options = await p.group({
35
+ projectName: () => p.text({
36
+ message: 'Project name',
37
+ placeholder: 'my-asterui-app',
38
+ defaultValue: 'my-asterui-app',
39
+ validate: (value) => {
40
+ if (!value)
41
+ return 'Project name is required';
42
+ if (!/^[a-z0-9-]+$/.test(value))
43
+ return 'Project name must be lowercase with hyphens only';
44
+ if (fs.existsSync(value))
45
+ return `Directory "${value}" already exists`;
46
+ },
47
+ }),
48
+ language: () => p.select({
49
+ message: 'Language',
50
+ options: [
51
+ { value: 'ts', label: 'TypeScript', hint: 'recommended' },
52
+ { value: 'js', label: 'JavaScript' },
53
+ ],
54
+ }),
55
+ themePreset: () => p.select({
56
+ message: 'Themes',
57
+ options: [
58
+ { value: 'light-dark', label: 'Light/Dark', hint: 'recommended' },
59
+ { value: 'business', label: 'Business/Corporate' },
60
+ { value: 'all', label: 'All themes' },
61
+ { value: 'custom', label: 'Choose specific...' },
62
+ ],
63
+ }),
64
+ customThemes: ({ results }) => results.themePreset === 'custom'
65
+ ? p.multiselect({
66
+ message: 'Select themes',
67
+ options: DAISYUI_THEMES.map((t) => ({ value: t, label: t })),
68
+ initialValues: ['light', 'dark'],
69
+ required: true,
70
+ })
71
+ : Promise.resolve([]),
72
+ packageManager: () => p.select({
73
+ message: 'Package manager',
74
+ options: [
75
+ { value: detectedPm, label: detectedPm, hint: 'detected' },
76
+ ...['npm', 'pnpm', 'yarn']
77
+ .filter((pm) => pm !== detectedPm)
78
+ .map((pm) => ({ value: pm, label: pm })),
79
+ ],
80
+ }),
81
+ }, {
82
+ onCancel: () => {
83
+ p.cancel('Operation cancelled.');
84
+ process.exit(0);
85
+ },
86
+ });
87
+ const s = p.spinner();
88
+ s.start('Creating project...');
89
+ const projectDir = path.resolve(process.cwd(), options.projectName);
90
+ const templateDir = path.join(__dirname, '..', 'templates', options.language);
91
+ // Create project directory
92
+ fs.mkdirSync(projectDir, { recursive: true });
93
+ fs.mkdirSync(path.join(projectDir, 'src'), { recursive: true });
94
+ // Copy template files
95
+ copyDir(templateDir, projectDir);
96
+ // Generate package.json
97
+ const packageJson = generatePackageJson(options.projectName, options.language);
98
+ fs.writeFileSync(path.join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
99
+ // Generate index.css with theme config
100
+ const themes = getThemes(options.themePreset, options.customThemes);
101
+ const cssContent = generateCss(themes);
102
+ fs.writeFileSync(path.join(projectDir, 'src', 'index.css'), cssContent);
103
+ s.stop('Project created!');
104
+ const pm = options.packageManager;
105
+ // Run install
106
+ s.start('Installing dependencies...');
107
+ await runInstall(pm, projectDir);
108
+ s.stop('Dependencies installed!');
109
+ p.note(`cd ${options.projectName}\n${getRunCommand(pm)} dev`, 'Next steps');
110
+ p.outro(pc.green('Happy coding!'));
111
+ }
112
+ function runInstall(pm, cwd) {
113
+ return new Promise((resolve, reject) => {
114
+ const cmd = pm === 'npm' ? 'npm' : pm;
115
+ const args = pm === 'yarn' ? [] : ['install'];
116
+ const child = spawn(cmd, args, { cwd, stdio: 'ignore' });
117
+ child.on('close', (code) => {
118
+ if (code === 0)
119
+ resolve();
120
+ else
121
+ reject(new Error(`Install failed with code ${code}`));
122
+ });
123
+ child.on('error', reject);
124
+ });
125
+ }
126
+ function copyDir(src, dest) {
127
+ const entries = fs.readdirSync(src, { withFileTypes: true });
128
+ for (const entry of entries) {
129
+ const srcPath = path.join(src, entry.name);
130
+ const destPath = path.join(dest, entry.name);
131
+ if (entry.isDirectory()) {
132
+ fs.mkdirSync(destPath, { recursive: true });
133
+ copyDir(srcPath, destPath);
134
+ }
135
+ else {
136
+ fs.copyFileSync(srcPath, destPath);
137
+ }
138
+ }
139
+ }
140
+ function generatePackageJson(name, language) {
141
+ const isTs = language === 'ts';
142
+ const pkg = {
143
+ name,
144
+ private: true,
145
+ version: '0.0.0',
146
+ type: 'module',
147
+ scripts: {
148
+ dev: 'vite',
149
+ build: isTs ? 'tsc -b && vite build' : 'vite build',
150
+ preview: 'vite preview',
151
+ },
152
+ dependencies: {
153
+ asterui: '^0.12.0',
154
+ react: '^19.0.0',
155
+ 'react-dom': '^19.0.0',
156
+ 'react-hook-form': '^7.0.0',
157
+ },
158
+ devDependencies: {
159
+ '@tailwindcss/vite': '^4.1.0',
160
+ '@vitejs/plugin-react': '^5.1.0',
161
+ daisyui: '^5.0.0',
162
+ tailwindcss: '^4.1.0',
163
+ vite: '^7.0.0',
164
+ },
165
+ };
166
+ if (isTs) {
167
+ pkg.devDependencies['typescript'] = '^5.6.0';
168
+ pkg.devDependencies['@types/react'] = '^19.0.0';
169
+ pkg.devDependencies['@types/react-dom'] = '^19.0.0';
170
+ }
171
+ return pkg;
172
+ }
173
+ function getThemes(preset, customThemes) {
174
+ switch (preset) {
175
+ case 'light-dark':
176
+ return ['light', 'dark'];
177
+ case 'business':
178
+ return ['corporate', 'business'];
179
+ case 'all':
180
+ return [];
181
+ case 'custom':
182
+ return customThemes;
183
+ default:
184
+ return ['light', 'dark'];
185
+ }
186
+ }
187
+ function generateCss(themes) {
188
+ let daisyPlugin;
189
+ if (themes.length === 0) {
190
+ // All themes
191
+ daisyPlugin = '@plugin "daisyui";';
192
+ }
193
+ else if (themes.length === 2 && ((themes[0] === 'light' && themes[1] === 'dark') ||
194
+ (themes[0] === 'corporate' && themes[1] === 'business'))) {
195
+ // Light/dark pair with prefersDark
196
+ daisyPlugin = `@plugin "daisyui" {
197
+ themes: ${themes[0]} --default, ${themes[1]} --prefersDark;
198
+ }`;
199
+ }
200
+ else {
201
+ // Custom selection
202
+ daisyPlugin = `@plugin "daisyui" {
203
+ themes: ${themes.join(', ')};
204
+ }`;
205
+ }
206
+ return `@import "tailwindcss";
207
+ ${daisyPlugin}
208
+ @source "../node_modules/asterui";
209
+ `;
210
+ }
211
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "create-asterui",
3
+ "version": "0.1.0",
4
+ "description": "Create a new AsterUI project",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-asterui": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates"
12
+ ],
13
+ "dependencies": {
14
+ "@clack/prompts": "^0.10.0",
15
+ "picocolors": "^1.1.1"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^22.0.0",
19
+ "typescript": "^5.6.3"
20
+ },
21
+ "keywords": [
22
+ "asterui",
23
+ "react",
24
+ "daisyui",
25
+ "tailwindcss",
26
+ "create"
27
+ ],
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/edadma/asterui"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "dev": "tsc --watch"
36
+ }
37
+ }
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>AsterUI App</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.jsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,24 @@
1
+ import { Navbar, ThemeController } from 'asterui'
2
+
3
+ function App() {
4
+ return (
5
+ <>
6
+ <Navbar
7
+ className="bg-base-100 shadow-lg"
8
+ start={<a className="text-xl font-bold">AsterUI App</a>}
9
+ end={<ThemeController.Swap />}
10
+ />
11
+
12
+ <div className="p-6">
13
+ <div className="max-w-4xl mx-auto">
14
+ <h1 className="text-4xl font-bold mb-4">Welcome to AsterUI</h1>
15
+ <p className="text-base-content/70">
16
+ Start building your app by editing <code className="bg-base-300 px-1 rounded">src/App.jsx</code>
17
+ </p>
18
+ </div>
19
+ </div>
20
+ </>
21
+ )
22
+ }
23
+
24
+ export default App
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App'
5
+
6
+ createRoot(document.getElementById('root')).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import tailwindcss from '@tailwindcss/vite'
4
+
5
+ export default defineConfig({
6
+ plugins: [react(), tailwindcss()],
7
+ })
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>AsterUI App</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,24 @@
1
+ import { Navbar, ThemeController } from 'asterui'
2
+
3
+ function App() {
4
+ return (
5
+ <>
6
+ <Navbar
7
+ className="bg-base-100 shadow-lg"
8
+ start={<a className="text-xl font-bold">AsterUI App</a>}
9
+ end={<ThemeController.Swap />}
10
+ />
11
+
12
+ <div className="p-6">
13
+ <div className="max-w-4xl mx-auto">
14
+ <h1 className="text-4xl font-bold mb-4">Welcome to AsterUI</h1>
15
+ <p className="text-base-content/70">
16
+ Start building your app by editing <code className="bg-base-300 px-1 rounded">src/App.tsx</code>
17
+ </p>
18
+ </div>
19
+ </div>
20
+ </>
21
+ )
22
+ }
23
+
24
+ export default App
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "isolatedModules": true,
11
+ "moduleDetection": "force",
12
+ "noEmit": true,
13
+ "jsx": "react-jsx",
14
+ "strict": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "noUncheckedSideEffectImports": true
19
+ },
20
+ "include": ["src"]
21
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import tailwindcss from '@tailwindcss/vite'
4
+
5
+ export default defineConfig({
6
+ plugins: [react(), tailwindcss()],
7
+ })