@xleddyl/nuxt-cms 0.2.0 → 0.2.2

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.
Files changed (95) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +17 -6
  3. package/dist/runtime/app/components/cms/BrandMark.vue +2 -3
  4. package/dist/runtime/app/components/cms/ConfirmModal.vue +14 -1
  5. package/dist/runtime/app/components/cms/Drawer.vue +5 -9
  6. package/dist/runtime/app/components/cms/EntryDrawer.vue +11 -3
  7. package/dist/runtime/app/components/cms/EntryForm.vue +0 -1
  8. package/dist/runtime/app/components/cms/Input.d.vue.ts +0 -1
  9. package/dist/runtime/app/components/cms/Input.vue +7 -4
  10. package/dist/runtime/app/components/cms/Input.vue.d.ts +0 -1
  11. package/dist/runtime/app/components/cms/LocaleSwitch.vue +1 -1
  12. package/dist/runtime/app/components/cms/MediaFolderPicker.d.vue.ts +0 -1
  13. package/dist/runtime/app/components/cms/MediaFolderPicker.vue +1 -3
  14. package/dist/runtime/app/components/cms/MediaFolderPicker.vue.d.ts +0 -1
  15. package/dist/runtime/app/components/cms/MediaGallery.vue +89 -11
  16. package/dist/runtime/app/components/cms/Modal.vue +5 -11
  17. package/dist/runtime/app/components/cms/PasswordInput.vue +9 -5
  18. package/dist/runtime/app/components/cms/RelationField.vue +7 -2
  19. package/dist/runtime/app/components/cms/SelectMenu.d.vue.ts +0 -1
  20. package/dist/runtime/app/components/cms/SelectMenu.vue +1 -6
  21. package/dist/runtime/app/components/cms/SelectMenu.vue.d.ts +0 -1
  22. package/dist/runtime/app/components/cms/SettingsEntry.vue +1 -8
  23. package/dist/runtime/app/components/cms/SettingsModal.vue +5 -10
  24. package/dist/runtime/app/components/cms/SettingsUsers.vue +8 -4
  25. package/dist/runtime/app/components/cms/Table.d.vue.ts +0 -7
  26. package/dist/runtime/app/components/cms/Table.vue +7 -49
  27. package/dist/runtime/app/components/cms/Table.vue.d.ts +0 -7
  28. package/dist/runtime/app/components/cms/Textarea.d.vue.ts +0 -1
  29. package/dist/runtime/app/components/cms/Textarea.vue +1 -2
  30. package/dist/runtime/app/components/cms/Textarea.vue.d.ts +0 -1
  31. package/dist/runtime/app/composables/cms-confirm.d.ts +16 -7
  32. package/dist/runtime/app/composables/cms-confirm.js +1 -0
  33. package/dist/runtime/app/composables/cms-entry-disabled.js +1 -1
  34. package/dist/runtime/app/composables/cms-media-keys.d.ts +1 -0
  35. package/dist/runtime/app/composables/cms-media-keys.js +5 -0
  36. package/dist/runtime/app/composables/cms-media-library.d.ts +1 -2
  37. package/dist/runtime/app/composables/cms-media-library.js +15 -19
  38. package/dist/runtime/app/composables/cms-media-uploader.d.ts +0 -1
  39. package/dist/runtime/app/composables/cms-media-uploader.js +1 -1
  40. package/dist/runtime/app/composables/cms-overlay.d.ts +4 -0
  41. package/dist/runtime/app/composables/cms-overlay.js +23 -0
  42. package/dist/runtime/app/composables/cms-settings.d.ts +0 -1
  43. package/dist/runtime/app/composables/cms-settings.js +1 -1
  44. package/dist/runtime/app/pages/admin-entry.vue +1 -0
  45. package/dist/runtime/app/utils/ui.d.ts +0 -2
  46. package/dist/runtime/assets/main.css +1 -1
  47. package/dist/runtime/generate.js +1 -1
  48. package/dist/runtime/seed.js +11 -1
  49. package/dist/runtime/server/api/collection.get.js +1 -1
  50. package/dist/runtime/server/api/collection.post.js +20 -14
  51. package/dist/runtime/server/api/collection.put.js +12 -12
  52. package/dist/runtime/server/api/item.put.js +14 -13
  53. package/dist/runtime/server/api/media-folder.patch.js +10 -16
  54. package/dist/runtime/server/api/media-move.post.js +12 -8
  55. package/dist/runtime/server/api/media.delete.js +3 -2
  56. package/dist/runtime/server/api/media.post.js +4 -2
  57. package/dist/runtime/server/api/media.put.js +4 -2
  58. package/dist/runtime/server/api/users.post.js +13 -9
  59. package/dist/runtime/server/plugins/migrate-sqlite.js +2 -2
  60. package/dist/runtime/server/routes/auth/login.post.js +30 -24
  61. package/dist/runtime/server/utils/db-d1.d.ts +0 -1
  62. package/dist/runtime/server/utils/db-d1.js +3 -4
  63. package/dist/runtime/server/utils/db-libsql.d.ts +0 -1
  64. package/dist/runtime/server/utils/db-libsql.js +3 -4
  65. package/dist/runtime/server/utils/db-postgres.d.ts +0 -1
  66. package/dist/runtime/server/utils/db-postgres.js +1 -4
  67. package/dist/runtime/server/utils/db-sqlite.d.ts +0 -1
  68. package/dist/runtime/server/utils/db-sqlite.js +4 -10
  69. package/dist/runtime/server/utils/graphql-depth.js +12 -5
  70. package/dist/runtime/server/utils/graphql.js +4 -3
  71. package/dist/runtime/server/utils/libsql-migrations.d.ts +1 -0
  72. package/dist/runtime/server/utils/libsql-migrations.js +1 -1
  73. package/dist/runtime/server/utils/media-folders.js +23 -24
  74. package/dist/runtime/server/utils/media.d.ts +1 -0
  75. package/dist/runtime/server/utils/media.js +6 -1
  76. package/dist/runtime/server/utils/migrate.d.ts +1 -0
  77. package/dist/runtime/server/utils/migrate.js +33 -1
  78. package/dist/runtime/server/utils/registry.d.ts +3 -0
  79. package/dist/runtime/server/utils/registry.js +10 -1
  80. package/dist/runtime/server/utils/relations.d.ts +1 -1
  81. package/dist/runtime/server/utils/relations.js +6 -9
  82. package/dist/runtime/server/utils/require-admin.d.ts +0 -2
  83. package/dist/runtime/server/utils/require-admin.js +0 -1
  84. package/dist/runtime/server/utils/timestamps.d.ts +12 -0
  85. package/dist/runtime/server/utils/timestamps.js +48 -0
  86. package/dist/runtime/server/utils/users.js +3 -2
  87. package/dist/runtime/server/utils/write-statements.d.ts +33 -0
  88. package/dist/runtime/server/utils/write-statements.js +75 -0
  89. package/dist/runtime/shared/index.d.ts +14 -0
  90. package/dist/runtime/shared/index.js +13 -0
  91. package/dist/runtime/shared/layout.d.ts +0 -1
  92. package/dist/runtime/shared/layout.js +0 -3
  93. package/dist/runtime/shared/timestamps.d.ts +4 -0
  94. package/dist/runtime/shared/timestamps.js +24 -0
  95. package/package.json +1 -1
