ui-thing 0.1.28 → 0.1.30
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/.github/dependabot.yml +12 -0
- package/CHANGELOG.md +55 -0
- package/dist/index.js +267 -138
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/commands/add.ts +6 -11
- package/src/commands/init.ts +6 -2
- package/src/commands/prettier.ts +2 -6
- package/src/commands/shortcuts.ts +2 -6
- package/src/comps.ts +7 -7
- package/src/index.ts +2 -1
- package/src/templates/css.ts +5 -7
- package/src/templates/shortcuts.ts +11 -6
- package/src/templates/tailwind.ts +31 -1
- package/src/types.ts +2 -1
- package/src/utils/addPrettierConfig.ts +4 -2
- package/src/utils/addShortcutFiles.ts +9 -3
- package/src/utils/compareUIConfig.ts +1 -0
- package/src/utils/config.ts +21 -3
- package/src/utils/constants.ts +14 -1
- package/src/utils/uiConfigPrompt.ts +32 -13
- package/tests/utils/compareUIConfig.test.ts +1 -0
- package/tsconfig.json +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui-thing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"description": "CLI used to add Nuxt 3 components to a project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -44,28 +44,28 @@
|
|
|
44
44
|
"c12": "^2.0.1",
|
|
45
45
|
"commander": "^12.1.0",
|
|
46
46
|
"defu": "^6.1.4",
|
|
47
|
-
"execa": "^9.
|
|
47
|
+
"execa": "^9.5.1",
|
|
48
48
|
"figlet": "^1.8.0",
|
|
49
49
|
"fs-extra": "^11.2.0",
|
|
50
50
|
"kleur": "^4.1.5",
|
|
51
51
|
"lodash": "^4.17.21",
|
|
52
52
|
"nypm": "^0.3.12",
|
|
53
|
-
"ora": "^8.1.
|
|
53
|
+
"ora": "^8.1.1",
|
|
54
54
|
"prompts": "^2.4.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@gmrchk/cli-testing-library": "^0.1.2",
|
|
58
|
-
"@ianvs/prettier-plugin-sort-imports": "^4.
|
|
58
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
|
|
59
59
|
"@types/figlet": "^1.7.0",
|
|
60
60
|
"@types/fs-extra": "^11.0.4",
|
|
61
|
-
"@types/lodash": "^4.17.
|
|
62
|
-
"@types/node": "^22.
|
|
61
|
+
"@types/lodash": "^4.17.13",
|
|
62
|
+
"@types/node": "^22.9.0",
|
|
63
63
|
"@types/prompts": "^2.4.9",
|
|
64
|
-
"@vitest/coverage-v8": "^2.1.
|
|
64
|
+
"@vitest/coverage-v8": "^2.1.5",
|
|
65
65
|
"magicast": "^0.3.5",
|
|
66
|
-
"tsup": "^8.3.
|
|
66
|
+
"tsup": "^8.3.5",
|
|
67
67
|
"typescript": "^5.6.3",
|
|
68
|
-
"vitest": "^2.1.
|
|
68
|
+
"vitest": "^2.1.5"
|
|
69
69
|
},
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
package/src/commands/add.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { Command } from "commander";
|
|
4
3
|
import { consola } from "consola";
|
|
5
|
-
import { defu } from "defu";
|
|
6
4
|
import kleur from "kleur";
|
|
7
5
|
import _ from "lodash";
|
|
8
6
|
import prompts from "prompts";
|
|
@@ -144,11 +142,8 @@ export const add = new Command()
|
|
|
144
142
|
(i: any) => i.from === "vue-sonner" && i.name === "toast"
|
|
145
143
|
);
|
|
146
144
|
if (!sonnerExists) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
name: "toast",
|
|
150
|
-
as: "useSonner",
|
|
151
|
-
});
|
|
145
|
+
// prettier-ignore
|
|
146
|
+
cfg.defaultExport.imports.imports.push({ from: "vue-sonner", name: "toast", as: "useSonner" });
|
|
152
147
|
}
|
|
153
148
|
const transpileExists = cfg.defaultExport.build.transpile.find((i: any) => "vue-sonner");
|
|
154
149
|
if (!transpileExists) {
|
|
@@ -162,21 +157,21 @@ export const add = new Command()
|
|
|
162
157
|
cfg.defaultExport.app.head.script ||= [];
|
|
163
158
|
const scriptOneExists = cfg.defaultExport.app.head.script.find(
|
|
164
159
|
(i: any) =>
|
|
165
|
-
i.src === "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.
|
|
160
|
+
i.src === "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/pdfmake.min.js"
|
|
166
161
|
);
|
|
167
162
|
if (!scriptOneExists) {
|
|
168
163
|
cfg.defaultExport.app.head.script.push({
|
|
169
|
-
src: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.
|
|
164
|
+
src: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/pdfmake.min.js",
|
|
170
165
|
defer: true,
|
|
171
166
|
});
|
|
172
167
|
}
|
|
173
168
|
const scriptTwoExists = cfg.defaultExport.app.head.script.find(
|
|
174
169
|
(i: any) =>
|
|
175
|
-
i.src === "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.
|
|
170
|
+
i.src === "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/vfs_fonts.min.js"
|
|
176
171
|
);
|
|
177
172
|
if (!scriptTwoExists) {
|
|
178
173
|
cfg.defaultExport.app.head.script.push({
|
|
179
|
-
src: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.
|
|
174
|
+
src: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.12/vfs_fonts.min.js",
|
|
180
175
|
defer: true,
|
|
181
176
|
});
|
|
182
177
|
}
|
package/src/commands/init.ts
CHANGED
|
@@ -16,10 +16,11 @@ export const init = new Command()
|
|
|
16
16
|
.command("init")
|
|
17
17
|
.name("init")
|
|
18
18
|
.description(
|
|
19
|
-
"Initialize UI Thing in your
|
|
19
|
+
"Initialize UI Thing in your Nuxt project. This will: 1. Create a tailwind.config.js file 2. Update your nuxt.config.ts file 3. Add the necessary dependencies 4. Create a ui-thing.config.ts file with the default configuration"
|
|
20
20
|
)
|
|
21
21
|
.option("-f --force", "Overwrite config file if it exists.", false)
|
|
22
22
|
.option("-y --yes", "Skip prompts and use default values.", false)
|
|
23
|
+
.option("-n --nuxtVersion <number>", "Specify the Nuxt version you are using.", "3")
|
|
23
24
|
.action(async (options: InitOptions) => {
|
|
24
25
|
// Get nuxt config
|
|
25
26
|
const cfg = await getNuxtConfig();
|
|
@@ -37,7 +38,10 @@ export const init = new Command()
|
|
|
37
38
|
// Add init modules ot nuxt cinfig
|
|
38
39
|
addModuleToConfig(cfg.nuxtConfig, INIT_MODULES);
|
|
39
40
|
// Configure modules in nuxt config
|
|
40
|
-
cfg.defaultExport.tailwindcss = defu(cfg.defaultExport.tailwindcss, {
|
|
41
|
+
cfg.defaultExport.tailwindcss = defu(cfg.defaultExport.tailwindcss, {
|
|
42
|
+
exposeConfig: true,
|
|
43
|
+
editorSupport: true,
|
|
44
|
+
});
|
|
41
45
|
cfg.defaultExport.colorMode = defu(cfg.defaultExport.colorMode, { classSuffix: "" });
|
|
42
46
|
cfg.defaultExport.imports ||= {};
|
|
43
47
|
cfg.defaultExport.imports.imports ||= [];
|
package/src/commands/prettier.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Command } from "commander";
|
|
|
2
2
|
import prompts from "prompts";
|
|
3
3
|
|
|
4
4
|
import { addPrettierConfig } from "../utils/addPrettierConfig";
|
|
5
|
+
import { PACKAGE_MANAGER_CHOICES } from "../utils/constants";
|
|
5
6
|
import { installPackages } from "../utils/installPackages";
|
|
6
7
|
import { printFancyBoxMessage } from "../utils/printFancyBoxMessage";
|
|
7
8
|
|
|
@@ -24,12 +25,7 @@ export const addPrettier = new Command()
|
|
|
24
25
|
name: "pkgManager",
|
|
25
26
|
type: "select",
|
|
26
27
|
message: "Which package manager are you using?",
|
|
27
|
-
choices:
|
|
28
|
-
{ title: "npm", value: "npm" },
|
|
29
|
-
{ title: "yarn", value: "yarn" },
|
|
30
|
-
{ title: "pnpm", value: "pnpm" },
|
|
31
|
-
{ title: "bun", value: "bun" },
|
|
32
|
-
],
|
|
28
|
+
choices: PACKAGE_MANAGER_CHOICES,
|
|
33
29
|
});
|
|
34
30
|
if (!pkgManager) return process.exit(0);
|
|
35
31
|
|
|
@@ -3,6 +3,7 @@ import prompts from "prompts";
|
|
|
3
3
|
|
|
4
4
|
import { addShortcutFiles } from "../utils/addShortcutFiles";
|
|
5
5
|
import { addModuleToConfig, getNuxtConfig, updateConfig } from "../utils/config";
|
|
6
|
+
import { PACKAGE_MANAGER_CHOICES } from "../utils/constants";
|
|
6
7
|
import { installPackages } from "../utils/installPackages";
|
|
7
8
|
import { printFancyBoxMessage } from "../utils/printFancyBoxMessage";
|
|
8
9
|
|
|
@@ -23,12 +24,7 @@ export const addShortcuts = new Command()
|
|
|
23
24
|
name: "pkgManager",
|
|
24
25
|
type: "select",
|
|
25
26
|
message: "Which package manager are you using?",
|
|
26
|
-
choices:
|
|
27
|
-
{ title: "npm", value: "npm" },
|
|
28
|
-
{ title: "yarn", value: "yarn" },
|
|
29
|
-
{ title: "pnpm", value: "pnpm" },
|
|
30
|
-
{ title: "bun", value: "bun" },
|
|
31
|
-
],
|
|
27
|
+
choices: PACKAGE_MANAGER_CHOICES,
|
|
32
28
|
});
|
|
33
29
|
if (!pkgManager) return process.exit(0);
|
|
34
30
|
|
package/src/comps.ts
CHANGED
|
@@ -76,7 +76,7 @@ export default [
|
|
|
76
76
|
fileName: "shared.styles.ts",
|
|
77
77
|
dirPath: "utils",
|
|
78
78
|
fileContent:
|
|
79
|
-
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "inline-flex items-center justify-center
|
|
79
|
+
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "group inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n expandIcon: "group relative bg-primary text-primary-foreground hover:bg-primary/90",\n ringHover:\n "bg-primary text-primary-foreground transition-all duration-300 hover:bg-primary/90 hover:ring-2 hover:ring-primary/90 hover:ring-offset-2",\n shine:\n "animate-shine bg-gradient-to-r from-primary via-primary/75 to-primary bg-[length:400%_100%] text-primary-foreground",\n gooeyRight:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 before:absolute before:inset-0 before:-z-10 before:translate-x-[150%] before:translate-y-[150%] before:scale-[2.5] before:rounded-[100%] before:bg-gradient-to-r before:transition-transform before:duration-1000 hover:before:translate-x-[0%] hover:before:translate-y-[0%]",\n gooeyLeft:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 after:absolute after:inset-0 after:-z-10 after:translate-x-[-150%] after:translate-y-[150%] after:scale-[2.5] after:rounded-[100%] after:bg-gradient-to-l after:transition-transform after:duration-1000 hover:after:translate-x-[0%] hover:after:translate-y-[0%]",\n linkHover1:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-right hover:after:scale-x-0",\n linkHover2:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-right after:scale-x-0 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-left hover:after:scale-x-100",\n },\n size: {\n xs: "h-8 px-2",\n sm: "h-9 px-3",\n default: "h-10 px-4 py-2",\n lg: "h-11 px-8",\n "icon-xs": "h-8 w-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n hasIcon: {\n false: "gap-2",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n',
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
82
|
files: [
|
|
@@ -300,7 +300,7 @@ export default [
|
|
|
300
300
|
fileName: "Badge.vue",
|
|
301
301
|
dirPath: "components/UI",
|
|
302
302
|
fileContent:
|
|
303
|
-
'<template>\n <component\n :is="elementType"\n :
|
|
303
|
+
'<template>\n <component\n :is="elementType"\n :class="badgeVariants({ disabled, size, variant, class: props.class })"\n v-bind="forwarded"\n @click="onClick"\n >\n <slot />\n </component>\n</template>\n\n<script lang="ts">\n import { reactiveOmit } from "@vueuse/core";\n import { useForwardProps } from "radix-vue";\n import type { NuxtLinkProps } from "#app/components";\n</script>\n<script lang="ts" setup>\n const badgeVariants = tv({\n base: "inline-flex items-center rounded-full border font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",\n variants: {\n variant: {\n default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",\n secondary:\n "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",\n destructive:\n "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",\n outline: "text-foreground",\n },\n disabled: {\n true: "cursor-not-allowed opacity-50",\n },\n size: {\n sm: "px-2.5 py-0.5 text-xs font-medium",\n md: "px-2.5 py-1 text-sm font-semibold",\n lg: "px-3 py-1.5 text-sm font-semibold",\n },\n },\n defaultVariants: {\n variant: "default",\n disabled: false,\n size: "sm",\n },\n });\n\n type BadgeProps = VariantProps<typeof badgeVariants>;\n\n const props = defineProps<\n NuxtLinkProps & {\n /** Any additional class that should be added to the badge */\n class?: any;\n /** The variant of the badge */\n variant?: BadgeProps["variant"];\n /** The size of the badge */\n size?: BadgeProps["size"];\n /** The action to perform when the badge is clicked */\n onClick?: () => void;\n /** Should the badge be disabled or not */\n disabled?: boolean;\n /** The element to render the badge as */\n tag?: string;\n }\n >();\n\n const forwarded = useForwardProps(reactiveOmit(props, "class", "variant", "onClick", "disabled"));\n\n const elementType = computed(() => {\n if (props.tag) return props.tag;\n if (props.href || props.to) return resolveComponent("NuxtLink");\n if (props.onClick) return "button";\n return props.tag || "div";\n });\n</script>\n',
|
|
304
304
|
},
|
|
305
305
|
],
|
|
306
306
|
utils: [],
|
|
@@ -330,7 +330,7 @@ export default [
|
|
|
330
330
|
fileName: "shared.styles.ts",
|
|
331
331
|
dirPath: "utils",
|
|
332
332
|
fileContent:
|
|
333
|
-
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "inline-flex items-center justify-center
|
|
333
|
+
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "group inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n expandIcon: "group relative bg-primary text-primary-foreground hover:bg-primary/90",\n ringHover:\n "bg-primary text-primary-foreground transition-all duration-300 hover:bg-primary/90 hover:ring-2 hover:ring-primary/90 hover:ring-offset-2",\n shine:\n "animate-shine bg-gradient-to-r from-primary via-primary/75 to-primary bg-[length:400%_100%] text-primary-foreground",\n gooeyRight:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 before:absolute before:inset-0 before:-z-10 before:translate-x-[150%] before:translate-y-[150%] before:scale-[2.5] before:rounded-[100%] before:bg-gradient-to-r before:transition-transform before:duration-1000 hover:before:translate-x-[0%] hover:before:translate-y-[0%]",\n gooeyLeft:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 after:absolute after:inset-0 after:-z-10 after:translate-x-[-150%] after:translate-y-[150%] after:scale-[2.5] after:rounded-[100%] after:bg-gradient-to-l after:transition-transform after:duration-1000 hover:after:translate-x-[0%] hover:after:translate-y-[0%]",\n linkHover1:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-right hover:after:scale-x-0",\n linkHover2:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-right after:scale-x-0 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-left hover:after:scale-x-100",\n },\n size: {\n xs: "h-8 px-2",\n sm: "h-9 px-3",\n default: "h-10 px-4 py-2",\n lg: "h-11 px-8",\n "icon-xs": "h-8 w-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n hasIcon: {\n false: "gap-2",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n',
|
|
334
334
|
},
|
|
335
335
|
],
|
|
336
336
|
files: [
|
|
@@ -338,7 +338,7 @@ export default [
|
|
|
338
338
|
fileName: "Button.vue",
|
|
339
339
|
dirPath: "components/UI",
|
|
340
340
|
fileContent:
|
|
341
|
-
'<template>\n <component\n :is="elementType"\n :class="\n buttonStyles({\n disabled: disabled || loading,\n variant: variant,\n size: size,\n class: props.class,\n })\n "\n :disabled="disabled || loading"\n
|
|
341
|
+
'<template>\n <component\n :is="elementType"\n :class="\n buttonStyles({\n hasIcon: !!icon,\n disabled: disabled || loading,\n variant: variant,\n size: size,\n class: props.class,\n })\n "\n :disabled="disabled || loading"\n v-bind="forwarded"\n >\n <slot name="iconLeft">\n <div\n v-if="icon && iconPlacement == \'left\'"\n className="w-0 flex items-center shrink-0 justify-center translate-x-[0%] pr-0 opacity-0 transition-all duration-200 group-hover:w-6 group-hover:translate-x-100 group-hover:pr-2 group-hover:opacity-100"\n >\n <Icon :name="icon" class="size-5" />\n </div>\n </slot>\n <slot>\n <span v-if="text">{{ text }}</span>\n </slot>\n <slot name="iconRight">\n <div\n v-if="icon && iconPlacement == \'right\'"\n className="w-0 flex items-center justify-center shrink-0 translate-x-[100%] pl-0 opacity-0 transition-all duration-200 group-hover:w-6 group-hover:translate-x-0 group-hover:pl-2 group-hover:opacity-100"\n >\n <Icon :name="icon" class="size-5" />\n </div>\n </slot>\n </component>\n</template>\n\n<script setup lang="ts">\n import { reactiveOmit } from "@vueuse/core";\n import { useForwardProps } from "radix-vue";\n import type { NuxtLinkProps } from "#app/components";\n\n type ButtonProps = VariantProps<typeof buttonStyles>;\n const props = withDefaults(\n defineProps<\n NuxtLinkProps & {\n /** The type fro the button */\n type?: "button" | "submit" | "reset";\n /** Whether the button is disabled */\n disabled?: boolean;\n /** Whether the button is loading */\n loading?: boolean;\n /** The action to perform when the button is clicked */\n onClick?: any;\n /** The element to render the button as */\n as?: string;\n /** Custom class(es) to add to parent element */\n class?: any;\n /** The variant of the button */\n variant?: ButtonProps["variant"];\n /** The size of the button */\n size?: ButtonProps["size"];\n /** The text to display in the button */\n text?: string;\n /** Should the icon be displayed on the `left` or the `right`? */\n iconPlacement?: "left" | "right";\n /** The icon to display in the button */\n icon?: string;\n }\n >(),\n {\n type: "button",\n }\n );\n\n const elementType = computed(() => {\n if (props.as) return props.as;\n if (props.href || props.to || props.target) return resolveComponent("NuxtLink");\n return "button";\n });\n\n const forwarded = useForwardProps(\n reactiveOmit(\n props,\n "class",\n "text",\n "icon",\n "iconPlacement",\n "size",\n "variant",\n "as",\n "loading",\n "disabled"\n )\n );\n</script>\n',
|
|
342
342
|
},
|
|
343
343
|
],
|
|
344
344
|
composables: [],
|
|
@@ -1295,7 +1295,7 @@ export default [
|
|
|
1295
1295
|
fileName: "Label.vue",
|
|
1296
1296
|
dirPath: "components/UI",
|
|
1297
1297
|
fileContent:
|
|
1298
|
-
'<template>\n <Label :class="styles({ class: props.class })" v-bind="forwarded">\n <slot />\n <slot name="hint">\n <span v-if="hint">\n {{ hint }}\n </span>\n </slot>\n </Label>\n</template>\n\n<script lang="ts" setup>\n import { Label } from "radix-vue";\n import type { LabelProps } from "radix-vue";\n\n const props = defineProps<\n LabelProps & {\n /** Custom class(es) to add to the label */\n class?: any;\n hint?: string;\n }\n >();\n\n const forwarded = reactiveOmit(props, "class", "hint");\n\n const styles = tv({\n base: "flex items-center justify-between text-[15px] font-medium leading-none hover:cursor-pointer peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm",\n });\n</script>\n',
|
|
1298
|
+
'<template>\n <Label :class="styles({ class: props.class })" v-bind="forwarded">\n <slot />\n <slot name="hint">\n <span v-if="hint" class="text-muted-foreground">\n {{ hint }}\n </span>\n </slot>\n </Label>\n</template>\n\n<script lang="ts" setup>\n import { Label } from "radix-vue";\n import type { LabelProps } from "radix-vue";\n\n const props = defineProps<\n LabelProps & {\n /** Custom class(es) to add to the label */\n class?: any;\n hint?: string;\n }\n >();\n\n const forwarded = reactiveOmit(props, "class", "hint");\n\n const styles = tv({\n base: "flex items-center justify-between text-[15px] font-medium leading-none hover:cursor-pointer peer-disabled:cursor-not-allowed peer-disabled:opacity-70 sm:text-sm",\n });\n</script>\n',
|
|
1299
1299
|
},
|
|
1300
1300
|
],
|
|
1301
1301
|
utils: [],
|
|
@@ -1539,7 +1539,7 @@ export default [
|
|
|
1539
1539
|
fileName: "Navbar.vue",
|
|
1540
1540
|
dirPath: "components/UI",
|
|
1541
1541
|
fileContent:
|
|
1542
|
-
'<template>\n <Primitive :class="styles({ sticky, class: props.class })" v-bind="forwarded">\n <slot />\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n /** Whether the navbar should be sticky */\n sticky?: boolean;\n }\n >(),\n {\n as: "header",\n }\n );\n\n const forwarded = reactiveOmit(props, "class", "sticky");\n\n const styles = tv({\n base: "z-20 border-b bg-background/90 backdrop-blur",\n variants: {\n sticky: {\n true: "sticky top-0",\n },\n },\n });\n</script>\n',
|
|
1542
|
+
'<template>\n <Primitive :class="styles({ sticky, class: props.class })" v-bind="forwarded">\n <slot />\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { reactiveOmit } from "@vueuse/core";\n import { Primitive, useForwardProps } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n /** Whether the navbar should be sticky */\n sticky?: boolean;\n }\n >(),\n {\n as: "header",\n }\n );\n\n const forwarded = useForwardProps(reactiveOmit(props, "class", "sticky"));\n\n const styles = tv({\n base: "z-20 border-b bg-background/90 backdrop-blur",\n variants: {\n sticky: {\n true: "sticky top-0",\n },\n },\n });\n</script>\n',
|
|
1543
1543
|
},
|
|
1544
1544
|
],
|
|
1545
1545
|
utils: [],
|
|
@@ -2667,7 +2667,7 @@ export default [
|
|
|
2667
2667
|
fileName: "Vee/Input.vue",
|
|
2668
2668
|
dirPath: "components/UI",
|
|
2669
2669
|
fileContent:
|
|
2670
|
-
'<template>\n <div class="w-full">\n <UiLabel\n v-if="label"\n :for="inputId"\n :hint="labelHint"\n :class="[disabled && \'text-muted-foreground\', errorMessage && \'text-destructive\', \'mb-2\']"\n ><span>{{ label }} <span v-if="required" class="text-destructive">*</span></span></UiLabel\n >\n <div class="relative">\n <slot name="icon">\n <span v-if="hasIcon" class="absolute inset-y-0 left-3 flex items-center justify-center">\n <Icon v-if="icon" :name="icon" class="h-4 w-4 text-muted-foreground/70" />\n </span>\n </slot>\n <UiInput\n :id="inputId"\n v-model="value"\n :type="type"\n :required="required"\n :name="name"\n :disabled="disabled"\n v-bind="$attrs"\n :class="[hasIcon && \'pl-9\']"\n :placeholder="placeholder"\n @blur="handleBlur"\n />\n </div>\n <TransitionSlide group tag="div">\n <p v-if="hint && !errorMessage" key="hint" class="mt-1.5 text-sm text-muted-foreground">\n {{ hint }}\n </p>\n\n <p v-if="errorMessage" key="errorMessage" class="mt-1.5 text-sm text-destructive">\n {{ errorMessage }}\n </p>\n </TransitionSlide>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = defineProps<{\n label?: string;\n labelHint?: string;\n icon?: string;\n hint?: string;\n disabled?: boolean;\n modelValue?: string;\n name?: string;\n id?: string;\n rules?: any;\n validateOnMount?: boolean;\n type?: string;\n placeholder?: string;\n required?: boolean;\n }>();\n\n const inputId = props.id || useId();\n\n const hasIcon = computed(() => Boolean(props.icon) || Boolean(useSlots().icon));\n\n const { errorMessage, value, handleBlur } = useField(() => props.name || inputId, props.rules, {\n initialValue: props.modelValue,\n label: props.label,\n validateOnMount: props.validateOnMount,\n syncVModel: true,\n });\n</script>\n',
|
|
2670
|
+
'<template>\n <div class="w-full">\n <UiLabel\n v-if="label"\n :for="inputId"\n :hint="labelHint"\n :class="[disabled && \'text-muted-foreground\', errorMessage && \'text-destructive\', \'mb-2\']"\n ><span>{{ label }} <span v-if="required" class="text-destructive">*</span></span></UiLabel\n >\n <div class="relative">\n <slot name="icon">\n <span v-if="hasIcon" class="absolute inset-y-0 left-3 flex items-center justify-center">\n <Icon v-if="icon" :name="icon" class="h-4 w-4 text-muted-foreground/70" />\n </span>\n </slot>\n <slot name="trailingIcon">\n <span\n v-if="hasTrailingIcon"\n class="absolute inset-y-0 right-3 flex items-center justify-center"\n >\n <Icon v-if="trailingIcon" :name="trailingIcon" class="h-4 w-4 text-muted-foreground/70" />\n </span>\n </slot>\n <UiInput\n :id="inputId"\n v-model="value"\n :type="type"\n :required="required"\n :name="name"\n :disabled="disabled"\n v-bind="$attrs"\n :class="[hasIcon && \'pl-9\', hasTrailingIcon && \'pr-9\']"\n :placeholder="placeholder"\n @blur="handleBlur"\n />\n </div>\n <TransitionSlide group tag="div">\n <p v-if="hint && !errorMessage" key="hint" class="mt-1.5 text-sm text-muted-foreground">\n {{ hint }}\n </p>\n\n <p v-if="errorMessage" key="errorMessage" class="mt-1.5 text-sm text-destructive">\n {{ errorMessage }}\n </p>\n </TransitionSlide>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = defineProps<{\n label?: string;\n labelHint?: string;\n icon?: string;\n trailingIcon?: string;\n hint?: string;\n disabled?: boolean;\n modelValue?: string;\n name?: string;\n id?: string;\n rules?: any;\n validateOnMount?: boolean;\n type?: string;\n placeholder?: string;\n required?: boolean;\n }>();\n\n defineOptions({ inheritAttrs: false });\n\n const inputId = props.id || useId();\n\n const hasIcon = computed(() => Boolean(props.icon) || Boolean(useSlots().icon));\n const hasTrailingIcon = computed(\n () => Boolean(props.trailingIcon) || Boolean(useSlots().trailingIcon)\n );\n\n const { errorMessage, value, handleBlur } = useField(() => props.name || inputId, props.rules, {\n initialValue: props.modelValue,\n label: props.label,\n validateOnMount: props.validateOnMount,\n syncVModel: true,\n });\n</script>\n',
|
|
2671
2671
|
},
|
|
2672
2672
|
],
|
|
2673
2673
|
utils: [],
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
|
|
4
|
+
import { version } from "../package.json";
|
|
4
5
|
import { add } from "./commands/add";
|
|
5
6
|
import { init } from "./commands/init";
|
|
6
7
|
import { addPrettier } from "./commands/prettier";
|
|
@@ -22,7 +23,7 @@ console.log();
|
|
|
22
23
|
program
|
|
23
24
|
.name("ui-thing")
|
|
24
25
|
.description("CLI for adding ui-thing components to your Nuxt 3 application")
|
|
25
|
-
.version(
|
|
26
|
+
.version(version)
|
|
26
27
|
.addCommand(init)
|
|
27
28
|
.addCommand(add)
|
|
28
29
|
.addCommand(theme)
|
package/src/templates/css.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export const CSS_START = `@
|
|
2
|
-
|
|
3
|
-
@tailwind base;
|
|
1
|
+
export const CSS_START = `@tailwind base;
|
|
4
2
|
@tailwind components;
|
|
5
3
|
@tailwind utilities;
|
|
6
4
|
`;
|
|
@@ -9,14 +7,14 @@ export const CSS_END = `@layer base {
|
|
|
9
7
|
* {
|
|
10
8
|
@apply border-border;
|
|
11
9
|
}
|
|
10
|
+
html {
|
|
11
|
+
@apply antialiased;
|
|
12
|
+
}
|
|
12
13
|
body {
|
|
13
14
|
@apply bg-background text-foreground;
|
|
14
|
-
font-feature-settings:
|
|
15
|
-
"rlig" 1,
|
|
16
|
-
"calt" 1;
|
|
15
|
+
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
|
-
|
|
20
18
|
`;
|
|
21
19
|
|
|
22
20
|
export const createCSS = (theme: keyof typeof themes) => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export const DEFINE_SHORTCUT =
|
|
2
|
-
import {
|
|
1
|
+
export const DEFINE_SHORTCUT = `/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
|
2
|
+
import { logicAnd, logicNot } from "@vueuse/math";
|
|
3
3
|
import type { ComputedRef, WatchSource } from "vue";
|
|
4
4
|
|
|
5
5
|
export interface ShortcutConfig {
|
|
6
6
|
handler: Function;
|
|
7
7
|
usingInput?: string | boolean;
|
|
8
|
-
whenever?: WatchSource<
|
|
8
|
+
whenever?: WatchSource<boolean>[];
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface ShortcutsConfig {
|
|
@@ -18,7 +18,7 @@ export interface ShortcutsOptions {
|
|
|
18
18
|
|
|
19
19
|
interface Shortcut {
|
|
20
20
|
handler: Function;
|
|
21
|
-
condition: ComputedRef<
|
|
21
|
+
condition: ComputedRef<boolean>;
|
|
22
22
|
chained: boolean;
|
|
23
23
|
// KeyboardEvent attributes
|
|
24
24
|
key: string;
|
|
@@ -157,7 +157,7 @@ export const defineShortcuts = (config: ShortcutsConfig, options: ShortcutsOptio
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
// Create shortcut computed
|
|
160
|
-
const conditions: ComputedRef<
|
|
160
|
+
const conditions: ComputedRef<boolean>[] = [];
|
|
161
161
|
if (!(shortcutConfig as ShortcutConfig).usingInput) {
|
|
162
162
|
conditions.push(logicNot(usingInput));
|
|
163
163
|
} else if (typeof (shortcutConfig as ShortcutConfig).usingInput === "string") {
|
|
@@ -176,12 +176,16 @@ export const defineShortcuts = (config: ShortcutsConfig, options: ShortcutsOptio
|
|
|
176
176
|
|
|
177
177
|
useEventListener("keydown", onKeyDown);
|
|
178
178
|
};
|
|
179
|
+
|
|
179
180
|
`;
|
|
180
181
|
|
|
181
182
|
export const USE_SHORTCUTS = `export const _useShortcuts = () => {
|
|
182
183
|
const macOS = computed(
|
|
183
184
|
() =>
|
|
184
|
-
|
|
185
|
+
import.meta.client &&
|
|
186
|
+
navigator &&
|
|
187
|
+
navigator.userAgent &&
|
|
188
|
+
navigator.userAgent.match(/Macintosh;/)
|
|
185
189
|
);
|
|
186
190
|
|
|
187
191
|
const metaSymbol = ref(" ");
|
|
@@ -214,4 +218,5 @@ export const USE_SHORTCUTS = `export const _useShortcuts = () => {
|
|
|
214
218
|
};
|
|
215
219
|
|
|
216
220
|
export const useShortcuts = createSharedComposable(_useShortcuts);
|
|
221
|
+
|
|
217
222
|
`;
|
|
@@ -17,7 +17,13 @@ module.exports = {
|
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
fontFamily: {
|
|
20
|
-
sans: [
|
|
20
|
+
sans: [
|
|
21
|
+
\`Inter, \${fontFamily.sans.join(", ")}\`,
|
|
22
|
+
{
|
|
23
|
+
fontFeatureSettings: '"cv02","cv03","cv04","cv11"',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
mono: ["'Fira Code'", ...fontFamily.mono],
|
|
21
27
|
},
|
|
22
28
|
borderRadius: {
|
|
23
29
|
lg: "var(--radius)",
|
|
@@ -25,6 +31,27 @@ module.exports = {
|
|
|
25
31
|
sm: "calc(var(--radius) - 4px)",
|
|
26
32
|
},
|
|
27
33
|
keyframes: {
|
|
34
|
+
shine: {
|
|
35
|
+
from: { backgroundPosition: "200% 0" },
|
|
36
|
+
to: { backgroundPosition: "-200% 0" },
|
|
37
|
+
},
|
|
38
|
+
meteor: {
|
|
39
|
+
"0%": { transform: "rotate(215deg) translateX(0)", opacity: 1 },
|
|
40
|
+
"70%": { opacity: 1 },
|
|
41
|
+
"100%": {
|
|
42
|
+
transform: "rotate(215deg) translateX(-500px)",
|
|
43
|
+
opacity: 0,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
grid: {
|
|
47
|
+
"0%": { transform: "translateY(-50%)" },
|
|
48
|
+
"100%": { transform: "translateY(0)" },
|
|
49
|
+
},
|
|
50
|
+
"border-beam": {
|
|
51
|
+
"100%": {
|
|
52
|
+
"offset-distance": "100%",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
28
55
|
"accordion-down": {
|
|
29
56
|
from: { height: "0px" },
|
|
30
57
|
to: { height: "var(--radix-accordion-content-height)" },
|
|
@@ -51,6 +78,9 @@ module.exports = {
|
|
|
51
78
|
},
|
|
52
79
|
},
|
|
53
80
|
animation: {
|
|
81
|
+
shine: "shine 8s ease-in-out infinite",
|
|
82
|
+
meteor: "meteor 5s linear infinite",
|
|
83
|
+
grid: "grid 15s linear infinite",
|
|
54
84
|
"accordion-down": "accordion-down 0.2s ease-out",
|
|
55
85
|
"accordion-up": "accordion-up 0.2s ease-out",
|
|
56
86
|
fadeIn: "fadeIn 0.2s ease-out",
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type UIConfig = {
|
|
2
|
+
nuxtVersion?: number;
|
|
2
3
|
theme: string;
|
|
3
4
|
tailwindCSSLocation: string;
|
|
4
5
|
tailwindConfigLocation: string;
|
|
@@ -11,7 +12,7 @@ export type UIConfig = {
|
|
|
11
12
|
packageManager: string;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
export type InitOptions = { force?: boolean; yes?: boolean };
|
|
15
|
+
export type InitOptions = { force?: boolean; yes?: boolean; nuxtVersion?: number };
|
|
15
16
|
|
|
16
17
|
export type Component = {
|
|
17
18
|
name: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import { $ } from "execa";
|
|
2
3
|
import fse from "fs-extra";
|
|
3
4
|
import ora from "ora";
|
|
@@ -6,7 +7,8 @@ import prompts from "prompts";
|
|
|
6
7
|
import { PRETTIER_CONFIG } from "../templates/prettier";
|
|
7
8
|
|
|
8
9
|
export const addPrettierConfig = async (cwd = process.cwd(), format: boolean = true) => {
|
|
9
|
-
|
|
10
|
+
const prettierLocation = join(cwd, ".prettierrc");
|
|
11
|
+
if (fse.existsSync(prettierLocation)) {
|
|
10
12
|
const res = await prompts({
|
|
11
13
|
name: "overwrite",
|
|
12
14
|
type: "confirm",
|
|
@@ -15,7 +17,7 @@ export const addPrettierConfig = async (cwd = process.cwd(), format: boolean = t
|
|
|
15
17
|
});
|
|
16
18
|
if (!res.overwrite) return false;
|
|
17
19
|
}
|
|
18
|
-
await fse.writeFile(
|
|
20
|
+
await fse.writeFile(prettierLocation, PRETTIER_CONFIG, "utf-8");
|
|
19
21
|
if (!format) return true;
|
|
20
22
|
const spinner = ora("Formatting files with prettier...").start();
|
|
21
23
|
await $`npx prettier --write .`;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import fse from "fs-extra";
|
|
2
3
|
|
|
3
4
|
import { DEFINE_SHORTCUT, USE_SHORTCUTS } from "../templates/shortcuts";
|
|
5
|
+
import { UIConfig } from "../types";
|
|
6
|
+
import { getUIConfig } from "./config";
|
|
4
7
|
|
|
5
8
|
export const addShortcutFiles = async (cwd = process.cwd()) => {
|
|
9
|
+
// get config
|
|
10
|
+
let userConfig: UIConfig = await getUIConfig();
|
|
11
|
+
const composablesLocation = join(cwd, userConfig.composablesLocation);
|
|
6
12
|
// ensure that the composable folder exists
|
|
7
|
-
await fse.ensureDir(
|
|
13
|
+
await fse.ensureDir(composablesLocation);
|
|
8
14
|
// write the defineShortcuts composable
|
|
9
|
-
await fse.writeFile(
|
|
15
|
+
await fse.writeFile(join(composablesLocation, "defineShortcuts.ts"), DEFINE_SHORTCUT, "utf-8");
|
|
10
16
|
// write the useShortcuts composable
|
|
11
|
-
await fse.writeFile(
|
|
17
|
+
await fse.writeFile(join(composablesLocation, "useShortcuts.ts"), USE_SHORTCUTS, "utf-8");
|
|
12
18
|
};
|
package/src/utils/config.ts
CHANGED
|
@@ -8,11 +8,12 @@ import { addNuxtModule, getDefaultExportOptions } from "magicast/helpers";
|
|
|
8
8
|
import prompts from "prompts";
|
|
9
9
|
|
|
10
10
|
import { InitOptions, UIConfig } from "../types";
|
|
11
|
-
import { initPrompts } from "./uiConfigPrompt";
|
|
11
|
+
import { initPrompts, promptForNuxtVersion } from "./uiConfigPrompt";
|
|
12
12
|
|
|
13
13
|
const currentDir = process.cwd();
|
|
14
14
|
const uiConfigFilename = "ui-thing.config.ts";
|
|
15
|
-
const defaultConfig = {
|
|
15
|
+
const defaultConfig: UIConfig = {
|
|
16
|
+
nuxtVersion: 3,
|
|
16
17
|
theme: "zinc",
|
|
17
18
|
tailwindCSSLocation: "assets/css/tailwind.css",
|
|
18
19
|
tailwindConfigLocation: "tailwind.config.js",
|
|
@@ -24,6 +25,19 @@ const defaultConfig = {
|
|
|
24
25
|
useDefaultFilename: true,
|
|
25
26
|
packageManager: "npm",
|
|
26
27
|
};
|
|
28
|
+
const defaultNuxt4Config: UIConfig = {
|
|
29
|
+
nuxtVersion: 4,
|
|
30
|
+
theme: "zinc",
|
|
31
|
+
tailwindCSSLocation: "app/assets/css/tailwind.css",
|
|
32
|
+
tailwindConfigLocation: "tailwind.config.js",
|
|
33
|
+
componentsLocation: "app/components/Ui",
|
|
34
|
+
composablesLocation: "app/composables",
|
|
35
|
+
pluginsLocation: "app/plugins",
|
|
36
|
+
utilsLocation: "app/utils",
|
|
37
|
+
force: true,
|
|
38
|
+
useDefaultFilename: true,
|
|
39
|
+
packageManager: "npm",
|
|
40
|
+
};
|
|
27
41
|
|
|
28
42
|
export const getNuxtConfig = async () => {
|
|
29
43
|
if (!fse.existsSync("nuxt.config.ts")) {
|
|
@@ -38,11 +52,15 @@ export const getNuxtConfig = async () => {
|
|
|
38
52
|
export const getUIConfig = async (options?: InitOptions) => {
|
|
39
53
|
const configFileExists = fse.existsSync(uiConfigFilename);
|
|
40
54
|
let uiConfig: UIConfig = {} as UIConfig;
|
|
55
|
+
let nuxtVersion = Number(options?.nuxtVersion);
|
|
41
56
|
|
|
42
57
|
if (!configFileExists || options?.force) {
|
|
58
|
+
if (!nuxtVersion) {
|
|
59
|
+
nuxtVersion = await promptForNuxtVersion();
|
|
60
|
+
}
|
|
43
61
|
// if option yes is passed, use default values
|
|
44
62
|
if (options?.yes) {
|
|
45
|
-
uiConfig = defaultConfig;
|
|
63
|
+
uiConfig = Number(nuxtVersion) === 4 ? defaultNuxt4Config : defaultConfig;
|
|
46
64
|
} else {
|
|
47
65
|
uiConfig = await initPrompts();
|
|
48
66
|
}
|
package/src/utils/constants.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const INIT_DEPS = ["radix-vue", "tailwind-variants"];
|
|
1
|
+
export const INIT_DEPS = ["radix-vue", "tailwind-variants", "@nuxt/fonts"];
|
|
2
2
|
export const INIT_DEV_DEPS = [
|
|
3
3
|
"typescript",
|
|
4
4
|
"tailwindcss-animate",
|
|
@@ -17,6 +17,19 @@ export const INIT_MODULES = [
|
|
|
17
17
|
"@nuxtjs/color-mode",
|
|
18
18
|
"@vueuse/nuxt",
|
|
19
19
|
"@nuxt/icon",
|
|
20
|
+
"@nuxt/fonts",
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export const NUXT_VERSIONS = [
|
|
24
|
+
{ title: "Nuxt 3", value: 3 },
|
|
25
|
+
{ title: "Nuxt 4", value: 4 },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export const PACKAGE_MANAGER_CHOICES = [
|
|
29
|
+
{ title: "NPM", value: "npm" },
|
|
30
|
+
{ title: "YARN", value: "yarn" },
|
|
31
|
+
{ title: "PNPM", value: "pnpm" },
|
|
32
|
+
{ title: "BUN", value: "bun" },
|
|
20
33
|
];
|
|
21
34
|
|
|
22
35
|
export const CSS_THEME_OPTIONS = [
|