@xleddyl/nuxt-cms 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/module.d.mts +36 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +765 -0
- package/dist/runtime/app/components/cms/BlocksField.d.vue.ts +15 -0
- package/dist/runtime/app/components/cms/BlocksField.vue +110 -0
- package/dist/runtime/app/components/cms/BlocksField.vue.d.ts +15 -0
- package/dist/runtime/app/components/cms/EmptyState.d.vue.ts +18 -0
- package/dist/runtime/app/components/cms/EmptyState.vue +20 -0
- package/dist/runtime/app/components/cms/EmptyState.vue.d.ts +18 -0
- package/dist/runtime/app/components/cms/EntryForm.d.vue.ts +23 -0
- package/dist/runtime/app/components/cms/EntryForm.vue +78 -0
- package/dist/runtime/app/components/cms/EntryForm.vue.d.ts +23 -0
- package/dist/runtime/app/components/cms/FieldInput.d.vue.ts +16 -0
- package/dist/runtime/app/components/cms/FieldInput.vue +85 -0
- package/dist/runtime/app/components/cms/FieldInput.vue.d.ts +16 -0
- package/dist/runtime/app/components/cms/JsonField.d.vue.ts +10 -0
- package/dist/runtime/app/components/cms/JsonField.vue +51 -0
- package/dist/runtime/app/components/cms/JsonField.vue.d.ts +10 -0
- package/dist/runtime/app/components/cms/MediaField.d.vue.ts +16 -0
- package/dist/runtime/app/components/cms/MediaField.vue +81 -0
- package/dist/runtime/app/components/cms/MediaField.vue.d.ts +16 -0
- package/dist/runtime/app/components/cms/MediaGallery.d.vue.ts +19 -0
- package/dist/runtime/app/components/cms/MediaGallery.vue +309 -0
- package/dist/runtime/app/components/cms/MediaGallery.vue.d.ts +19 -0
- package/dist/runtime/app/components/cms/MediaUpload.d.vue.ts +14 -0
- package/dist/runtime/app/components/cms/MediaUpload.vue +132 -0
- package/dist/runtime/app/components/cms/MediaUpload.vue.d.ts +14 -0
- package/dist/runtime/app/components/cms/PageHeader.d.vue.ts +19 -0
- package/dist/runtime/app/components/cms/PageHeader.vue +23 -0
- package/dist/runtime/app/components/cms/PageHeader.vue.d.ts +19 -0
- package/dist/runtime/app/components/cms/RelationField.d.vue.ts +16 -0
- package/dist/runtime/app/components/cms/RelationField.vue +87 -0
- package/dist/runtime/app/components/cms/RelationField.vue.d.ts +16 -0
- package/dist/runtime/app/components/cms/RichTextField.d.vue.ts +10 -0
- package/dist/runtime/app/components/cms/RichTextField.vue +123 -0
- package/dist/runtime/app/components/cms/RichTextField.vue.d.ts +10 -0
- package/dist/runtime/app/components/cms/SlugField.d.vue.ts +14 -0
- package/dist/runtime/app/components/cms/SlugField.vue +44 -0
- package/dist/runtime/app/components/cms/SlugField.vue.d.ts +14 -0
- package/dist/runtime/app/components/cms/TranslatableField.d.vue.ts +15 -0
- package/dist/runtime/app/components/cms/TranslatableField.vue +64 -0
- package/dist/runtime/app/components/cms/TranslatableField.vue.d.ts +15 -0
- package/dist/runtime/app/composables/cms-query.d.ts +4 -0
- package/dist/runtime/app/composables/cms-query.js +18 -0
- package/dist/runtime/app/composables/cms-runtime.d.ts +5 -0
- package/dist/runtime/app/composables/cms-runtime.js +4 -0
- package/dist/runtime/app/i18n/en.json +93 -0
- package/dist/runtime/app/i18n/it.json +93 -0
- package/dist/runtime/app/layouts/cms-admin.d.vue.ts +13 -0
- package/dist/runtime/app/layouts/cms-admin.vue +97 -0
- package/dist/runtime/app/layouts/cms-admin.vue.d.ts +13 -0
- package/dist/runtime/app/middleware/cms-auth.d.ts +2 -0
- package/dist/runtime/app/middleware/cms-auth.js +7 -0
- package/dist/runtime/app/pages/admin-collection.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin-collection.vue +273 -0
- package/dist/runtime/app/pages/admin-collection.vue.d.ts +3 -0
- package/dist/runtime/app/pages/admin-entry.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin-entry.vue +156 -0
- package/dist/runtime/app/pages/admin-entry.vue.d.ts +3 -0
- package/dist/runtime/app/pages/admin-index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin-index.vue +11 -0
- package/dist/runtime/app/pages/admin-index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/admin-login.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin-login.vue +87 -0
- package/dist/runtime/app/pages/admin-login.vue.d.ts +3 -0
- package/dist/runtime/app/pages/admin-media.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin-media.vue +13 -0
- package/dist/runtime/app/pages/admin-media.vue.d.ts +3 -0
- package/dist/runtime/app/utils/api.d.ts +7 -0
- package/dist/runtime/app/utils/api.js +3 -0
- package/dist/runtime/app/utils/ui.d.ts +8 -0
- package/dist/runtime/app/utils/ui.js +9 -0
- package/dist/runtime/assets/main.css +1 -0
- package/dist/runtime/server/api/collection.get.d.ts +6 -0
- package/dist/runtime/server/api/collection.get.js +19 -0
- package/dist/runtime/server/api/collection.post.d.ts +2 -0
- package/dist/runtime/server/api/collection.post.js +30 -0
- package/dist/runtime/server/api/collection.put.d.ts +2 -0
- package/dist/runtime/server/api/collection.put.js +28 -0
- package/dist/runtime/server/api/item.delete.d.ts +4 -0
- package/dist/runtime/server/api/item.delete.js +19 -0
- package/dist/runtime/server/api/item.get.d.ts +2 -0
- package/dist/runtime/server/api/item.get.js +18 -0
- package/dist/runtime/server/api/item.put.d.ts +2 -0
- package/dist/runtime/server/api/item.put.js +40 -0
- package/dist/runtime/server/api/media-presign.post.d.ts +11 -0
- package/dist/runtime/server/api/media-presign.post.js +51 -0
- package/dist/runtime/server/api/media.delete.d.ts +4 -0
- package/dist/runtime/server/api/media.delete.js +25 -0
- package/dist/runtime/server/api/media.get.d.ts +5 -0
- package/dist/runtime/server/api/media.get.js +13 -0
- package/dist/runtime/server/api/media.post.d.ts +3 -0
- package/dist/runtime/server/api/media.post.js +32 -0
- package/dist/runtime/server/api/media.put.d.ts +3 -0
- package/dist/runtime/server/api/media.put.js +28 -0
- package/dist/runtime/server/plugins/migrate-postgres.d.ts +2 -0
- package/dist/runtime/server/plugins/migrate-postgres.js +9 -0
- package/dist/runtime/server/plugins/migrate-sqlite.d.ts +2 -0
- package/dist/runtime/server/plugins/migrate-sqlite.js +9 -0
- package/dist/runtime/server/plugins/session-check.d.ts +2 -0
- package/dist/runtime/server/plugins/session-check.js +9 -0
- package/dist/runtime/server/routes/auth/login.post.d.ts +4 -0
- package/dist/runtime/server/routes/auth/login.post.js +62 -0
- package/dist/runtime/server/routes/graphql.d.ts +2 -0
- package/dist/runtime/server/routes/graphql.js +34 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/custom-id.d.ts +2 -0
- package/dist/runtime/server/utils/custom-id.js +10 -0
- package/dist/runtime/server/utils/db-errors.d.ts +1 -0
- package/dist/runtime/server/utils/db-errors.js +31 -0
- package/dist/runtime/server/utils/db-postgres.d.ts +3 -0
- package/dist/runtime/server/utils/db-postgres.js +16 -0
- package/dist/runtime/server/utils/db-sqlite.d.ts +4 -0
- package/dist/runtime/server/utils/db-sqlite.js +17 -0
- package/dist/runtime/server/utils/graphql-depth.d.ts +4 -0
- package/dist/runtime/server/utils/graphql-depth.js +72 -0
- package/dist/runtime/server/utils/graphql.d.ts +14 -0
- package/dist/runtime/server/utils/graphql.js +317 -0
- package/dist/runtime/server/utils/media.d.ts +24 -0
- package/dist/runtime/server/utils/media.js +38 -0
- package/dist/runtime/server/utils/registry.d.ts +20 -0
- package/dist/runtime/server/utils/registry.js +47 -0
- package/dist/runtime/server/utils/relations.d.ts +12 -0
- package/dist/runtime/server/utils/relations.js +80 -0
- package/dist/runtime/server/utils/require-admin.d.ts +2 -0
- package/dist/runtime/server/utils/require-admin.js +13 -0
- package/dist/runtime/shared/empty-config.d.ts +2 -0
- package/dist/runtime/shared/empty-config.js +1 -0
- package/dist/runtime/shared/graphql-sdl.d.ts +5 -0
- package/dist/runtime/shared/graphql-sdl.js +147 -0
- package/dist/runtime/shared/index.d.ts +62 -0
- package/dist/runtime/shared/index.js +55 -0
- package/dist/runtime/shared/validation.d.ts +16 -0
- package/dist/runtime/shared/validation.js +82 -0
- package/dist/types.d.mts +3 -0
- package/package.json +93 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FieldConfig } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
field: FieldConfig;
|
|
4
|
+
};
|
|
5
|
+
type __VLS_ModelProps = {
|
|
6
|
+
modelValue: Record<string, unknown>[] | null;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: Record<string, unknown>[] | null) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: Record<string, unknown>[] | null) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col gap-3">
|
|
3
|
+
<div
|
|
4
|
+
v-for="(item, index) in items"
|
|
5
|
+
:key="uidFor(item)"
|
|
6
|
+
class="cms-card flex flex-col gap-4 p-4"
|
|
7
|
+
>
|
|
8
|
+
<div class="flex items-center gap-1">
|
|
9
|
+
<span class="cms-kicker grow">
|
|
10
|
+
{{ blocks[item.type]?.label ?? item.type }}
|
|
11
|
+
</span>
|
|
12
|
+
<UButton
|
|
13
|
+
icon="i-lucide-chevron-up"
|
|
14
|
+
size="xs"
|
|
15
|
+
variant="ghost"
|
|
16
|
+
color="neutral"
|
|
17
|
+
:disabled="index === 0"
|
|
18
|
+
@click="move(index, -1)"
|
|
19
|
+
/>
|
|
20
|
+
<UButton
|
|
21
|
+
icon="i-lucide-chevron-down"
|
|
22
|
+
size="xs"
|
|
23
|
+
variant="ghost"
|
|
24
|
+
color="neutral"
|
|
25
|
+
:disabled="index === items.length - 1"
|
|
26
|
+
@click="move(index, 1)"
|
|
27
|
+
/>
|
|
28
|
+
<UButton
|
|
29
|
+
icon="i-lucide-trash-2"
|
|
30
|
+
size="xs"
|
|
31
|
+
variant="ghost"
|
|
32
|
+
color="error"
|
|
33
|
+
@click="remove(index)"
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
36
|
+
<UFormField
|
|
37
|
+
v-for="(blockField, blockKey) in blocks[item.type]?.fields"
|
|
38
|
+
:key="blockKey"
|
|
39
|
+
:label="blockField.label"
|
|
40
|
+
:required="blockField.required"
|
|
41
|
+
:ui="CMS_FIELD_UI"
|
|
42
|
+
>
|
|
43
|
+
<CmsFieldInput
|
|
44
|
+
:model-value="item[blockKey]"
|
|
45
|
+
:field="blockField"
|
|
46
|
+
@update:model-value="(value) => updateField(index, blockKey, value)"
|
|
47
|
+
/>
|
|
48
|
+
</UFormField>
|
|
49
|
+
</div>
|
|
50
|
+
<UDropdownMenu :items="addItems">
|
|
51
|
+
<UButton
|
|
52
|
+
:label="t('cms.form.addBlock')"
|
|
53
|
+
icon="i-lucide-plus"
|
|
54
|
+
variant="subtle"
|
|
55
|
+
class="self-start rounded-full px-4"
|
|
56
|
+
/>
|
|
57
|
+
</UDropdownMenu>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script setup>
|
|
62
|
+
import { computed, useI18n } from "#imports";
|
|
63
|
+
import { CMS_FIELD_UI } from "../../utils/ui";
|
|
64
|
+
const props = defineProps({
|
|
65
|
+
field: { type: Object, required: true }
|
|
66
|
+
});
|
|
67
|
+
const model = defineModel({ type: [Array, null], ...{ required: true } });
|
|
68
|
+
const { t } = useI18n();
|
|
69
|
+
const blocks = computed(() => props.field.blocks ?? {});
|
|
70
|
+
const items = computed(() => Array.isArray(model.value) ? model.value : []);
|
|
71
|
+
let uidCounter = 0;
|
|
72
|
+
const uids = /* @__PURE__ */ new WeakMap();
|
|
73
|
+
function uidFor(item) {
|
|
74
|
+
let uid = uids.get(item);
|
|
75
|
+
if (uid === void 0) {
|
|
76
|
+
uid = ++uidCounter;
|
|
77
|
+
uids.set(item, uid);
|
|
78
|
+
}
|
|
79
|
+
return uid;
|
|
80
|
+
}
|
|
81
|
+
function updateField(index, key, value) {
|
|
82
|
+
const current = items.value[index];
|
|
83
|
+
if (!current) return;
|
|
84
|
+
const updated = { ...current, [key]: value };
|
|
85
|
+
uids.set(updated, uidFor(current));
|
|
86
|
+
model.value = items.value.map((item, i) => i === index ? updated : item);
|
|
87
|
+
}
|
|
88
|
+
function add(type) {
|
|
89
|
+
const block = blocks.value[type];
|
|
90
|
+
if (!block) return;
|
|
91
|
+
const empty = Object.fromEntries(Object.keys(block.fields).map((k) => [k, null]));
|
|
92
|
+
model.value = [...items.value, { type, ...empty }];
|
|
93
|
+
}
|
|
94
|
+
function remove(index) {
|
|
95
|
+
const next = items.value.filter((_, i) => i !== index);
|
|
96
|
+
model.value = next.length ? next : null;
|
|
97
|
+
}
|
|
98
|
+
function move(index, delta) {
|
|
99
|
+
const next = [...items.value];
|
|
100
|
+
const [item] = next.splice(index, 1);
|
|
101
|
+
next.splice(index + delta, 0, item);
|
|
102
|
+
model.value = next;
|
|
103
|
+
}
|
|
104
|
+
const addItems = computed(
|
|
105
|
+
() => Object.entries(blocks.value).map(([type, block]) => ({
|
|
106
|
+
label: block.label,
|
|
107
|
+
onSelect: () => add(type)
|
|
108
|
+
}))
|
|
109
|
+
);
|
|
110
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FieldConfig } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
field: FieldConfig;
|
|
4
|
+
};
|
|
5
|
+
type __VLS_ModelProps = {
|
|
6
|
+
modelValue: Record<string, unknown>[] | null;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: Record<string, unknown>[] | null) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: Record<string, unknown>[] | null) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
icon: string;
|
|
3
|
+
title: string;
|
|
4
|
+
body?: string;
|
|
5
|
+
};
|
|
6
|
+
declare var __VLS_6: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_6) => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
15
|
+
new (): {
|
|
16
|
+
$slots: S;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="cms-empty flex flex-col items-center gap-2 p-14 text-center">
|
|
3
|
+
<UIcon :name="icon" class="text-(--cms-fern) mb-1 size-6" />
|
|
4
|
+
<p class="cms-display text-(--ui-text-highlighted) text-xl">
|
|
5
|
+
{{ title }}<span class="text-(--cms-fern)">.</span>
|
|
6
|
+
</p>
|
|
7
|
+
<p v-if="body" class="text-(--ui-text-muted) max-w-md text-sm">
|
|
8
|
+
{{ body }}
|
|
9
|
+
</p>
|
|
10
|
+
<slot />
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
defineProps({
|
|
16
|
+
icon: { type: String, required: true },
|
|
17
|
+
title: { type: String, required: true },
|
|
18
|
+
body: { type: String, required: false }
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
icon: string;
|
|
3
|
+
title: string;
|
|
4
|
+
body?: string;
|
|
5
|
+
};
|
|
6
|
+
declare var __VLS_6: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_6) => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
15
|
+
new (): {
|
|
16
|
+
$slots: S;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CmsEntry } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
fields: CmsEntry['fields'];
|
|
4
|
+
drafts?: boolean;
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
formId?: string;
|
|
7
|
+
footer?: boolean;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_ModelProps = {
|
|
10
|
+
modelValue: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
error: () => any;
|
|
15
|
+
submit: () => any;
|
|
16
|
+
"update:modelValue": (value: Record<string, unknown>) => any;
|
|
17
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
18
|
+
onError?: (() => any) | undefined;
|
|
19
|
+
onSubmit?: (() => any) | undefined;
|
|
20
|
+
"onUpdate:modelValue"?: ((value: Record<string, unknown>) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const _default: typeof __VLS_export;
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UForm
|
|
3
|
+
:id="formId"
|
|
4
|
+
:state="state"
|
|
5
|
+
:schema="schema"
|
|
6
|
+
class="flex flex-col gap-5"
|
|
7
|
+
@submit="emit('submit')"
|
|
8
|
+
@error="emit('error')"
|
|
9
|
+
>
|
|
10
|
+
<UFormField
|
|
11
|
+
v-for="(field, key) in fields"
|
|
12
|
+
:key="key"
|
|
13
|
+
:label="field.label"
|
|
14
|
+
:name="key"
|
|
15
|
+
:required="field.required"
|
|
16
|
+
:ui="CMS_FIELD_UI"
|
|
17
|
+
>
|
|
18
|
+
<CmsFieldInput
|
|
19
|
+
v-model="state[key]"
|
|
20
|
+
:field="field"
|
|
21
|
+
:slug-source="field.from ? state[field.from] : void 0"
|
|
22
|
+
/>
|
|
23
|
+
</UFormField>
|
|
24
|
+
<div v-if="footer" class="flex items-center justify-end gap-3 pt-1">
|
|
25
|
+
<UButton
|
|
26
|
+
type="submit"
|
|
27
|
+
:label="t('cms.form.save')"
|
|
28
|
+
:loading="loading"
|
|
29
|
+
class="rounded-full px-6"
|
|
30
|
+
/>
|
|
31
|
+
<UButton
|
|
32
|
+
v-if="drafts"
|
|
33
|
+
type="submit"
|
|
34
|
+
:label="published ? t('cms.status.unpublish') : t('cms.status.publish')"
|
|
35
|
+
:loading="loading"
|
|
36
|
+
class="rounded-full px-6"
|
|
37
|
+
@click="togglePublished"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
</UForm>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script setup>
|
|
44
|
+
import { computed, useI18n } from "#imports";
|
|
45
|
+
import { buildEntrySchema } from "../../../shared/validation";
|
|
46
|
+
import { useCmsRuntime } from "../../composables/cms-runtime";
|
|
47
|
+
import { CMS_FIELD_UI } from "../../utils/ui";
|
|
48
|
+
const props = defineProps({
|
|
49
|
+
fields: { type: Object, required: true },
|
|
50
|
+
drafts: { type: Boolean, required: false },
|
|
51
|
+
loading: { type: Boolean, required: false },
|
|
52
|
+
formId: { type: String, required: false },
|
|
53
|
+
footer: { type: Boolean, required: false, default: true }
|
|
54
|
+
});
|
|
55
|
+
const state = defineModel({ type: Object, ...{ required: true } });
|
|
56
|
+
const emit = defineEmits(["submit", "error"]);
|
|
57
|
+
const { t } = useI18n();
|
|
58
|
+
const { i18n } = useCmsRuntime();
|
|
59
|
+
const schema = computed(
|
|
60
|
+
() => buildEntrySchema({ fields: props.fields, drafts: props.drafts }, i18n, {
|
|
61
|
+
required: t("cms.validation.required"),
|
|
62
|
+
invalidDate: t("cms.validation.invalidDate"),
|
|
63
|
+
invalidEmail: t("cms.validation.invalidEmail"),
|
|
64
|
+
invalidSlug: t("cms.validation.invalidSlug"),
|
|
65
|
+
unknownLocale: t("cms.validation.unknownLocale"),
|
|
66
|
+
requiredLocale: (locale) => t("cms.validation.requiredLocale", { locale })
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
const published = computed({
|
|
70
|
+
get: () => state.value.status === "published",
|
|
71
|
+
set: (value) => {
|
|
72
|
+
state.value.status = value ? "published" : "draft";
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
function togglePublished() {
|
|
76
|
+
published.value = !published.value;
|
|
77
|
+
}
|
|
78
|
+
</script>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CmsEntry } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
fields: CmsEntry['fields'];
|
|
4
|
+
drafts?: boolean;
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
formId?: string;
|
|
7
|
+
footer?: boolean;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_ModelProps = {
|
|
10
|
+
modelValue: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
error: () => any;
|
|
15
|
+
submit: () => any;
|
|
16
|
+
"update:modelValue": (value: Record<string, unknown>) => any;
|
|
17
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
18
|
+
onError?: (() => any) | undefined;
|
|
19
|
+
onSubmit?: (() => any) | undefined;
|
|
20
|
+
"onUpdate:modelValue"?: ((value: Record<string, unknown>) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const _default: typeof __VLS_export;
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FieldConfig } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
field: FieldConfig;
|
|
4
|
+
slugSource?: string | null;
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue: unknown;
|
|
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: unknown) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<CmsTranslatableField v-if="isTranslatableField(field)" v-model="translatable" :field="field" />
|
|
3
|
+
<CmsBlocksField v-else-if="field.type === 'blocks'" v-model="blocksValue" :field="field" />
|
|
4
|
+
<CmsRichTextField v-else-if="field.type === 'richtext'" v-model="strOrNull" />
|
|
5
|
+
<UTextarea
|
|
6
|
+
v-else-if="field.type === 'text' && field.textarea"
|
|
7
|
+
v-model="str"
|
|
8
|
+
:rows="4"
|
|
9
|
+
size="lg"
|
|
10
|
+
class="w-full"
|
|
11
|
+
/>
|
|
12
|
+
<UInput v-else-if="field.type === 'text'" v-model="str" size="lg" class="w-full" />
|
|
13
|
+
<UInput v-else-if="field.type === 'email'" v-model="str" type="email" size="lg" class="w-full" />
|
|
14
|
+
<CmsSlugField v-else-if="field.type === 'slug'" v-model="strOrNull" :source="slugSource" />
|
|
15
|
+
<USelect
|
|
16
|
+
v-else-if="field.type === 'select'"
|
|
17
|
+
v-model="sel"
|
|
18
|
+
:items="field.options"
|
|
19
|
+
size="lg"
|
|
20
|
+
class="w-full"
|
|
21
|
+
/>
|
|
22
|
+
<USwitch
|
|
23
|
+
v-else-if="field.type === 'boolean'"
|
|
24
|
+
:model-value="!!model"
|
|
25
|
+
@update:model-value="
|
|
26
|
+
(v) => {
|
|
27
|
+
model = v;
|
|
28
|
+
}
|
|
29
|
+
"
|
|
30
|
+
/>
|
|
31
|
+
<CmsJsonField v-else-if="field.type === 'json'" v-model="jsonValue" />
|
|
32
|
+
<UInput
|
|
33
|
+
v-else-if="field.type === 'number'"
|
|
34
|
+
v-model.number="num"
|
|
35
|
+
type="number"
|
|
36
|
+
size="lg"
|
|
37
|
+
class="w-full"
|
|
38
|
+
/>
|
|
39
|
+
<UInput v-else-if="field.type === 'date'" v-model="str" type="date" size="lg" class="w-full" />
|
|
40
|
+
<CmsRelationField
|
|
41
|
+
v-else-if="field.type === 'relation'"
|
|
42
|
+
v-model="relationValue"
|
|
43
|
+
:to="field.to"
|
|
44
|
+
:required="field.required"
|
|
45
|
+
:multiple="field.cardinality === 'many-to-many'"
|
|
46
|
+
/>
|
|
47
|
+
<CmsMediaField v-else v-model="strOrNull" :media-type="field.mediaType" :accept="field.accept" />
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script setup>
|
|
51
|
+
import { isTranslatableField } from "#nuxt-cms";
|
|
52
|
+
import { computed } from "#imports";
|
|
53
|
+
defineProps({
|
|
54
|
+
field: { type: Object, required: true },
|
|
55
|
+
slugSource: { type: [String, null], required: false }
|
|
56
|
+
});
|
|
57
|
+
const model = defineModel({ type: null, ...{ required: true } });
|
|
58
|
+
function proxy(fromModel, toModel = (v) => v) {
|
|
59
|
+
return computed({
|
|
60
|
+
get: () => fromModel(model.value),
|
|
61
|
+
set: (value) => {
|
|
62
|
+
model.value = toModel(value);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const str = proxy(
|
|
67
|
+
(v) => v ?? "",
|
|
68
|
+
(v) => v === "" ? null : v
|
|
69
|
+
);
|
|
70
|
+
const strOrNull = proxy((v) => v);
|
|
71
|
+
const sel = proxy(
|
|
72
|
+
(v) => v ?? void 0,
|
|
73
|
+
(v) => v ?? null
|
|
74
|
+
);
|
|
75
|
+
const num = proxy(
|
|
76
|
+
(v) => v ?? void 0,
|
|
77
|
+
(v) => typeof v === "number" && !Number.isNaN(v) ? v : null
|
|
78
|
+
);
|
|
79
|
+
const translatable = proxy((v) => v);
|
|
80
|
+
const blocksValue = proxy(
|
|
81
|
+
(v) => v
|
|
82
|
+
);
|
|
83
|
+
const relationValue = proxy((v) => v);
|
|
84
|
+
const jsonValue = proxy((v) => v);
|
|
85
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FieldConfig } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
field: FieldConfig;
|
|
4
|
+
slugSource?: string | null;
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue: unknown;
|
|
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: unknown) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue: unknown;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: unknown) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col gap-1">
|
|
3
|
+
<UTextarea
|
|
4
|
+
v-model="text"
|
|
5
|
+
:rows="6"
|
|
6
|
+
size="lg"
|
|
7
|
+
class="w-full font-mono"
|
|
8
|
+
:color="invalid ? 'error' : void 0"
|
|
9
|
+
@blur="commit"
|
|
10
|
+
@update:model-value="invalid = false"
|
|
11
|
+
/>
|
|
12
|
+
<p v-if="invalid" class="text-(--ui-error) text-xs">
|
|
13
|
+
{{ t("cms.form.invalidJson") }}
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup>
|
|
19
|
+
import { ref, useI18n, watch } from "#imports";
|
|
20
|
+
const model = defineModel({ type: null, ...{ required: true } });
|
|
21
|
+
const { t } = useI18n();
|
|
22
|
+
function serialize(value) {
|
|
23
|
+
return value == null ? "" : JSON.stringify(value, null, 2);
|
|
24
|
+
}
|
|
25
|
+
function parse(raw) {
|
|
26
|
+
if (!raw.trim()) return null;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(raw);
|
|
29
|
+
} catch {
|
|
30
|
+
return void 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const text = ref(serialize(model.value));
|
|
34
|
+
const invalid = ref(false);
|
|
35
|
+
watch(model, (value) => {
|
|
36
|
+
const current = parse(text.value);
|
|
37
|
+
if (JSON.stringify(current ?? null) !== JSON.stringify(value ?? null)) {
|
|
38
|
+
text.value = serialize(value);
|
|
39
|
+
invalid.value = false;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
function commit() {
|
|
43
|
+
const parsed = parse(text.value);
|
|
44
|
+
if (parsed === void 0) {
|
|
45
|
+
invalid.value = true;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
invalid.value = false;
|
|
49
|
+
model.value = parsed;
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue: unknown;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: unknown) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MediaType } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
mediaType?: MediaType;
|
|
4
|
+
accept?: string[];
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue: string | null;
|
|
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 | null) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string | null) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="model" class="cms-card overflow-hidden">
|
|
3
|
+
<img
|
|
4
|
+
v-if="kind === 'image' && url"
|
|
5
|
+
:src="url"
|
|
6
|
+
alt=""
|
|
7
|
+
class="bg-(--cms-field) max-h-56 w-full object-cover"
|
|
8
|
+
/>
|
|
9
|
+
<video
|
|
10
|
+
v-else-if="kind === 'video' && url"
|
|
11
|
+
:src="url"
|
|
12
|
+
controls
|
|
13
|
+
preload="metadata"
|
|
14
|
+
playsinline
|
|
15
|
+
class="bg-(--cms-field) max-h-56 w-full"
|
|
16
|
+
/>
|
|
17
|
+
<div class="flex items-center gap-2.5 px-4 py-3">
|
|
18
|
+
<UIcon :name="icon" class="text-(--ui-text-dimmed) size-4 shrink-0" />
|
|
19
|
+
<span class="min-w-0 flex-1 truncate text-[13px] font-medium" :title="model">{{
|
|
20
|
+
mediaFilename(model)
|
|
21
|
+
}}</span>
|
|
22
|
+
<UButton
|
|
23
|
+
icon="i-lucide-images"
|
|
24
|
+
variant="ghost"
|
|
25
|
+
color="neutral"
|
|
26
|
+
size="xs"
|
|
27
|
+
class="rounded-full"
|
|
28
|
+
:aria-label="t('cms.form.mediaChange')"
|
|
29
|
+
@click="openGallery"
|
|
30
|
+
/>
|
|
31
|
+
<UButton
|
|
32
|
+
icon="i-lucide-x"
|
|
33
|
+
variant="ghost"
|
|
34
|
+
color="neutral"
|
|
35
|
+
size="xs"
|
|
36
|
+
class="rounded-full"
|
|
37
|
+
:aria-label="t('cms.form.mediaRemove')"
|
|
38
|
+
@click="clear"
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<button v-else type="button" class="cms-dropzone is-dense" @click="openGallery">
|
|
44
|
+
<UIcon name="i-lucide-images" class="size-5 shrink-0" />
|
|
45
|
+
<span class="text-[13px] font-medium">{{ t("cms.form.mediaChoose") }}</span>
|
|
46
|
+
</button>
|
|
47
|
+
|
|
48
|
+
<UModal v-model:open="galleryOpen" :title="t('cms.media.title')" :ui="CMS_MODAL_UI">
|
|
49
|
+
<template #body>
|
|
50
|
+
<CmsMediaGallery selectable :media-type="mediaType" :accept="accept" @select="onSelect" />
|
|
51
|
+
</template>
|
|
52
|
+
</UModal>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup>
|
|
56
|
+
import { computed, ref, useI18n } from "#imports";
|
|
57
|
+
import { mediaFilename, mediaIconFor, mediaPublicUrl, mediaTypeForKey } from "#nuxt-cms";
|
|
58
|
+
import { useCmsRuntime } from "../../composables/cms-runtime";
|
|
59
|
+
import { CMS_MODAL_UI } from "../../utils/ui";
|
|
60
|
+
defineProps({
|
|
61
|
+
mediaType: { type: null, required: false },
|
|
62
|
+
accept: { type: Array, required: false }
|
|
63
|
+
});
|
|
64
|
+
const model = defineModel({ type: [String, null], ...{ required: true } });
|
|
65
|
+
const { t } = useI18n();
|
|
66
|
+
const { mediaBaseUrl } = useCmsRuntime();
|
|
67
|
+
const galleryOpen = ref(false);
|
|
68
|
+
function onSelect(item) {
|
|
69
|
+
model.value = item.key;
|
|
70
|
+
galleryOpen.value = false;
|
|
71
|
+
}
|
|
72
|
+
function openGallery() {
|
|
73
|
+
galleryOpen.value = true;
|
|
74
|
+
}
|
|
75
|
+
function clear() {
|
|
76
|
+
model.value = null;
|
|
77
|
+
}
|
|
78
|
+
const url = computed(() => model.value ? mediaPublicUrl(mediaBaseUrl, model.value) : null);
|
|
79
|
+
const kind = computed(() => model.value ? mediaTypeForKey(model.value) : "file");
|
|
80
|
+
const icon = computed(() => mediaIconFor(kind.value));
|
|
81
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MediaType } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
mediaType?: MediaType;
|
|
4
|
+
accept?: string[];
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue: string | null;
|
|
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 | null) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string | null) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MediaType } from '#nuxt-cms';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
selectable?: boolean;
|
|
4
|
+
mediaType?: MediaType;
|
|
5
|
+
accept?: string[];
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
select: (item: {
|
|
9
|
+
key: string;
|
|
10
|
+
url: string | null;
|
|
11
|
+
}) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
13
|
+
onSelect?: ((item: {
|
|
14
|
+
key: string;
|
|
15
|
+
url: string | null;
|
|
16
|
+
}) => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|