@xleddyl/nuxt-cms 0.1.13 → 0.1.15
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/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/app/components/cms/ConfirmModal.vue +1 -1
- package/dist/runtime/app/components/cms/FieldInput.vue +10 -9
- package/dist/runtime/app/components/cms/FormField.vue +2 -2
- package/dist/runtime/app/components/cms/Icon.vue +1 -1
- package/dist/runtime/app/components/cms/JsonField.vue +1 -1
- package/dist/runtime/app/components/cms/MediaField.vue +2 -2
- package/dist/runtime/app/components/cms/MediaGallery.vue +5 -5
- package/dist/runtime/app/components/cms/MediaUpload.vue +1 -1
- package/dist/runtime/app/components/cms/SelectMenu.d.vue.ts +1 -0
- package/dist/runtime/app/components/cms/SelectMenu.vue +38 -9
- package/dist/runtime/app/components/cms/SelectMenu.vue.d.ts +1 -0
- package/dist/runtime/app/components/cms/Toaster.vue +2 -2
- package/dist/runtime/app/components/cms/TranslatableField.vue +1 -1
- package/dist/runtime/app/layouts/cms-admin.vue +1 -1
- package/dist/runtime/app/utils/ui.js +2 -2
- package/dist/runtime/assets/main.css +1 -1
- package/dist/runtime/generate.d.ts +5 -0
- package/dist/runtime/generate.js +22 -0
- package/dist/runtime/seed.d.ts +27 -0
- package/dist/runtime/seed.js +44 -0
- package/package.json +9 -1
- package/dist/runtime/app/components/cms/Select.d.vue.ts +0 -16
- package/dist/runtime/app/components/cms/Select.vue +0 -19
- package/dist/runtime/app/components/cms/Select.vue.d.ts +0 -16
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -557,7 +557,7 @@ const module$1 = defineNuxtModule({
|
|
|
557
557
|
` dialect: '${dialect}',`,
|
|
558
558
|
` schema: '${toPosix(schemaTemplate.dst)}',`,
|
|
559
559
|
` out: '${toPosix(migrationsDir)}',`,
|
|
560
|
-
driver === "postgres" ? ` dbCredentials: { url: process.env.NUXT_CMS_DATABASE_URL ?? '${databaseUrl}' },` : driver === "libsql" ? ` dbCredentials: { url: process.env.NUXT_CMS_DATABASE_URL ?? '${databaseUrl || `file:${toPosix(resolvedDbPath)}`}', authToken: process.env.NUXT_CMS_DATABASE_AUTH_TOKEN ?? '${databaseAuthToken}' || undefined },` : ` dbCredentials: { url: '${toPosix(resolvedDbPath)}' },`,
|
|
560
|
+
driver === "postgres" ? ` dbCredentials: { url: process.env.NUXT_CMS_DATABASE_URL ?? '${databaseUrl}' },` : driver === "libsql" ? ` dbCredentials: { url: process.env.NUXT_CMS_DATABASE_URL ?? '${databaseUrl || `file:${toPosix(resolvedDbPath)}`}', authToken: (process.env.NUXT_CMS_DATABASE_AUTH_TOKEN ?? '${databaseAuthToken}') || undefined },` : ` dbCredentials: { url: '${toPosix(resolvedDbPath)}' },`,
|
|
561
561
|
`}`,
|
|
562
562
|
``
|
|
563
563
|
].join("\n")
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
import { useCmsConfirmState } from "../../composables/cms-confirm";
|
|
33
33
|
import { CMS_MODAL_UI } from "../../utils/ui";
|
|
34
34
|
const state = useCmsConfirmState();
|
|
35
|
-
const ui = { ...CMS_MODAL_UI, content: "rounded-2xl
|
|
35
|
+
const ui = { ...CMS_MODAL_UI, content: "rounded-2xl sm:max-w-md" };
|
|
36
36
|
function finish(value) {
|
|
37
37
|
const resolve = state.value.resolve;
|
|
38
38
|
if (!resolve) return;
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
class="w-full"
|
|
19
19
|
/>
|
|
20
20
|
<CmsSlugField v-else-if="field.type === 'slug'" v-model="strOrNull" :source="slugSource" />
|
|
21
|
-
<
|
|
21
|
+
<CmsSelectMenu
|
|
22
22
|
v-else-if="field.type === 'select'"
|
|
23
|
-
v-model="
|
|
24
|
-
:items="
|
|
25
|
-
|
|
23
|
+
v-model="selValue"
|
|
24
|
+
:items="selectItems"
|
|
25
|
+
placeholder="Select…"
|
|
26
26
|
size="lg"
|
|
27
27
|
class="w-full"
|
|
28
28
|
/>
|
|
@@ -57,11 +57,15 @@
|
|
|
57
57
|
<script setup>
|
|
58
58
|
import { isTranslatableField } from "#nuxt-cms";
|
|
59
59
|
import { computed } from "#imports";
|
|
60
|
-
defineProps({
|
|
60
|
+
const props = defineProps({
|
|
61
61
|
field: { type: Object, required: true },
|
|
62
62
|
slugSource: { type: [String, null], required: false }
|
|
63
63
|
});
|
|
64
64
|
const model = defineModel({ type: null, ...{ required: true } });
|
|
65
|
+
const selectItems = computed(() => [
|
|
66
|
+
...props.field.required ? [] : [{ label: "\u2014", value: null }],
|
|
67
|
+
...(props.field.options ?? []).map((option) => ({ label: option, value: option }))
|
|
68
|
+
]);
|
|
65
69
|
function proxy(fromModel, toModel = (v) => v) {
|
|
66
70
|
return computed({
|
|
67
71
|
get: () => fromModel(model.value),
|
|
@@ -75,10 +79,7 @@ const str = proxy(
|
|
|
75
79
|
(v) => v === "" ? null : v
|
|
76
80
|
);
|
|
77
81
|
const strOrNull = proxy((v) => v);
|
|
78
|
-
const
|
|
79
|
-
(v) => v ?? void 0,
|
|
80
|
-
(v) => v ?? null
|
|
81
|
-
);
|
|
82
|
+
const selValue = proxy((v) => v ?? null);
|
|
82
83
|
const num = proxy(
|
|
83
84
|
(v) => v ?? void 0,
|
|
84
85
|
(v) => typeof v === "number" && !Number.isNaN(v) ? v : null
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="flex flex-col gap-1.5">
|
|
3
|
-
<label v-if="label" :class="ui?.label ?? 'text-
|
|
3
|
+
<label v-if="label" :class="ui?.label ?? 'text-sm font-medium text-(--ui-text-toned)'">
|
|
4
4
|
{{ label }}<span v-if="required" class="text-(--ui-error)"> *</span>
|
|
5
5
|
</label>
|
|
6
6
|
<slot />
|
|
7
|
-
<p v-if="error" class="text-
|
|
7
|
+
<p v-if="error" class="text-sm text-(--ui-error)">{{ error }}</p>
|
|
8
8
|
</div>
|
|
9
9
|
</template>
|
|
10
10
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
/>
|
|
17
17
|
<div class="flex items-center gap-2.5 px-4 py-3">
|
|
18
18
|
<CmsIcon :name="icon" class="size-4 shrink-0 text-(--ui-text-dimmed)" />
|
|
19
|
-
<span class="min-w-0 flex-1 truncate text-
|
|
19
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium" :title="model">{{
|
|
20
20
|
mediaFilename(model)
|
|
21
21
|
}}</span>
|
|
22
22
|
<CmsButton
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
<button v-else type="button" class="cms-dropzone is-dense" @click="openGallery">
|
|
44
44
|
<CmsIcon name="photo" class="size-5 shrink-0" />
|
|
45
|
-
<span class="text-
|
|
45
|
+
<span class="text-sm font-medium">Choose from the gallery</span>
|
|
46
46
|
</button>
|
|
47
47
|
|
|
48
48
|
<CmsModal v-model:open="galleryOpen" title="Media" :ui="CMS_MODAL_UI">
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
:type="selectable ? 'button' : void 0"
|
|
60
60
|
class="cms-card group overflow-hidden text-left"
|
|
61
61
|
:class="{
|
|
62
|
-
'hover:border-(--cms-
|
|
62
|
+
'hover:border-(--cms-line-strong)': selectable
|
|
63
63
|
}"
|
|
64
64
|
@click="selectable && emit('select', { key: item.key, url: item.url })"
|
|
65
65
|
>
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
size="xs"
|
|
94
94
|
color="neutral"
|
|
95
95
|
variant="solid"
|
|
96
|
-
class="rounded-full
|
|
96
|
+
class="rounded-full"
|
|
97
97
|
aria-label="Edit details"
|
|
98
98
|
@click="openEdit(item)"
|
|
99
99
|
/>
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
size="xs"
|
|
103
103
|
color="neutral"
|
|
104
104
|
variant="solid"
|
|
105
|
-
class="rounded-full
|
|
105
|
+
class="rounded-full"
|
|
106
106
|
aria-label="Copy URL"
|
|
107
107
|
@click="copy(item)"
|
|
108
108
|
/>
|
|
@@ -111,14 +111,14 @@
|
|
|
111
111
|
size="xs"
|
|
112
112
|
color="error"
|
|
113
113
|
variant="solid"
|
|
114
|
-
class="rounded-full
|
|
114
|
+
class="rounded-full"
|
|
115
115
|
aria-label="Delete"
|
|
116
116
|
@click="remove(item)"
|
|
117
117
|
/>
|
|
118
118
|
</div>
|
|
119
119
|
</div>
|
|
120
120
|
<div class="flex flex-col gap-1 px-3.5 py-2.5">
|
|
121
|
-
<div class="truncate text-
|
|
121
|
+
<div class="truncate text-sm font-medium" :title="item.key">
|
|
122
122
|
{{ mediaFilename(item.key) }}
|
|
123
123
|
</div>
|
|
124
124
|
<div class="cms-kicker">
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
class="size-5 shrink-0"
|
|
24
24
|
:class="{ 'animate-spin': uploading }"
|
|
25
25
|
/>
|
|
26
|
-
<span class="text-
|
|
26
|
+
<span class="text-sm font-medium">
|
|
27
27
|
{{
|
|
28
28
|
uploading ? `Uploading ${Math.min(done + 1, total)} of ${total}\u2026` : multiple ? "Drop files here or click to browse" : "Drop a file here or click to browse"
|
|
29
29
|
}}
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
</template>
|
|
16
16
|
<input
|
|
17
17
|
ref="input"
|
|
18
|
-
class="min-w-16 flex-1 bg-transparent outline-none"
|
|
19
|
-
:value="
|
|
18
|
+
class="min-w-16 flex-1 bg-transparent text-(--ui-text-highlighted) outline-none"
|
|
19
|
+
:value="displayValue"
|
|
20
20
|
:placeholder="placeholder"
|
|
21
|
-
@input="
|
|
22
|
-
@focus="
|
|
21
|
+
@input="onInput"
|
|
22
|
+
@focus="onFocus"
|
|
23
23
|
/>
|
|
24
24
|
<CmsIcon
|
|
25
25
|
v-if="loading"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
</div>
|
|
30
30
|
<div v-if="open" class="cms-selectmenu-panel">
|
|
31
31
|
<button
|
|
32
|
-
v-for="item in
|
|
32
|
+
v-for="item in visibleItems"
|
|
33
33
|
:key="String(item[valueKey])"
|
|
34
34
|
type="button"
|
|
35
35
|
class="cms-menu-item"
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
>
|
|
38
38
|
<span class="truncate">{{ item.label }}</span>
|
|
39
39
|
<CmsIcon
|
|
40
|
-
v-if="isSelected(item[valueKey])"
|
|
40
|
+
v-if="!multiple && isSelected(item[valueKey])"
|
|
41
41
|
name="check"
|
|
42
42
|
class="cms-menu-check size-3.5"
|
|
43
43
|
/>
|
|
44
44
|
</button>
|
|
45
|
-
<div v-if="!
|
|
45
|
+
<div v-if="!visibleItems.length" class="cms-menu-item pointer-events-none opacity-60">
|
|
46
46
|
No results
|
|
47
47
|
</div>
|
|
48
48
|
</div>
|
|
@@ -57,7 +57,8 @@ const props = defineProps({
|
|
|
57
57
|
multiple: { type: Boolean, required: false },
|
|
58
58
|
ignoreFilter: { type: Boolean, required: false },
|
|
59
59
|
loading: { type: Boolean, required: false },
|
|
60
|
-
size: { type: String, required: false }
|
|
60
|
+
size: { type: String, required: false },
|
|
61
|
+
placeholder: { type: String, required: false }
|
|
61
62
|
});
|
|
62
63
|
const model = defineModel({ type: [String, Array, null] });
|
|
63
64
|
const search = defineModel("searchTerm", { type: String, ...{ default: "" } });
|
|
@@ -72,7 +73,33 @@ const selectedLabel = computed(() => {
|
|
|
72
73
|
const current = model.value;
|
|
73
74
|
return current == null ? "" : labelFor(current);
|
|
74
75
|
});
|
|
75
|
-
const placeholder = computed(() =>
|
|
76
|
+
const placeholder = computed(() => {
|
|
77
|
+
if (props.multiple) return modelArray.value.length ? "" : props.placeholder ?? "";
|
|
78
|
+
return selectedLabel.value || props.placeholder || "";
|
|
79
|
+
});
|
|
80
|
+
const displayValue = computed(() => {
|
|
81
|
+
if (props.multiple) return search.value;
|
|
82
|
+
return open.value ? search.value : selectedLabel.value;
|
|
83
|
+
});
|
|
84
|
+
function onInput(event) {
|
|
85
|
+
search.value = event.target.value;
|
|
86
|
+
open.value = true;
|
|
87
|
+
}
|
|
88
|
+
function onFocus() {
|
|
89
|
+
if (!props.multiple) search.value = "";
|
|
90
|
+
open.value = true;
|
|
91
|
+
}
|
|
92
|
+
const visibleItems = computed(() => {
|
|
93
|
+
let list = props.items;
|
|
94
|
+
if (!props.ignoreFilter) {
|
|
95
|
+
const query = search.value.trim().toLowerCase();
|
|
96
|
+
if (query) list = list.filter((item) => item.label.toLowerCase().includes(query));
|
|
97
|
+
}
|
|
98
|
+
if (props.multiple) {
|
|
99
|
+
list = list.filter((item) => !modelArray.value.includes(item[props.valueKey]));
|
|
100
|
+
}
|
|
101
|
+
return list;
|
|
102
|
+
});
|
|
76
103
|
function labelFor(value) {
|
|
77
104
|
return props.items.find((item) => item[props.valueKey] === value)?.label ?? `#${value}`;
|
|
78
105
|
}
|
|
@@ -90,6 +117,8 @@ function pick(item) {
|
|
|
90
117
|
const value = item[props.valueKey];
|
|
91
118
|
if (props.multiple) {
|
|
92
119
|
if (value != null) toggle(value);
|
|
120
|
+
search.value = "";
|
|
121
|
+
focusInput();
|
|
93
122
|
} else {
|
|
94
123
|
model.value = value;
|
|
95
124
|
search.value = "";
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
>
|
|
14
14
|
<div class="flex items-start gap-3">
|
|
15
15
|
<div class="min-w-0 flex-1">
|
|
16
|
-
<p class="text-
|
|
16
|
+
<p class="text-sm font-medium text-(--ui-text-highlighted)">
|
|
17
17
|
{{ toast.title }}
|
|
18
18
|
</p>
|
|
19
|
-
<p v-if="toast.description" class="mt-0.5 text-
|
|
19
|
+
<p v-if="toast.description" class="mt-0.5 text-sm text-(--ui-text-muted)">
|
|
20
20
|
{{ toast.description }}
|
|
21
21
|
</p>
|
|
22
22
|
</div>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</nav>
|
|
34
34
|
|
|
35
35
|
<div class="flex flex-col gap-3 border-t border-(--cms-line) px-3 pt-5">
|
|
36
|
-
<div class="truncate text-
|
|
36
|
+
<div class="truncate text-sm font-medium text-(--ui-text-muted)">
|
|
37
37
|
{{ user?.email }}
|
|
38
38
|
</div>
|
|
39
39
|
<CmsButton
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const CMS_FIELD_UI = { label: "text-
|
|
1
|
+
export const CMS_FIELD_UI = { label: "text-sm font-medium text-(--ui-text-toned)" };
|
|
2
2
|
export const CMS_MODAL_UI = {
|
|
3
|
-
content: "rounded-2xl
|
|
3
|
+
content: "rounded-2xl sm:max-w-3xl",
|
|
4
4
|
title: "cms-display text-xl font-medium text-(--ui-text-highlighted)"
|
|
5
5
|
};
|
|
6
6
|
export const CMS_FORM_ERRORS = Symbol("cms-form-errors");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&family=Hanken+Grotesk:ital,wght@0,300..800;1,300..800&family=Fragment+Mono:ital@0;1&display=swap");@layer theme, base, components, utilities;@import "tailwindcss/theme.css" layer(theme);.cms-scope{@import "tailwindcss/preflight.css" layer(base);@import "tailwindcss/utilities.css" layer(utilities) source(none)}@source "../app";.cms-scope,body:has(.cms-scope){--cms-paper:#f6f4ef;--cms-surface:#fdfcfa;--cms-field:#f1ede4;--cms-ink:#262119;--cms-line:#e8e3d8;--cms-line-strong:#d8d1c1;--cms-fern:#3e6b4f;--cms-sage:#e3ebe1;--cms-sage-ink:#2e5138;--cms-shadow-soft:0 1px 2px rgba(38,33,25,.05),0 16px 40px -24px rgba(38,33,25,.22);color-scheme:light;--ui-text-dimmed:#a69d8b;--ui-text-muted:#877e6c;--ui-text-toned:#60594a;--ui-text:#403a2f;--ui-text-highlighted:var(--cms-ink);--ui-text-inverted:#fffdf8;--ui-bg:var(--cms-surface);--ui-bg-muted:var(--cms-paper);--ui-bg-elevated:var(--cms-field);--ui-bg-accented:#e7e1d3;--ui-bg-inverted:var(--cms-ink);--ui-border:var(--cms-line);--ui-border-muted:var(--cms-line);--ui-border-accented:var(--cms-line-strong);--ui-border-inverted:var(--cms-ink);--ui-primary:var(--cms-fern);--ui-error:#b4442f;--ui-radius:0.4rem;color:var(--ui-text);font-family:Hanken Grotesk,ui-sans-serif,system-ui,sans-serif;margin:0;padding:0;-webkit-font-smoothing:antialiased}body:has(.cms-scope) ::-moz-selection{background:var(--cms-sage);color:var(--cms-sage-ink)}body:has(.cms-scope) ::selection{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-display{font-family:Poppins,ui-sans-serif,system-ui,sans-serif;letter-spacing:-.02em}.cms-kicker{color:var(--ui-text-dimmed);font-family:Fragment Mono,ui-monospace,monospace;font-size:.6875rem;letter-spacing:.16em;line-height:1.4;text-transform:uppercase}body:has(.cms-scope) :is(button,a,label,[role=button],[role=menuitem],[role=option],.__clickable):not(:disabled,[aria-disabled=true]){@apply cursor-pointer transition-all duration-200 select-none}body:has(.cms-scope) :is(button,a,label,[role=button],[role=menuitem],[role=option],.__clickable):not(:disabled,[aria-disabled=true]):active{@apply transition-none;scale:.99}.cms-canvas{background-attachment:fixed;background-color:var(--cms-paper);background-image:radial-gradient(50rem 34rem at 10% -10%,rgba(62,107,79,.07),transparent 62%),radial-gradient(44rem 30rem at 108% 112%,rgba(193,149,87,.09),transparent 62%)}.cms-grain:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='a'%3E%3CfeTurbulence baseFrequency='.8' numOctaves='2' stitchTiles='stitch' type='fractalNoise'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E");content:"";inset:0;mix-blend-mode:multiply;opacity:.035;pointer-events:none;position:fixed;z-index:50}.cms-card{background:var(--cms-surface);border:1px solid var(--cms-line);border-radius:1rem;box-shadow:var(--cms-shadow-soft)}.cms-empty{background:rgba(253,252,250,.5);border:1.5px dashed var(--cms-line-strong);border-radius:1rem}.cms-navlink{align-items:center;border-radius:.75rem;color:var(--ui-text-toned);display:flex;font-size:.875rem;font-weight:500;gap:.625rem;padding:.5rem .75rem;transition:background-color .15s ease,color .15s ease}.cms-navlink:hover{background:rgba(38,33,25,.05);color:var(--ui-text-highlighted)}.cms-navlink.is-active{background:var(--cms-sage);color:var(--cms-sage-ink);font-weight:600}.cms-navlink.is-active .cms-navlink-icon{color:var(--cms-fern)}.cms-badge{border:1px solid transparent;border-radius:9999px;cursor:pointer;font-family:Fragment Mono,ui-monospace,monospace;font-size:.625rem;letter-spacing:.12em;padding:.25rem .625rem;text-transform:uppercase;transition:background-color .15s ease,border-color .15s ease}.cms-badge.is-published{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-badge.is-published:hover{background:#d6e2d3}.cms-badge.is-draft{background:transparent;border:1px dashed var(--cms-line-strong);color:var(--ui-text-muted)}.cms-badge.is-draft:hover{background:rgba(38,33,25,.04)}.cms-dropzone{align-items:center;background:rgba(253,252,250,.5);border:1.5px dashed var(--cms-line-strong);border-radius:1rem;color:var(--ui-text-muted);cursor:pointer;display:flex;flex-direction:column;gap:.5rem;justify-content:center;padding:2rem 1.5rem;transition:border-color .15s ease,background-color .15s ease,color .15s ease;width:100%}.cms-dropzone.is-over,.cms-dropzone:hover{background:var(--cms-sage);border-color:var(--cms-fern);color:var(--cms-sage-ink)}.cms-dropzone.is-dense{border-radius:.75rem;flex-direction:row;gap:.625rem;padding:.875rem 1.25rem}.cms-dropzone.is-busy{opacity:.7;pointer-events:none}.cms-pill{background:var(--cms-surface);border:1px solid var(--cms-line);border-radius:9999px;color:var(--ui-text-dimmed);cursor:pointer;font-family:Fragment Mono,ui-monospace,monospace;font-size:.625rem;letter-spacing:.12em;padding:.3rem .8rem;transition:background-color .15s ease,color .15s ease}.cms-pill:hover{background:rgba(38,33,25,.05);color:var(--ui-text)}.cms-pill.is-active{background:var(--cms-sage);color:var(--cms-sage-ink)}@keyframes cms-rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}.cms-rise{animation:cms-rise .55s cubic-bezier(.22,1,.36,1) both}@media (prefers-reduced-motion:reduce){.cms-rise{animation:none}}.cms-richtext{border:1px solid var(--cms-line);border-radius:.75rem;overflow:hidden}.cms-richtext-toolbar{align-items:center;border-bottom:1px solid var(--cms-line);display:flex;flex-wrap:wrap;gap:2px;padding:4px}.cms-richtext-body{font-size:.875rem;min-height:9rem;outline:none;padding:.75rem 1rem}.cms-richtext-body h2{font-size:1.25rem;font-weight:600;margin:.75em 0 .35em}.cms-richtext-body h3{font-size:1.1rem;font-weight:600;margin:.75em 0 .35em}.cms-richtext-body p{margin:.35em 0}.cms-richtext-body ul{list-style:disc;padding-left:1.25rem}.cms-richtext-body ol{list-style:decimal;padding-left:1.25rem}.cms-richtext-body blockquote{border-left:3px solid var(--cms-line);color:var(--ui-text-muted);padding-left:.75rem}.cms-btn{align-items:center;border:1px solid transparent;border-radius:var(--ui-radius);display:inline-flex;font-weight:500;gap:.375rem;justify-content:center;line-height:1;transition:background-color .15s ease,border-color .15s ease,color .15s ease,opacity .15s ease;white-space:nowrap}.cms-btn:disabled,.cms-btn[aria-disabled=true]{opacity:.5;pointer-events:none}.cms-btn.is-block{width:100%}.cms-btn-xs{font-size:.75rem;padding:.25rem .5rem}.cms-btn-sm{font-size:.8125rem;padding:.375rem .625rem}.cms-btn-md{font-size:.875rem;padding:.5rem .875rem}.cms-btn-lg{font-size:.9375rem;padding:.625rem 1rem}.cms-btn-primary.cms-btn-solid{background:var(--ui-primary);color:var(--ui-text-inverted)}.cms-btn-primary.cms-btn-solid:hover{background:color-mix(in oklab,var(--ui-primary) 88%,#000)}.cms-btn-primary.cms-btn-subtle{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-btn-primary.cms-btn-subtle:hover{background:#d6e2d3}.cms-btn-primary.cms-btn-soft{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-btn-neutral.cms-btn-solid{background:var(--ui-bg-inverted);color:var(--ui-text-inverted)}.cms-btn-neutral.cms-btn-subtle{background:var(--ui-bg-elevated);color:var(--ui-text-highlighted)}.cms-btn-neutral.cms-btn-subtle:hover{background:var(--ui-bg-accented)}.cms-btn-neutral.cms-btn-soft{background:var(--ui-bg-elevated);color:var(--ui-text-highlighted)}.cms-btn-neutral.cms-btn-ghost{color:var(--ui-text-toned)}.cms-btn-neutral.cms-btn-ghost:hover{background:rgba(38,33,25,.06);color:var(--ui-text-highlighted)}.cms-btn-error.cms-btn-solid{background:var(--ui-error);color:#fff}.cms-btn-error.cms-btn-solid:hover{background:color-mix(in oklab,var(--ui-error) 88%,#000)}.cms-btn-error.cms-btn-subtle{background:color-mix(in oklab,var(--ui-error) 12%,transparent);color:var(--ui-error)}.cms-btn-error.cms-btn-ghost{color:var(--ui-error)}.cms-btn-error.cms-btn-ghost:hover{background:color-mix(in oklab,var(--ui-error) 10%,transparent)}.cms-btn-success.cms-btn-solid{background:var(--cms-fern);color:var(--ui-text-inverted)}.cms-field{background:var(--ui-bg);border:1px solid var(--cms-line-strong);border-radius:var(--ui-radius);color:var(--ui-text-highlighted);transition:border-color .15s ease,box-shadow .15s ease;width:100%}.cms-field::-moz-placeholder{color:var(--ui-text-dimmed)}.cms-field::placeholder{color:var(--ui-text-dimmed)}.cms-field:focus,.cms-field:focus-within{border-color:var(--ui-primary);box-shadow:0 0 0 3px color-mix(in oklab,var(--ui-primary) 18%,transparent);outline:none}.cms-field.is-error{border-color:var(--ui-error)}.cms-field-sm{font-size:.8125rem;padding:.375rem .625rem}.cms-field-md{font-size:.875rem;padding:.5rem .75rem}.cms-field-lg{font-size:.9375rem;padding:.625rem .875rem}.cms-input-wrap{align-items:center;display:flex;position:relative}.cms-input-wrap .cms-field{width:100%}.cms-input-lead,.cms-input-trail{align-items:center;color:var(--ui-text-dimmed);display:flex;position:absolute}.cms-input-lead{left:.625rem}.cms-input-trail{right:.375rem}.cms-input-wrap.has-lead .cms-field{padding-left:2rem}.cms-switch{align-items:center;background:var(--cms-line-strong);border-radius:9999px;display:inline-flex;flex-shrink:0;height:1.25rem;position:relative;transition:background-color .15s ease;width:2.25rem}.cms-switch.is-on{background:var(--ui-primary)}.cms-switch:after{background:#fff;border-radius:9999px;content:"";height:.875rem;left:.1875rem;position:absolute;transition:transform .15s ease;width:.875rem}.cms-switch.is-on:after{transform:translateX(1rem)}.cms-overlay{align-items:flex-start;backdrop-filter:blur(2px);background:rgba(38,33,25,.32);display:flex;inset:0;justify-content:center;overflow-y:auto;padding:4rem 1rem 2rem;position:fixed;z-index:60}.cms-modal{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:1rem;box-shadow:var(--cms-shadow-soft);max-width:32rem;width:100%}.cms-modal-header{padding:1.25rem 1.5rem 0}.cms-modal-body{padding:1.25rem 1.5rem 1.5rem}.cms-menu{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:.75rem;box-shadow:var(--cms-shadow-soft);margin-top:.375rem;min-width:11rem;padding:.25rem;position:absolute;z-index:50}.cms-menu.align-end{right:0}.cms-menu-item{align-items:center;border-radius:.5rem;color:var(--ui-text);cursor:pointer;display:flex;font-size:.8125rem;gap:.5rem;padding:.4rem .6rem;text-align:left;width:100%}.cms-menu-item:hover{background:var(--ui-bg-elevated)}.cms-menu-check{color:var(--ui-primary);margin-left:auto}.cms-popover,.cms-selectmenu-panel{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:.75rem;box-shadow:var(--cms-shadow-soft);margin-top:.375rem;position:absolute;z-index:50}.cms-selectmenu-panel{left:0;max-height:15rem;overflow-y:auto;padding:.25rem;right:0}.cms-tag{align-items:center;background:var(--ui-bg-elevated);border-radius:9999px;display:inline-flex;font-size:.75rem;gap:.25rem;padding:.125rem .5rem}.cms-table{border-collapse:collapse;text-align:left;width:100%}.cms-alert{border-radius:.75rem;font-size:.8125rem;padding:.75rem 1rem}.cms-alert-error{background:color-mix(in oklab,var(--ui-error) 10%,transparent);color:var(--ui-error)}.cms-toaster{bottom:1rem;display:flex;flex-direction:column;gap:.5rem;max-width:calc(100vw - 2rem);position:fixed;right:1rem;width:20rem;z-index:80}.cms-toast{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:.75rem;box-shadow:var(--cms-shadow-soft);padding:.75rem .875rem}.cms-toast.is-success{border-left:3px solid var(--cms-fern)}.cms-toast.is-error{border-left:3px solid var(--ui-error)}.cms-pagination{align-items:center;display:flex;gap:.25rem}.cms-page-btn{border-radius:.5rem;color:var(--ui-text-toned);font-size:.8125rem;height:2rem;min-width:2rem;padding:0 .5rem}.cms-page-btn:hover:not(:disabled){background:var(--ui-bg-elevated)}.cms-page-btn.is-active{background:var(--cms-sage);color:var(--cms-sage-ink);font-weight:600}.cms-page-btn:disabled{opacity:.4}
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&family=Hanken+Grotesk:ital,wght@0,300..800;1,300..800&family=Fragment+Mono:ital@0;1&display=swap");@layer theme, base, components, utilities;@import "tailwindcss/theme.css" layer(theme);.cms-scope{@import "tailwindcss/preflight.css" layer(base);@import "tailwindcss/utilities.css" layer(utilities) source(none)}@source "../app";.cms-scope,body:has(.cms-scope){--cms-paper:#f5f5f5;--cms-surface:#fff;--cms-field:#f0f0f0;--cms-ink:#171717;--cms-line:#e5e5e5;--cms-line-strong:#d4d4d4;--cms-fern:#171717;--cms-sage:#ebebeb;--cms-sage-ink:#171717;--cms-shadow-soft:none;color-scheme:light;--ui-text-dimmed:#a3a3a3;--ui-text-muted:#737373;--ui-text-toned:#525252;--ui-text:#404040;--ui-text-highlighted:var(--cms-ink);--ui-text-inverted:#fff;--ui-bg:var(--cms-surface);--ui-bg-muted:var(--cms-paper);--ui-bg-elevated:var(--cms-field);--ui-bg-accented:#e0e0e0;--ui-bg-inverted:var(--cms-ink);--ui-border:var(--cms-line);--ui-border-muted:var(--cms-line);--ui-border-accented:var(--cms-line-strong);--ui-border-inverted:var(--cms-ink);--ui-primary:var(--cms-ink);--ui-error:#dc2626;--ui-radius:0.4rem;color:var(--ui-text);font-family:Hanken Grotesk,ui-sans-serif,system-ui,sans-serif;margin:0;padding:0;-webkit-font-smoothing:antialiased}body:has(.cms-scope) ::-moz-selection{background:var(--cms-sage);color:var(--cms-sage-ink)}body:has(.cms-scope) ::selection{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-display{font-family:Poppins,ui-sans-serif,system-ui,sans-serif;letter-spacing:-.02em}.cms-kicker{color:var(--ui-text-dimmed);font-family:Fragment Mono,ui-monospace,monospace;font-size:.875rem;letter-spacing:.16em;line-height:1.4;text-transform:uppercase}body:has(.cms-scope) :is(button,a,[role=button],[role=menuitem],[role=option],.__clickable):not(:disabled,[aria-disabled=true]){@apply cursor-pointer transition-all duration-200 select-none}body:has(.cms-scope) :is(button,a,[role=button],[role=menuitem],[role=option],.__clickable):not(:disabled,[aria-disabled=true]):active{@apply transition-none;scale:.99}.cms-canvas{background-color:var(--cms-paper)}.cms-grain:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='a'%3E%3CfeTurbulence baseFrequency='.8' numOctaves='2' stitchTiles='stitch' type='fractalNoise'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E");content:"";inset:0;mix-blend-mode:multiply;opacity:.035;pointer-events:none;position:fixed;z-index:50}.cms-card{background:var(--cms-surface);border:1px solid var(--cms-line);border-radius:1rem;box-shadow:var(--cms-shadow-soft)}.cms-empty{background:rgba(253,252,250,.5);border:1.5px dashed var(--cms-line-strong);border-radius:1rem}.cms-navlink{align-items:center;border-radius:.75rem;color:var(--ui-text-toned);display:flex;font-size:.875rem;font-weight:500;gap:.625rem;padding:.5rem .75rem;transition:background-color .15s ease,color .15s ease}.cms-navlink:hover{background:rgba(38,33,25,.05);color:var(--ui-text-highlighted)}.cms-navlink.is-active{background:var(--cms-sage);color:var(--cms-sage-ink);font-weight:600}.cms-navlink.is-active .cms-navlink-icon{color:var(--cms-fern)}.cms-badge{border:1px solid transparent;border-radius:9999px;cursor:pointer;font-family:Fragment Mono,ui-monospace,monospace;font-size:.875rem;letter-spacing:.12em;padding:.25rem .625rem;text-transform:uppercase;transition:background-color .15s ease,border-color .15s ease}.cms-badge.is-published{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-badge.is-published:hover{background:#e0e0e0}.cms-badge.is-draft{background:transparent;border:1px dashed var(--cms-line-strong);color:var(--ui-text-muted)}.cms-badge.is-draft:hover{background:rgba(38,33,25,.04)}.cms-dropzone{align-items:center;background:rgba(253,252,250,.5);border:1.5px dashed var(--cms-line-strong);border-radius:1rem;color:var(--ui-text-muted);cursor:pointer;display:flex;flex-direction:column;gap:.5rem;justify-content:center;padding:2rem 1.5rem;transition:border-color .15s ease,background-color .15s ease,color .15s ease;width:100%}.cms-dropzone.is-over,.cms-dropzone:hover{background:var(--cms-sage);border-color:var(--cms-fern);color:var(--cms-sage-ink)}.cms-dropzone.is-dense{border-radius:.75rem;flex-direction:row;gap:.625rem;padding:.875rem 1.25rem}.cms-dropzone.is-busy{opacity:.7;pointer-events:none}.cms-pill{background:var(--cms-surface);border:1px solid var(--cms-line);border-radius:9999px;color:var(--ui-text-dimmed);cursor:pointer;font-family:Fragment Mono,ui-monospace,monospace;font-size:.875rem;letter-spacing:.12em;padding:.3rem .8rem;transition:background-color .15s ease,color .15s ease}.cms-pill:hover{background:rgba(38,33,25,.05);color:var(--ui-text)}.cms-pill.is-active{background:var(--cms-sage);color:var(--cms-sage-ink)}@keyframes cms-rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}.cms-rise{animation:cms-rise .55s cubic-bezier(.22,1,.36,1) both}@media (prefers-reduced-motion:reduce){.cms-rise{animation:none}}.cms-richtext{border:1px solid var(--cms-line);border-radius:.75rem;overflow:hidden}.cms-richtext-toolbar{align-items:center;border-bottom:1px solid var(--cms-line);display:flex;flex-wrap:wrap;gap:2px;padding:4px}.cms-richtext-body{font-size:.875rem;min-height:9rem;outline:none;padding:.75rem 1rem}.cms-richtext-body h2{font-size:1.25rem;font-weight:600;margin:.75em 0 .35em}.cms-richtext-body h3{font-size:1.1rem;font-weight:600;margin:.75em 0 .35em}.cms-richtext-body p{margin:.35em 0}.cms-richtext-body ul{list-style:disc;padding-left:1.25rem}.cms-richtext-body ol{list-style:decimal;padding-left:1.25rem}.cms-richtext-body blockquote{border-left:3px solid var(--cms-line);color:var(--ui-text-muted);padding-left:.75rem}.cms-btn{align-items:center;border:1px solid transparent;border-radius:var(--ui-radius);display:inline-flex;font-weight:500;gap:.375rem;justify-content:center;line-height:1;transition:background-color .15s ease,border-color .15s ease,color .15s ease,opacity .15s ease;white-space:nowrap}.cms-btn:disabled,.cms-btn[aria-disabled=true]{opacity:.5;pointer-events:none}.cms-btn.is-block{width:100%}.cms-btn-xs{font-size:.875rem;padding:.25rem .5rem}.cms-btn-sm{font-size:.875rem;padding:.375rem .625rem}.cms-btn-md{font-size:.875rem;padding:.5rem .875rem}.cms-btn-lg{font-size:.9375rem;padding:.625rem 1rem}.cms-btn-primary.cms-btn-solid{background:var(--ui-primary);color:var(--ui-text-inverted)}.cms-btn-primary.cms-btn-solid:hover{background:color-mix(in oklab,var(--ui-primary) 88%,#000)}.cms-btn-primary.cms-btn-subtle{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-btn-primary.cms-btn-subtle:hover{background:#e0e0e0}.cms-btn-primary.cms-btn-soft{background:var(--cms-sage);color:var(--cms-sage-ink)}.cms-btn-neutral.cms-btn-solid{background:var(--ui-bg-inverted);color:var(--ui-text-inverted)}.cms-btn-neutral.cms-btn-subtle{background:var(--ui-bg-elevated);color:var(--ui-text-highlighted)}.cms-btn-neutral.cms-btn-subtle:hover{background:var(--ui-bg-accented)}.cms-btn-neutral.cms-btn-soft{background:var(--ui-bg-elevated);color:var(--ui-text-highlighted)}.cms-btn-neutral.cms-btn-ghost{color:var(--ui-text-toned)}.cms-btn-neutral.cms-btn-ghost:hover{background:rgba(38,33,25,.06);color:var(--ui-text-highlighted)}.cms-btn-error.cms-btn-solid{background:var(--ui-error);color:#fff}.cms-btn-error.cms-btn-solid:hover{background:color-mix(in oklab,var(--ui-error) 88%,#000)}.cms-btn-error.cms-btn-subtle{background:color-mix(in oklab,var(--ui-error) 12%,transparent);color:var(--ui-error)}.cms-btn-error.cms-btn-ghost{color:var(--ui-error)}.cms-btn-error.cms-btn-ghost:hover{background:color-mix(in oklab,var(--ui-error) 10%,transparent)}.cms-btn-success.cms-btn-solid{background:var(--cms-fern);color:var(--ui-text-inverted)}.cms-field{background:var(--ui-bg);border:1px solid var(--cms-line-strong);border-radius:var(--ui-radius);color:var(--ui-text-highlighted);transition:border-color .15s ease,box-shadow .15s ease;width:100%}.cms-field::-moz-placeholder{color:var(--ui-text-dimmed)}.cms-field::placeholder{color:var(--ui-text-dimmed)}.cms-field:focus,.cms-field:focus-within{border-color:var(--ui-primary);box-shadow:0 0 0 3px color-mix(in oklab,var(--ui-primary) 18%,transparent);outline:none}.cms-field.is-error{border-color:var(--ui-error)}.cms-field-sm{font-size:.875rem;padding:.375rem .625rem}.cms-field-md{font-size:.875rem;padding:.5rem .75rem}.cms-field-lg{font-size:.9375rem;padding:.625rem .875rem}.cms-input-wrap{align-items:center;display:flex;position:relative}.cms-input-wrap .cms-field{width:100%}.cms-input-lead,.cms-input-trail{align-items:center;color:var(--ui-text-dimmed);display:flex;position:absolute}.cms-input-lead{left:.625rem}.cms-input-trail{right:.375rem}.cms-input-wrap.has-lead .cms-field{padding-left:2rem}.cms-switch{align-items:center;background:var(--cms-line-strong);border-radius:9999px;display:inline-flex;flex-shrink:0;height:1.25rem;position:relative;transition:background-color .15s ease;width:2.25rem}.cms-switch.is-on{background:var(--ui-primary)}.cms-switch:after{background:#fff;border-radius:9999px;content:"";height:.875rem;left:.1875rem;position:absolute;transition:transform .15s ease;width:.875rem}.cms-switch.is-on:after{transform:translateX(1rem)}.cms-overlay{align-items:center;backdrop-filter:blur(2px);background:rgba(38,33,25,.32);display:flex;inset:0;justify-content:center;overflow-y:auto;padding:2rem 1rem;position:fixed;z-index:60}.cms-modal{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:1rem;box-shadow:var(--cms-shadow-soft);max-width:32rem;width:100%}.cms-modal-header{padding:1.25rem 1.5rem 0}.cms-modal-body{padding:1.25rem 1.5rem 1.5rem}.cms-menu{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:.75rem;box-shadow:var(--cms-shadow-soft);margin-top:.375rem;min-width:11rem;padding:.25rem;position:absolute;z-index:50}.cms-menu.align-end{right:0}.cms-menu-item{align-items:center;border-radius:.5rem;color:var(--ui-text);cursor:pointer;display:flex;font-size:.875rem;gap:.5rem;padding:.4rem .6rem;text-align:left;width:100%}.cms-menu-item:hover{background:var(--ui-bg-elevated)}.cms-menu-check{color:var(--ui-primary);margin-left:auto}.cms-popover,.cms-selectmenu-panel{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:.75rem;box-shadow:var(--cms-shadow-soft);margin-top:.375rem;position:absolute;z-index:50}.cms-selectmenu-panel{left:0;max-height:15rem;overflow-y:auto;padding:.25rem;right:0}.cms-tag{align-items:center;background:var(--ui-bg-elevated);border-radius:9999px;display:inline-flex;font-size:.875rem;gap:.25rem;padding:.125rem .5rem}.cms-table{border-collapse:collapse;text-align:left;width:100%}.cms-alert{border-radius:.75rem;font-size:.875rem;padding:.75rem 1rem}.cms-alert-error{background:color-mix(in oklab,var(--ui-error) 10%,transparent);color:var(--ui-error)}.cms-toaster{bottom:1rem;display:flex;flex-direction:column;gap:.5rem;max-width:calc(100vw - 2rem);position:fixed;right:1rem;width:20rem;z-index:80}.cms-toast{background:var(--ui-bg);border:1px solid var(--cms-line);border-radius:.75rem;box-shadow:var(--cms-shadow-soft);padding:.75rem .875rem}.cms-toast.is-success{border-left:3px solid var(--cms-fern)}.cms-toast.is-error{border-left:3px solid var(--ui-error)}.cms-pagination{align-items:center;display:flex;gap:.25rem}.cms-page-btn{border-radius:.5rem;color:var(--ui-text-toned);font-size:.875rem;height:2rem;min-width:2rem;padding:0 .5rem}.cms-page-btn:hover:not(:disabled){background:var(--ui-bg-elevated)}.cms-page-btn.is-active{background:var(--cms-sage);color:var(--cms-sage-ink);font-weight:600}.cms-page-btn:disabled{opacity:.4}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
export async function generateMigrations(opts = {}) {
|
|
6
|
+
const root = opts.root ?? process.cwd();
|
|
7
|
+
const configPath = opts.configPath ?? join(root, ".nuxt/cms/drizzle.config.ts");
|
|
8
|
+
if (!existsSync(configPath)) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
`[nuxt-cms] drizzle config not found at ${configPath} \u2014 run \`nuxi prepare\` first.`
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
const bin = join(dirname(require.resolve("drizzle-kit")), "bin.cjs");
|
|
15
|
+
const code = await new Promise((done) => {
|
|
16
|
+
spawn(process.execPath, [bin, "generate", `--config=${configPath}`], {
|
|
17
|
+
cwd: root,
|
|
18
|
+
stdio: "inherit"
|
|
19
|
+
}).on("close", (c) => done(c ?? 1)).on("error", () => done(1));
|
|
20
|
+
});
|
|
21
|
+
if (code !== 0) throw new Error(`[nuxt-cms] drizzle-kit generate failed (exit ${code})`);
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { customId, ID_LENGTH } from './server/utils/custom-id.js';
|
|
2
|
+
export { customId, ID_LENGTH };
|
|
3
|
+
export type SeedDriver = 'sqlite' | 'libsql' | 'postgres';
|
|
4
|
+
export interface CmsSeederOptions {
|
|
5
|
+
driver?: SeedDriver;
|
|
6
|
+
url?: string;
|
|
7
|
+
authToken?: string;
|
|
8
|
+
dbPath?: string;
|
|
9
|
+
migrationsDir?: string;
|
|
10
|
+
root?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createCmsSeeder(opts?: CmsSeederOptions): Promise<{
|
|
13
|
+
db: import("drizzle-orm/libsql").LibSQLDatabase<Record<string, never>> & {
|
|
14
|
+
$client: import("@libsql/client").Client;
|
|
15
|
+
};
|
|
16
|
+
migrate: () => Promise<void>;
|
|
17
|
+
} | {
|
|
18
|
+
db: import("drizzle-orm/node-postgres").NodePgDatabase<Record<string, never>> & {
|
|
19
|
+
$client: import("pg").Pool;
|
|
20
|
+
};
|
|
21
|
+
migrate: () => Promise<void>;
|
|
22
|
+
} | {
|
|
23
|
+
db: import("drizzle-orm/better-sqlite3").BetterSQLite3Database<Record<string, never>> & {
|
|
24
|
+
$client: import("better-sqlite3").Database;
|
|
25
|
+
};
|
|
26
|
+
migrate: () => void;
|
|
27
|
+
}>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { customId, ID_LENGTH } from "./server/utils/custom-id.js";
|
|
4
|
+
export { customId, ID_LENGTH };
|
|
5
|
+
function inferDriver(url) {
|
|
6
|
+
if (/^(libsql|wss?|https?):\/\//.test(url)) return "libsql";
|
|
7
|
+
if (/^postgres(ql)?:\/\//.test(url)) return "postgres";
|
|
8
|
+
return "sqlite";
|
|
9
|
+
}
|
|
10
|
+
export async function createCmsSeeder(opts = {}) {
|
|
11
|
+
const root = opts.root ?? process.cwd();
|
|
12
|
+
const url = opts.url ?? process.env.NUXT_CMS_DATABASE_URL ?? "";
|
|
13
|
+
const authToken = opts.authToken ?? process.env.NUXT_CMS_DATABASE_AUTH_TOKEN ?? "";
|
|
14
|
+
const driver = opts.driver ?? process.env.NUXT_CMS_DATABASE_DRIVER ?? inferDriver(url);
|
|
15
|
+
const dbPath = opts.dbPath ?? process.env.NUXT_CMS_DATABASE_PATH ?? "data/cms.db";
|
|
16
|
+
const resolvedDbPath = isAbsolute(dbPath) ? dbPath : resolve(root, dbPath);
|
|
17
|
+
const migrationsFolder = opts.migrationsDir ?? resolve(root, `server/db/migrations/${driver}`);
|
|
18
|
+
if (driver === "libsql") {
|
|
19
|
+
const { createClient } = await import("@libsql/client");
|
|
20
|
+
const { drizzle: drizzle2 } = await import("drizzle-orm/libsql");
|
|
21
|
+
const { migrate: migrate2 } = await import("drizzle-orm/libsql/migrator");
|
|
22
|
+
const dbUrl = url || `file:${resolvedDbPath}`;
|
|
23
|
+
if (dbUrl.startsWith("file:")) mkdirSync(dirname(resolvedDbPath), { recursive: true });
|
|
24
|
+
const db2 = drizzle2(createClient({ url: dbUrl, authToken: authToken || void 0 }));
|
|
25
|
+
return { db: db2, migrate: () => migrate2(db2, { migrationsFolder }) };
|
|
26
|
+
}
|
|
27
|
+
if (driver === "postgres") {
|
|
28
|
+
if (!url) throw new Error("[nuxt-cms] seed: Postgres needs a url (NUXT_CMS_DATABASE_URL)");
|
|
29
|
+
const { drizzle: drizzle2 } = await import("drizzle-orm/node-postgres");
|
|
30
|
+
const { migrate: migrate2 } = await import("drizzle-orm/node-postgres/migrator");
|
|
31
|
+
const pg = (await import("pg")).default;
|
|
32
|
+
const db2 = drizzle2(new pg.Pool({ connectionString: url }));
|
|
33
|
+
return { db: db2, migrate: () => migrate2(db2, { migrationsFolder }) };
|
|
34
|
+
}
|
|
35
|
+
const Database = (await import("better-sqlite3")).default;
|
|
36
|
+
const { drizzle } = await import("drizzle-orm/better-sqlite3");
|
|
37
|
+
const { migrate } = await import("drizzle-orm/better-sqlite3/migrator");
|
|
38
|
+
mkdirSync(dirname(resolvedDbPath), { recursive: true });
|
|
39
|
+
const sqlite = new Database(resolvedDbPath);
|
|
40
|
+
sqlite.pragma("journal_mode = WAL");
|
|
41
|
+
sqlite.pragma("foreign_keys = ON");
|
|
42
|
+
const db = drizzle(sqlite);
|
|
43
|
+
return { db, migrate: () => migrate(db, { migrationsFolder }) };
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xleddyl/nuxt-cms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Lightweight CMS that ships with your Nuxt app: runs on the Nitro server, content types defined in code, /cms admin panel, GraphQL API, SQLite or Postgres. No external CMS needed!",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Edoardo Alberti (https://github.com/xleddyl)",
|
|
@@ -38,6 +38,14 @@
|
|
|
38
38
|
".": {
|
|
39
39
|
"types": "./dist/types.d.mts",
|
|
40
40
|
"import": "./dist/module.mjs"
|
|
41
|
+
},
|
|
42
|
+
"./seed": {
|
|
43
|
+
"types": "./dist/runtime/seed.d.ts",
|
|
44
|
+
"import": "./dist/runtime/seed.js"
|
|
45
|
+
},
|
|
46
|
+
"./generate": {
|
|
47
|
+
"types": "./dist/runtime/generate.d.ts",
|
|
48
|
+
"import": "./dist/runtime/generate.js"
|
|
41
49
|
}
|
|
42
50
|
},
|
|
43
51
|
"main": "./dist/module.mjs",
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
type __VLS_Props = {
|
|
2
|
-
items?: string[];
|
|
3
|
-
size?: 'sm' | 'md' | 'lg';
|
|
4
|
-
required?: boolean;
|
|
5
|
-
};
|
|
6
|
-
type __VLS_ModelProps = {
|
|
7
|
-
modelValue?: string | undefined;
|
|
8
|
-
};
|
|
9
|
-
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
-
"update:modelValue": (value: string | undefined) => any;
|
|
12
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
-
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
14
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
-
declare const _default: typeof __VLS_export;
|
|
16
|
-
export default _default;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<select
|
|
3
|
-
:value="model ?? ''"
|
|
4
|
-
:class="['cms-field', `cms-field-${size ?? 'md'}`]"
|
|
5
|
-
@change="model = $event.target.value || void 0"
|
|
6
|
-
>
|
|
7
|
-
<option v-if="!required" value="">—</option>
|
|
8
|
-
<option v-for="option in items" :key="option" :value="option">{{ option }}</option>
|
|
9
|
-
</select>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
<script setup>
|
|
13
|
-
defineProps({
|
|
14
|
-
items: { type: Array, required: false },
|
|
15
|
-
size: { type: String, required: false },
|
|
16
|
-
required: { type: Boolean, required: false }
|
|
17
|
-
});
|
|
18
|
-
const model = defineModel({ type: null });
|
|
19
|
-
</script>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
type __VLS_Props = {
|
|
2
|
-
items?: string[];
|
|
3
|
-
size?: 'sm' | 'md' | 'lg';
|
|
4
|
-
required?: boolean;
|
|
5
|
-
};
|
|
6
|
-
type __VLS_ModelProps = {
|
|
7
|
-
modelValue?: string | undefined;
|
|
8
|
-
};
|
|
9
|
-
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
-
"update:modelValue": (value: string | undefined) => any;
|
|
12
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
-
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
14
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
-
declare const _default: typeof __VLS_export;
|
|
16
|
-
export default _default;
|