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 +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +211 -0
- package/package.json +37 -0
- package/templates/js/index.html +13 -0
- package/templates/js/src/App.jsx +24 -0
- package/templates/js/src/main.jsx +10 -0
- package/templates/js/vite.config.js +7 -0
- package/templates/ts/index.html +13 -0
- package/templates/ts/src/App.tsx +24 -0
- package/templates/ts/src/main.tsx +10 -0
- package/templates/ts/src/vite-env.d.ts +1 -0
- package/templates/ts/tsconfig.json +21 -0
- package/templates/ts/vite.config.ts +7 -0
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.
|
package/dist/index.d.ts
ADDED
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,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 @@
|
|
|
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
|
+
}
|