@@ -224,11 +224,15 @@ async function create() {
224
224
  }
225
225
  async function copyCredentials() {
226
226
  if (!created.value) return;
227
- await navigator.clipboard.writeText(
228
- `Email: ${created.value.email}
227
+ try {
228
+ await navigator.clipboard.writeText(
229
+ `Email: ${created.value.email}
229
230
  Password: ${created.value.password}`
230
- );
231
- copied.value = true;
231
+ );
232
+ copied.value = true;
233
+ } catch {
234
+ copied.value = false;
235
+ }
232
236
  }
233
237
  const resetting = ref(null);
234
238
  const reset = ref({ password: "" });
@@ -4,7 +4,6 @@ interface Column {
4
4
  accessorKey?: string;
5
5
  accessorFn?: (row: Row) => unknown;
6
6
  header?: string;
7
- reorderable?: boolean;
8
7
  sortable?: boolean;
9
8
  }
10
9
  interface TableSort {
@@ -15,11 +14,9 @@ type __VLS_Props = {
15
14
  data: Row[];
16
15
  columns: Column[];
17
16
  selectable?: boolean;
18
- rowKey?: string;
19
17
  };
20
18
  type __VLS_ModelProps = {
21
19
  'selected'?: string[];
22
- 'columnVisibility'?: Record<string, boolean>;
23
20
  'sort'?: TableSort | null;
24
21
  };
25
22
  type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
@@ -35,17 +32,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
35
32
  select: (event: Event, row: {
36
33
  original: Row;
37
34
  }) => any;
38
- reorder: (from: string, to: string) => any;
39
35
  "update:selected": (value: string[]) => any;
40
- "update:columnVisibility": (value: Record<string, boolean>) => any;
41
36
  "update:sort": (value: TableSort | null) => any;
42
37
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
43
38
  onSelect?: ((event: Event, row: {
44
39
  original: Row;
45
40
  }) => any) | undefined;
46
- onReorder?: ((from: string, to: string) => any) | undefined;
47
41
  "onUpdate:selected"?: ((value: string[]) => any) | undefined;
48
- "onUpdate:columnVisibility"?: ((value: Record<string, boolean>) => any) | undefined;
49
42
  "onUpdate:sort"?: ((value: TableSort | null) => any) | undefined;
50
43
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
51
44
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -13,22 +13,14 @@
13
13
  />
14
14
  </th>
15
15
  <th
16
- v-for="column in visibleColumns"
16
+ v-for="column in columns"
17
17
  :key="columnId(column)"
18
18
  :class="{
19
- 'is-dragging': draggingId === columnId(column),
20
- 'is-drop-target': dropTargetId === columnId(column),
21
19
  'is-sortable': column.sortable,
22
20
  'is-sorted': sort?.key === columnId(column)
23
21
  }"
24
- :draggable="column.reorderable || void 0"
25
22
  :aria-sort="ariaSort(column)"
26
23
  @click="toggleSort(column)"
27
- @dragstart="onDragStart($event, column)"
28
- @dragover="onDragOver($event, column)"
29
- @dragleave="onDragLeave(column)"
30
- @drop="onDrop($event, column)"
31
- @dragend="resetDrag"
32
24
  >
33
25
  <span class="cms-th-label">
34
26
  {{ column.header }}
@@ -44,7 +36,7 @@
44
36
  <tbody>
45
37
  <tr
46
38
  v-for="(row, index) in data"
47
- :key="index"
39
+ :key="keyOf(row)"
48
40
  class="__clickable"
49
41
  :class="{ 'is-selected': isSelected(row) }"
50
42
  :style="{ '--cms-row-delay': `${Math.min(index, 14) * 24}ms` }"
@@ -57,7 +49,7 @@
57
49
  @toggle="toggleRow(row)"
58
50
  />
59
51
  </td>
60
- <td v-for="column in visibleColumns" :key="columnId(column)">
52
+ <td v-for="column in columns" :key="columnId(column)">
61
53
  <slot :name="`${columnId(column)}-cell`" :row="{ original: row }">
62
54
  {{ cellValue(column, row) }}
63
55
  </slot>
@@ -70,16 +62,15 @@
70
62
  </template>
71
63
 
72
64
  <script setup>
73
- import { computed, ref } from "#imports";
65
+ import { computed } from "#imports";
74
66
  const props = defineProps({
75
67
  data: { type: Array, required: true },
76
68
  columns: { type: Array, required: true },
77
- selectable: { type: Boolean, required: false },
78
- rowKey: { type: String, required: false }
69
+ selectable: { type: Boolean, required: false }
79
70
  });
80
71
  const selected = defineModel("selected", { type: Array, ...{ default: () => [] } });
81
72
  function keyOf(row) {
82
- return String(row[props.rowKey ?? "id"]);
73
+ return String(row.id);
83
74
  }
84
75
  function isSelected(row) {
85
76
  return selected.value.includes(keyOf(row));
@@ -95,9 +86,8 @@ const someSelected = computed(() => !allSelected.value && selected.value.length
95
86
  function toggleAll() {
96
87
  selected.value = allSelected.value ? [] : props.data.map(keyOf);
97
88
  }
98
- const visibility = defineModel("columnVisibility", { type: Object, ...{ default: () => ({}) } });
99
89
  const sort = defineModel("sort", { type: [Object, null], ...{ default: null } });
100
- const emit = defineEmits(["select", "reorder"]);
90
+ const emit = defineEmits(["select"]);
101
91
  function columnId(column) {
102
92
  return column.id ?? column.accessorKey ?? "";
103
93
  }
@@ -117,38 +107,6 @@ function ariaSort(column) {
117
107
  if (sort.value?.key !== columnId(column)) return "none";
118
108
  return sort.value.order === "asc" ? "ascending" : "descending";
119
109
  }
120
- const draggingId = ref(null);
121
- const dropTargetId = ref(null);
122
- function resetDrag() {
123
- draggingId.value = null;
124
- dropTargetId.value = null;
125
- }
126
- function onDragStart(event, column) {
127
- if (!column.reorderable) return;
128
- draggingId.value = columnId(column);
129
- event.dataTransfer?.setData("text/plain", columnId(column));
130
- if (event.dataTransfer) event.dataTransfer.effectAllowed = "move";
131
- }
132
- function onDragOver(event, column) {
133
- if (!draggingId.value || !column.reorderable) return;
134
- event.preventDefault();
135
- if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
136
- dropTargetId.value = columnId(column);
137
- }
138
- function onDragLeave(column) {
139
- if (dropTargetId.value === columnId(column)) dropTargetId.value = null;
140
- }
141
- function onDrop(event, column) {
142
- if (!draggingId.value || !column.reorderable) return;
143
- event.preventDefault();
144
- const from = draggingId.value;
145
- const to = columnId(column);
146
- resetDrag();
147
- if (from !== to) emit("reorder", from, to);
148
- }
149
- const visibleColumns = computed(
150
- () => props.columns.filter((column) => visibility.value[columnId(column)] !== false)
151
- );
152
110
  function cellValue(column, row) {
153
111
  if (column.accessorFn) return column.accessorFn(row);
154
112
  if (column.accessorKey) return row[column.accessorKey];
@@ -4,7 +4,6 @@ interface Column {
4
4
  accessorKey?: string;
5
5
  accessorFn?: (row: Row) => unknown;
6
6
  header?: string;
7
- reorderable?: boolean;
8
7
  sortable?: boolean;
9
8
  }
10
9
  interface TableSort {
@@ -15,11 +14,9 @@ type __VLS_Props = {
15
14
  data: Row[];
16
15
  columns: Column[];
17
16
  selectable?: boolean;
18
- rowKey?: string;
19
17
  };
20
18
  type __VLS_ModelProps = {
21
19
  'selected'?: string[];
22
- 'columnVisibility'?: Record<string, boolean>;
23
20
  'sort'?: TableSort | null;
24
21
  };
25
22
  type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
@@ -35,17 +32,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
35
32
  select: (event: Event, row: {
36
33
  original: Row;
37
34
  }) => any;
38
- reorder: (from: string, to: string) => any;
39
35
  "update:selected": (value: string[]) => any;
40
- "update:columnVisibility": (value: Record<string, boolean>) => any;
41
36
  "update:sort": (value: TableSort | null) => any;
42
37
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
43
38
  onSelect?: ((event: Event, row: {
44
39
  original: Row;
45
40
  }) => any) | undefined;
46
- onReorder?: ((from: string, to: string) => any) | undefined;
47
41
  "onUpdate:selected"?: ((value: string[]) => any) | undefined;
48
- "onUpdate:columnVisibility"?: ((value: Record<string, boolean>) => any) | undefined;
49
42
  "onUpdate:sort"?: ((value: TableSort | null) => any) | undefined;
50
43
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
51
44
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,6 +1,5 @@
1
1
  type __VLS_Props = {
2
2
  rows?: number;
3
- size?: 'sm' | 'md' | 'lg';
4
3
  color?: 'error';
5
4
  };
6
5
  type __VLS_ModelProps = {
@@ -2,7 +2,7 @@
2
2
  <textarea
3
3
  :rows="rows ?? 3"
4
4
  :value="model ?? ''"
5
- :class="['cms-field', `cms-field-${size ?? 'md'}`, { 'is-error': color === 'error' }]"
5
+ :class="['cms-field', 'cms-field-md', { 'is-error': color === 'error' }]"
6
6
  @input="model = $event.target.value"
7
7
  />
8
8
  </template>
@@ -10,7 +10,6 @@
10
10
  <script setup>
11
11
  defineProps({
12
12
  rows: { type: Number, required: false },
13
- size: { type: String, required: false },
14
13
  color: { type: String, required: false }
15
14
  });
16
15
  const model = defineModel({ type: [String, null] });
@@ -1,6 +1,5 @@
1
1
  type __VLS_Props = {
2
2
  rows?: number;
3
- size?: 'sm' | 'md' | 'lg';
4
3
  color?: 'error';
5
4
  };
6
5
  type __VLS_ModelProps = {
@@ -1,12 +1,21 @@
1
- export interface CmsConfirmState {
2
- open: boolean;
3
- message: string;
1
+ export interface CmsConfirmLink {
2
+ title: string;
3
+ meta: string;
4
+ to: string;
5
+ }
6
+ export interface CmsConfirmGroup {
7
+ title: string;
8
+ links: CmsConfirmLink[];
9
+ }
10
+ export interface CmsConfirmOptions {
4
11
  title?: string;
5
12
  confirmLabel?: string;
13
+ groups?: CmsConfirmGroup[];
14
+ }
15
+ export interface CmsConfirmState extends CmsConfirmOptions {
16
+ open: boolean;
17
+ message: string;
6
18
  resolve?: (value: boolean) => void;
7
19
  }
8
20
  export declare function useCmsConfirmState(): import("vue").Ref<CmsConfirmState, CmsConfirmState>;
9
- export declare function useCmsConfirm(): (message: string, options?: {
10
- title?: string;
11
- confirmLabel?: string;
12
- }) => Promise<boolean>;
21
+ export declare function useCmsConfirm(): (message: string, options?: CmsConfirmOptions) => Promise<boolean>;
@@ -10,6 +10,7 @@ export function useCmsConfirm() {
10
10
  message,
11
11
  title: options?.title,
12
12
  confirmLabel: options?.confirmLabel,
13
+ groups: options?.groups,
13
14
  resolve
14
15
  };
15
16
  });
@@ -17,7 +17,7 @@ export function useCmsCollection(name, options = {}) {
17
17
  export function useCmsPage(path, options = {}) {
18
18
  const { locale, key, default: fallback } = options;
19
19
  return useAsyncData(
20
- `cms-page:${String(path)}:${locale ?? ""}`,
20
+ key ?? `cms-page:${String(path)}:${locale ?? ""}`,
21
21
  async () => fallback ? fallback() : null
22
22
  );
23
23
  }
@@ -1,3 +1,4 @@
1
+ export declare function invalidateCmsMediaKeys(): void;
1
2
  export declare function useCmsMediaKeys(): {
2
3
  isMissing: (key: unknown) => boolean;
3
4
  remember: (key: string) => void;
@@ -6,9 +6,14 @@ function load() {
6
6
  known.value = result.source.kind === "none" ? null : new Set(result.items.map((item) => item.key));
7
7
  }).catch(() => {
8
8
  known.value = null;
9
+ loading = null;
9
10
  });
10
11
  return loading;
11
12
  }
13
+ export function invalidateCmsMediaKeys() {
14
+ loading = null;
15
+ known.value = null;
16
+ }
12
17
  export function useCmsMediaKeys() {
13
18
  if (import.meta.client) void load();
14
19
  function isMissing(key) {
@@ -71,5 +71,4 @@ export declare function useCmsMediaLibrary(): {
71
71
  usage: (keys: string[]) => Promise<Record<string, MediaUsage[]> | null>;
72
72
  };
73
73
  export type CmsMediaLibrary = ReturnType<typeof useCmsMediaLibrary>;
74
- export declare function usageSummary(usage: Record<string, MediaUsage[]> | null, keys: string[]): string;
75
- export declare function usageLink(usage: MediaUsage): string;
74
+ export declare function usageLink(usage: Pick<MediaUsage, 'collection' | 'id'>): string;
@@ -6,8 +6,10 @@ import {
6
6
  } from "../../shared/index.js";
7
7
  import { computed, ref } from "#imports";
8
8
  import { errorMessage } from "../utils/ui.js";
9
+ import { invalidateCmsMediaKeys } from "./cms-media-keys.js";
9
10
  import { useCmsToast } from "./cms-toast.js";
10
11
  const endpoint = "/api/cms/admin/media";
12
+ const USAGE_CHUNK = 1e3;
11
13
  export function useCmsMediaLibrary() {
12
14
  const toast = useCmsToast();
13
15
  const items = ref([]);
@@ -81,6 +83,7 @@ export function useCmsMediaLibrary() {
81
83
  method: "DELETE",
82
84
  query: { name, recursive: "true" }
83
85
  });
86
+ invalidateCmsMediaKeys();
84
87
  await reload({ quiet: true });
85
88
  });
86
89
  }
@@ -93,6 +96,7 @@ export function useCmsMediaLibrary() {
93
96
  function deleteItems(keys) {
94
97
  return attempt("Delete failed", async () => {
95
98
  await $fetch(`${endpoint}/delete`, { method: "POST", body: { keys } });
99
+ invalidateCmsMediaKeys();
96
100
  await reload({ quiet: true });
97
101
  });
98
102
  }
@@ -103,13 +107,18 @@ export function useCmsMediaLibrary() {
103
107
  });
104
108
  }
105
109
  async function usage(keys) {
106
- if (!keys.length) return {};
110
+ const unique = [...new Set(keys)];
111
+ if (!unique.length) return {};
107
112
  try {
108
- const result = await $fetch(`${endpoint}/usage`, {
109
- method: "POST",
110
- body: { keys }
111
- });
112
- return result.usage;
113
+ const merged = {};
114
+ for (let index = 0; index < unique.length; index += USAGE_CHUNK) {
115
+ const result = await $fetch(
116
+ `${endpoint}/usage`,
117
+ { method: "POST", body: { keys: unique.slice(index, index + USAGE_CHUNK) } }
118
+ );
119
+ Object.assign(merged, result.usage);
120
+ }
121
+ return merged;
113
122
  } catch {
114
123
  return null;
115
124
  }
@@ -133,19 +142,6 @@ export function useCmsMediaLibrary() {
133
142
  usage
134
143
  };
135
144
  }
136
- export function usageSummary(usage, keys) {
137
- if (!usage) return "";
138
- const entries = /* @__PURE__ */ new Set();
139
- let used = 0;
140
- for (const key of keys) {
141
- const list = usage[key] ?? [];
142
- if (list.length) used++;
143
- for (const item of list) entries.add(`${item.collection}:${item.id ?? ""}`);
144
- }
145
- if (!used) return "";
146
- const files = keys.length === 1 ? "It is" : `${used} of them are`;
147
- return `${files} used in ${entries.size} entr${entries.size === 1 ? "y" : "ies"}, which will keep a broken link.`;
148
- }
149
145
  export function usageLink(usage) {
150
146
  return usage.id === null ? `/cms/${usage.collection}` : `/cms/${usage.collection}/${usage.id}`;
151
147
  }
@@ -1,5 +1,4 @@
1
1
  import type { MediaItem } from '../../shared/index.js';
2
- export declare function matchesAccept(file: File, accept: string | undefined): boolean;
3
2
  export interface UploadEntry {
4
3
  file: File;
5
4
  directory: string | null;
@@ -39,7 +39,7 @@ async function mediaDimensions(file) {
39
39
  if (file.type.startsWith("video/")) return videoDimensions(file);
40
40
  return {};
41
41
  }
42
- export function matchesAccept(file, accept) {
42
+ function matchesAccept(file, accept) {
43
43
  if (!accept) return true;
44
44
  return accept.split(",").some((raw) => {
45
45
  const pattern = raw.trim().toLowerCase();
@@ -0,0 +1,4 @@
1
+ export declare function useCmsOverlay(close: () => void): {
2
+ activate: () => void;
3
+ deactivate: () => void;
4
+ };
@@ -0,0 +1,23 @@
1
+ import { onBeforeUnmount } from "#imports";
2
+ const stack = [];
3
+ function onKeydown(event) {
4
+ if (event.key !== "Escape") return;
5
+ stack[stack.length - 1]?.close();
6
+ }
7
+ export function useCmsOverlay(close) {
8
+ const entry = { close };
9
+ function activate() {
10
+ if (import.meta.server || stack.includes(entry)) return;
11
+ stack.push(entry);
12
+ if (stack.length === 1) document.addEventListener("keydown", onKeydown);
13
+ }
14
+ function deactivate() {
15
+ if (import.meta.server) return;
16
+ const index = stack.indexOf(entry);
17
+ if (index === -1) return;
18
+ stack.splice(index, 1);
19
+ if (stack.length === 0) document.removeEventListener("keydown", onKeydown);
20
+ }
21
+ onBeforeUnmount(deactivate);
22
+ return { activate, deactivate };
23
+ }
@@ -7,7 +7,6 @@ export declare function useCmsSettings(): {
7
7
  reset: (name: string) => Promise<void>;
8
8
  };
9
9
  export declare function entryFields(name: string): Record<string, import("#nuxt-cms").FieldConfig>;
10
- export declare function defaultFormLayout(name: string, fields?: Record<string, import("#nuxt-cms").FieldConfig>): CmsFormLayout;
11
10
  export declare function entryFormLayout(name: string, settings: CmsSettingsMap, fields?: Record<string, import("#nuxt-cms").FieldConfig>): CmsFormLayout;
12
11
  export declare function listExtraColumns(name: string): string[];
13
12
  export declare function entryListColumns(name: string, settings: CmsSettingsMap): string[];
@@ -36,7 +36,7 @@ export function entryFields(name) {
36
36
  if (!entry) return {};
37
37
  return entry.kind === "page" ? pageAllFields(entry) : entry.fields;
38
38
  }
39
- export function defaultFormLayout(name, fields = entryFields(name)) {
39
+ function defaultFormLayout(name, fields = entryFields(name)) {
40
40
  return resolveFormLayout(fields, layoutFromConfig(entryOf(name)?.layout));
41
41
  }
42
42
  export function entryFormLayout(name, settings, fields = entryFields(name)) {
@@ -154,6 +154,7 @@ async function save() {
154
154
  toast.add({ title: "Saved", color: "success" });
155
155
  goBack();
156
156
  } catch (error) {
157
+ revertStatus();
157
158
  toast.add({
158
159
  title: "Save failed",
159
160
  description: errorMessage(error),
@@ -1,7 +1,5 @@
1
1
  import type { InjectionKey, Reactive } from 'vue';
2
2
  import type { FieldConfig } from '#nuxt-cms';
3
- /** Shared reactive map of field-name -> error message, provided by CmsForm and
4
- * read by CmsFormField to render inline validation errors. */
5
3
  export declare const CMS_FORM_ERRORS: InjectionKey<Reactive<Record<string, string>>>;
6
4
  export declare function errorMessage(error: unknown): string | undefined;
7
5
  export declare function fieldIcon(field: FieldConfig): string;