create-ui0 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/dist/index.js +54 -19
- package/package.json +2 -2
- package/template/package.json.tpl +3 -3
- package/template/src/App.vue +22 -25
- package/template-nuxt/app/app.vue +2 -1
- package/template-nuxt/assets/icons/bookmark.svg +3 -0
- package/template-nuxt/nuxt.config.ts +20 -2
- package/template-nuxt/package.json.tpl +4 -2
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import prompts from 'prompts';
|
|
|
6
6
|
/**
|
|
7
7
|
* create-ui0 - scaffolds a ui0 (Vue + @ui0 packages) app.
|
|
8
8
|
* Usage: npm create ui0 [dir]
|
|
9
|
+
* npm create ui0 [dir] [vite|nuxt] [features] (non-interactive;
|
|
10
|
+
* features: comma list of flex,button,icon)
|
|
9
11
|
*/
|
|
10
12
|
const templateDir = fileURLToPath(new URL('../template', import.meta.url));
|
|
11
13
|
const templateNuxtDir = fileURLToPath(new URL('../template-nuxt', import.meta.url));
|
|
@@ -32,8 +34,9 @@ const FEATURES = [
|
|
|
32
34
|
{
|
|
33
35
|
id: 'flex',
|
|
34
36
|
title: 'Flex layout',
|
|
35
|
-
deps: { '@ui0/flex': '^0.1.
|
|
37
|
+
deps: { '@ui0/flex': '^0.1.4' },
|
|
36
38
|
importLine: "import Flex from '@ui0/flex'",
|
|
39
|
+
cssLines: ["'@ui0/flex/style.css'"],
|
|
37
40
|
section: ` <section>
|
|
38
41
|
<h2>Flex</h2>
|
|
39
42
|
<Flex items="center">
|
|
@@ -46,8 +49,9 @@ const FEATURES = [
|
|
|
46
49
|
{
|
|
47
50
|
id: 'button',
|
|
48
51
|
title: 'Button component',
|
|
49
|
-
deps: { '@ui0/button': '^0.1.
|
|
52
|
+
deps: { '@ui0/button': '^0.1.4' },
|
|
50
53
|
importLine: "import Button from '@ui0/button'",
|
|
54
|
+
cssLines: ["'@ui0/button/style.css'"],
|
|
51
55
|
section: ` <section>
|
|
52
56
|
<h2>Button</h2>
|
|
53
57
|
<Button>default</Button>
|
|
@@ -56,11 +60,19 @@ const FEATURES = [
|
|
|
56
60
|
{
|
|
57
61
|
id: 'icon',
|
|
58
62
|
title: 'Icon component + ui0 icon pack',
|
|
59
|
-
deps: { '@ui0/icon': '^0.1.
|
|
63
|
+
deps: { '@ui0/icon': '^0.1.4', '@ui0/icons': '^0.1.4' },
|
|
60
64
|
importLine: "import { Icon } from '@ui0/icon'",
|
|
65
|
+
cssLines: ["'@ui0/icon/style.css'", "'@ui0/icons/style.css'"],
|
|
61
66
|
section: ` <section>
|
|
62
67
|
<h2>Icon</h2>
|
|
63
68
|
<Icon value="ui0/heart-alt" />
|
|
69
|
+
</section>`,
|
|
70
|
+
// the nuxt template also wires the svg loader, so the demo shows an
|
|
71
|
+
// app-local icon next to the built-in pack one
|
|
72
|
+
sectionNuxt: ` <section>
|
|
73
|
+
<h2>Icon</h2>
|
|
74
|
+
<Icon value="ui0/heart-alt" />
|
|
75
|
+
<Icon value="assets/icons/bookmark" />
|
|
64
76
|
</section>`
|
|
65
77
|
}
|
|
66
78
|
];
|
|
@@ -125,6 +137,8 @@ const run = async () => {
|
|
|
125
137
|
return;
|
|
126
138
|
}
|
|
127
139
|
const argDir = process.argv[2];
|
|
140
|
+
const argHost = process.argv[3];
|
|
141
|
+
const argFeatures = process.argv[4]?.split(',').filter(Boolean);
|
|
128
142
|
const { dir } = await prompts({
|
|
129
143
|
type: argDir ? null : 'text',
|
|
130
144
|
name: 'dir',
|
|
@@ -143,8 +157,8 @@ const run = async () => {
|
|
|
143
157
|
if (!overwrite)
|
|
144
158
|
process.exit(0);
|
|
145
159
|
}
|
|
146
|
-
const { host } = (await prompts({
|
|
147
|
-
type: 'select',
|
|
160
|
+
const { host: pickedHost } = (await prompts({
|
|
161
|
+
type: argHost ? null : 'select',
|
|
148
162
|
name: 'host',
|
|
149
163
|
message: 'App host',
|
|
150
164
|
choices: [
|
|
@@ -153,36 +167,57 @@ const run = async () => {
|
|
|
153
167
|
],
|
|
154
168
|
initial: 0
|
|
155
169
|
}, { onCancel }));
|
|
156
|
-
const
|
|
157
|
-
|
|
170
|
+
const host = argHost ?? pickedHost;
|
|
171
|
+
const { features: pickedFeatures } = (await prompts({
|
|
172
|
+
type: argFeatures ? null : 'multiselect',
|
|
158
173
|
name: 'features',
|
|
159
|
-
message:
|
|
174
|
+
message: 'Packages to include',
|
|
160
175
|
choices: FEATURES.map((f) => ({ title: f.title, value: f.id, selected: f.id !== 'icon' })),
|
|
161
176
|
instructions: false
|
|
162
177
|
}, { onCancel }));
|
|
163
|
-
|
|
164
|
-
//
|
|
178
|
+
const features = argFeatures ?? pickedFeatures ?? [];
|
|
179
|
+
// the nuxt flavour lives in its own template, in manual-import mode
|
|
180
|
+
// (components: false): the picked features drive the imports in app.vue,
|
|
181
|
+
// the demo sections and the built styles in the nuxt css pipeline
|
|
165
182
|
const sourceDir = host === 'nuxt' ? templateNuxtDir : templateDir;
|
|
166
183
|
mkdirSync(target, { recursive: true });
|
|
167
184
|
cpSync(sourceDir, target, { recursive: true });
|
|
168
185
|
rmSync(path.join(target, 'package.json.tpl'));
|
|
169
186
|
const picked = FEATURES.filter((f) => features.includes(f.id));
|
|
170
|
-
// package.json from the template manifest + chosen deps (
|
|
171
|
-
//
|
|
187
|
+
// package.json from the template manifest + the chosen feature deps (the
|
|
188
|
+
// nuxt template pins @ui0/core + @ui0/theme itself for the manual imports)
|
|
172
189
|
const manifest = JSON.parse(readFileSync(path.join(sourceDir, 'package.json.tpl'), 'utf8'));
|
|
173
190
|
manifest.name = name;
|
|
174
|
-
|
|
175
|
-
Object.assign(manifest.dependencies, ...picked.map((f) => f.deps));
|
|
191
|
+
Object.assign(manifest.dependencies, ...picked.map((f) => f.deps));
|
|
176
192
|
writeFileSync(path.join(target, 'package.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
177
|
-
// app entry: src/App.vue (vite) or app/app.vue (nuxt) - inject the
|
|
178
|
-
// sections of the picked features
|
|
179
|
-
// components, so no imports are added there
|
|
193
|
+
// app entry: src/App.vue (vite) or app/app.vue (nuxt) - inject the imports
|
|
194
|
+
// and the demo sections of the picked features
|
|
180
195
|
const appVue = path.join(target, host === 'nuxt' ? path.join('app', 'app.vue') : path.join('src', 'App.vue'));
|
|
181
196
|
let app = readFileSync(appVue, 'utf8');
|
|
182
197
|
app = app
|
|
183
|
-
.replace('/* FEATURE_IMPORTS */',
|
|
184
|
-
.replace('/* FEATURE_SECTIONS */', picked.map((f) => f.section).join('\n\n'));
|
|
198
|
+
.replace('/* FEATURE_IMPORTS */', picked.map((f) => f.importLine).join('\n'))
|
|
199
|
+
.replace('/* FEATURE_SECTIONS */', picked.map((f) => (host === 'nuxt' ? (f.sectionNuxt ?? f.section) : f.section)).join('\n\n'));
|
|
185
200
|
writeFileSync(appVue, app);
|
|
201
|
+
// nuxt manual mode: the picked features' built styles join the css
|
|
202
|
+
// pipeline, the icon feature wires the svg loader (the template ships
|
|
203
|
+
// sample icons under assets/ - they need the configured dir to exist)
|
|
204
|
+
if (host === 'nuxt') {
|
|
205
|
+
const nuxtConfigPath = path.join(target, 'nuxt.config.ts');
|
|
206
|
+
const withIcons = features.includes('icon');
|
|
207
|
+
const configSrc = readFileSync(nuxtConfigPath, 'utf8')
|
|
208
|
+
.replace('/* FEATURE_VITE_IMPORT */', withIcons ? "import { fileURLToPath } from 'node:url'\n\nimport ViteUi0Icon from '@ui0/icon/vite'\n" : '')
|
|
209
|
+
.replace('/* FEATURE_VITE_PLUGINS */',
|
|
210
|
+
// absolute on purpose: nuxt's vite root is the app/ dir, relative
|
|
211
|
+
// dirs would resolve against it. dir is the scan root - an svg at
|
|
212
|
+
// <dir>/icons/bookmark.svg is addressed 'assets/icons/bookmark'
|
|
213
|
+
withIcons ? "ViteUi0Icon({ dir: fileURLToPath(new URL('./assets', import.meta.url)) })" : '')
|
|
214
|
+
.replace('/* FEATURE_CSS */',
|
|
215
|
+
// the placeholder trails the array's first entry - lead with a comma
|
|
216
|
+
picked.length ? `,\n ${picked.flatMap((f) => f.cssLines ?? []).join(',\n ')}` : '');
|
|
217
|
+
writeFileSync(nuxtConfigPath, configSrc);
|
|
218
|
+
if (!withIcons)
|
|
219
|
+
rmSync(path.join(target, 'assets'), { recursive: true, force: true });
|
|
220
|
+
}
|
|
186
221
|
// the icon pack registers itself as a vue plugin (vite hosts only - the
|
|
187
222
|
// nuxt module wires the icon framework and the pack itself)
|
|
188
223
|
if (host !== 'nuxt') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-ui0",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Scaffold a ui0 (Vue + @ui0) app - npm create ui0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
16
|
"create:build": "tsc -p tsconfig.json",
|
|
17
|
-
"create:publish": "
|
|
17
|
+
"create:publish": "node ../../scripts/publish-packages.ts"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"prompts": "^2.4.2"
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"vue": "^3.5.45",
|
|
13
|
-
"@ui0/core": "^0.1.
|
|
14
|
-
"@ui0/theme": "^0.1.
|
|
13
|
+
"@ui0/core": "^0.1.5",
|
|
14
|
+
"@ui0/theme": "^0.1.5"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@ui0/types": "^0.1.
|
|
17
|
+
"@ui0/types": "^0.1.6",
|
|
18
18
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
19
19
|
"sass-embedded": "^1.80.0",
|
|
20
20
|
"typescript": "~6.0.3",
|
package/template/src/App.vue
CHANGED
|
@@ -4,41 +4,38 @@
|
|
|
4
4
|
title="ui0 app"
|
|
5
5
|
name="app"
|
|
6
6
|
>
|
|
7
|
-
|
|
8
|
-
<h1>ui0 app</h1>
|
|
9
|
-
|
|
10
|
-
/* FEATURE_SECTIONS */
|
|
11
|
-
</main>
|
|
7
|
+
/* FEATURE_SECTIONS */
|
|
12
8
|
</App>
|
|
13
9
|
</ThemeProvider>
|
|
14
10
|
</template>
|
|
15
11
|
|
|
16
12
|
<script setup lang="ts">
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
import { App } from '@ui0/core'
|
|
14
|
+
import { ThemeProvider } from '@ui0/theme'
|
|
19
15
|
/* FEATURE_IMPORTS */
|
|
20
16
|
</script>
|
|
21
17
|
|
|
22
18
|
<style module lang="scss">
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
@value app from '@ui0/core/app';
|
|
20
|
+
.page {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
gap: 24px;
|
|
24
|
+
padding: 32px;
|
|
25
|
+
font-family: system-ui, sans-serif;
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
h2 {
|
|
34
|
-
font-size: 14px;
|
|
35
|
-
opacity: 0.7;
|
|
36
|
-
margin-bottom: 8px;
|
|
37
|
-
}
|
|
27
|
+
h1 {
|
|
28
|
+
font-size: 20px;
|
|
38
29
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
h2 {
|
|
31
|
+
font-size: 14px;
|
|
32
|
+
opacity: 0.7;
|
|
33
|
+
margin-bottom: 8px;
|
|
43
34
|
}
|
|
35
|
+
}
|
|
36
|
+
.box {
|
|
37
|
+
padding: 12px 16px;
|
|
38
|
+
border: 1px solid rgba(127, 127, 127, 0.4);
|
|
39
|
+
border-radius: 6px;
|
|
40
|
+
}
|
|
44
41
|
</style>
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
/* FEATURE_VITE_IMPORT */
|
|
1
2
|
export default defineNuxtConfig({
|
|
2
3
|
ssr: true,
|
|
3
4
|
compatibilityDate: '2026-11-12',
|
|
4
5
|
devtools: { enabled: false },
|
|
5
|
-
//
|
|
6
|
-
|
|
6
|
+
// built ui0 component styles ship in the head of every ssr response; the
|
|
7
|
+
// module pushes @ui0/core/style.css itself - one entry per ui0 component
|
|
8
|
+
// the app renders (app/app.vue imports them in code, manual mode below)
|
|
9
|
+
css: ['@ui0/theme/theme-provider/style.css'/* FEATURE_CSS */],
|
|
10
|
+
modules: ['@ui0/nuxt'],
|
|
11
|
+
ui0: {
|
|
12
|
+
// manual component imports: no auto-registration, the template imports
|
|
13
|
+
// Flex / Button / Icon / ThemeProvider in app/app.vue and lists their
|
|
14
|
+
// style.css above
|
|
15
|
+
components: false
|
|
16
|
+
},
|
|
17
|
+
vite: {
|
|
18
|
+
plugins: [
|
|
19
|
+
// the svg icon loader - only for the app's OWN icons (dir) and
|
|
20
|
+
// compositions (virtual); the built-in ui0 pack ships prebuilt from
|
|
21
|
+
// @ui0/icons and needs no loader
|
|
22
|
+
/* FEATURE_VITE_PLUGINS */
|
|
23
|
+
]
|
|
24
|
+
}
|
|
7
25
|
})
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
"preview": "nuxt preview"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@ui0/
|
|
12
|
+
"@ui0/core": "^0.1.5",
|
|
13
|
+
"@ui0/nuxt": "^0.1.2",
|
|
14
|
+
"@ui0/theme": "^0.1.5",
|
|
13
15
|
"nuxt": "^4.6.4",
|
|
14
16
|
"vue": "^3.5.45"
|
|
15
17
|
},
|
|
16
18
|
"devDependencies": {
|
|
17
|
-
"@ui0/types": "^0.1.
|
|
19
|
+
"@ui0/types": "^0.1.6",
|
|
18
20
|
"sass-embedded": "^1.80.0"
|
|
19
21
|
}
|
|
20
22
|
}
|