@opengis/cms 0.0.21 → 0.0.22

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 (183) hide show
  1. package/package.json +2 -2
  2. package/src/App.css +52 -0
  3. package/src/App.vue +62 -0
  4. package/src/assets/image.png +0 -0
  5. package/src/assets/main.css +3 -0
  6. package/src/assets/tailwind-3.4.17.js +113 -0
  7. package/src/components/LanguageSwitcher.vue +73 -0
  8. package/src/components/SettingsCard.vue +40 -0
  9. package/src/components/builder/CreateForm.vue +128 -0
  10. package/src/components/builder/formTypeSchema.js +145 -0
  11. package/src/components/builder/tabs/index.ts +9 -0
  12. package/src/components/builder/tabs/vs-builder-edit.vue +133 -0
  13. package/src/components/builder/tabs/vs-builder-monaco.vue +29 -0
  14. package/src/components/builder/tabs/vs-builder-preview.vue +39 -0
  15. package/src/components/builder/vs-builder-datatable-controls.vue +138 -0
  16. package/src/components/builder/vs-builder-datatable-form.vue +80 -0
  17. package/src/components/builder/vs-builder-datatable.vue +191 -0
  18. package/src/components/builder/vs-builder-list-item.vue +110 -0
  19. package/src/components/collections/CollectionsBreadcrumb.vue +52 -0
  20. package/src/components/collections/CollectionsGrid.vue +176 -0
  21. package/src/components/collections/ContentBlock.vue +75 -0
  22. package/src/components/collections/formWrapper.vue +156 -0
  23. package/src/components/dashboard/ContentItem.vue +82 -0
  24. package/src/components/dashboard/DashboardHeader.vue +33 -0
  25. package/src/components/dashboard/QuickActions.vue +84 -0
  26. package/src/components/dashboard/RecentContent.vue +54 -0
  27. package/src/components/dashboard/StatCard.vue +63 -0
  28. package/src/components/dashboard/StatsGrid.vue +28 -0
  29. package/src/components/form-components/MonacoEditor.vue +104 -0
  30. package/src/components/form-components/VsFormMeta.vue +40 -0
  31. package/src/components/form-components/VsFormTags.vue +150 -0
  32. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-add.vue +84 -0
  33. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-controls.vue +106 -0
  34. package/src/components/form-components/index.js +23 -0
  35. package/src/components/form-components/reference/vs-form-reference-add.vue +92 -0
  36. package/src/components/form-components/reference/vs-form-reference-controls.vue +101 -0
  37. package/src/components/form-components/reference-list/referenceOptionList.js +78 -0
  38. package/src/components/form-components/reference-list/vs-form-reference-add.vue +145 -0
  39. package/src/components/form-components/reference-list/vs-form-reference-choce.vue +39 -0
  40. package/src/components/form-components/reference-list/vs-form-reference-controls.vue +110 -0
  41. package/src/components/form-components/reference-skeleton/about-skeleton.vue +37 -0
  42. package/src/components/form-components/reference-skeleton/banner-skeleton.vue +29 -0
  43. package/src/components/form-components/reference-skeleton/body-skeleton.vue +56 -0
  44. package/src/components/form-components/reference-skeleton/cards-skeleton.vue +47 -0
  45. package/src/components/form-components/reference-skeleton/documents-skeleton.vue +64 -0
  46. package/src/components/form-components/reference-skeleton/faq-skeleton.vue +64 -0
  47. package/src/components/form-components/reference-skeleton/form-skeleton.vue +41 -0
  48. package/src/components/form-components/reference-skeleton/index.js +36 -0
  49. package/src/components/form-components/reference-skeleton/infoLine-skeleton.vue +37 -0
  50. package/src/components/form-components/reference-skeleton/news-skeleton.vue +54 -0
  51. package/src/components/form-components/reference-skeleton/slider-skeleton.vue +41 -0
  52. package/src/components/form-components/reference-skeleton/tabs-skeleton.vue +40 -0
  53. package/src/components/form-components/reference-skeleton/team-skeleton.vue +103 -0
  54. package/src/components/form-components/reference-skeleton/usefulLinks-skeleton.vue +52 -0
  55. package/src/components/form-components/reference-skeleton/video-skeleton.vue +36 -0
  56. package/src/components/form-components/testReferenceTypes.js +773 -0
  57. package/src/components/form-components/vs-form-color-picker.vue +29 -0
  58. package/src/components/form-components/vs-form-custom-datatable.vue +214 -0
  59. package/src/components/form-components/vs-form-integer.vue +86 -0
  60. package/src/components/form-components/vs-form-key-value.vue +201 -0
  61. package/src/components/form-components/vs-form-marcdown-md.vue +3 -0
  62. package/src/components/form-components/vs-form-media-select.vue +780 -0
  63. package/src/components/form-components/vs-form-reference-list.vue +97 -0
  64. package/src/components/form-components/vs-form-reference.vue +59 -0
  65. package/src/components/form-components/vs-form-relation.vue +30 -0
  66. package/src/components/form-components/vs-form-reletion-link.vue +34 -0
  67. package/src/components/form-components/vs-form-select-collection.vue +0 -0
  68. package/src/components/form-components/vs-form-slug.vue +72 -0
  69. package/src/components/form-components/vs-form-tiptap.vue +7 -0
  70. package/src/components/form-components/vs-richtext-md.vue +3 -0
  71. package/src/components/icons/BellIcon.vue +17 -0
  72. package/src/components/icons/GlobeIcon.vue +18 -0
  73. package/src/components/icons/KeyIcon.vue +20 -0
  74. package/src/components/icons/PaletteIcon.vue +22 -0
  75. package/src/components/icons/SettingsIcon.vue +19 -0
  76. package/src/components/icons/ShieldIcon.vue +18 -0
  77. package/src/components/icons/UsersIcon.vue +19 -0
  78. package/src/components/icons/icon-chevron-right.vue +16 -0
  79. package/src/components/icons/icon-drag.vue +20 -0
  80. package/src/components/icons/icon-file-text.vue +21 -0
  81. package/src/components/icons/icon-folder.vue +18 -0
  82. package/src/components/icons/icon-grid.vue +17 -0
  83. package/src/components/icons/icon-group.vue +19 -0
  84. package/src/components/icons/icon-home.vue +16 -0
  85. package/src/components/icons/icon-image.vue +18 -0
  86. package/src/components/icons/icon-list.vue +20 -0
  87. package/src/components/icons/icon-more.vue +17 -0
  88. package/src/components/icons/icon-plus.vue +17 -0
  89. package/src/components/icons-types/icon-array.vue +22 -0
  90. package/src/components/icons-types/icon-boolean.vue +18 -0
  91. package/src/components/icons-types/icon-datalist.vue +22 -0
  92. package/src/components/icons-types/icon-date.vue +20 -0
  93. package/src/components/icons-types/icon-datetime.vue +20 -0
  94. package/src/components/icons-types/icon-file.vue +21 -0
  95. package/src/components/icons-types/icon-gallery.vue +18 -0
  96. package/src/components/icons-types/icon-image.vue +19 -0
  97. package/src/components/icons-types/icon-integer.vue +20 -0
  98. package/src/components/icons-types/icon-merkdown.vue +18 -0
  99. package/src/components/icons-types/icon-multiselect.vue +22 -0
  100. package/src/components/icons-types/icon-number.vue +20 -0
  101. package/src/components/icons-types/icon-radio.vue +22 -0
  102. package/src/components/icons-types/icon-reference-list.vue +22 -0
  103. package/src/components/icons-types/icon-reference.vue +20 -0
  104. package/src/components/icons-types/icon-relation.vue +22 -0
  105. package/src/components/icons-types/icon-richtext.vue +18 -0
  106. package/src/components/icons-types/icon-select.vue +22 -0
  107. package/src/components/icons-types/icon-slug.vue +19 -0
  108. package/src/components/icons-types/icon-text.vue +19 -0
  109. package/src/components/icons-types/index.js +43 -0
  110. package/src/components/layout/Layout.vue +67 -0
  111. package/src/components/layout/Sidebar.vue +128 -0
  112. package/src/components/media/FileUploadProgress.vue +29 -0
  113. package/src/components/media/MediaBreadcrumb.vue +42 -0
  114. package/src/components/media/MediaCreateFolder.vue +59 -0
  115. package/src/components/media/MediaFileInfo.vue +148 -0
  116. package/src/components/media/MediaGrid.vue +148 -0
  117. package/src/components/media/MediaList.vue +148 -0
  118. package/src/components/media/MediaViewControls.vue +38 -0
  119. package/src/components/media/TypeTag.vue +23 -0
  120. package/src/components/menu/AddNewItemInTree.vue +75 -0
  121. package/src/components/menu/MenuBody.vue +149 -0
  122. package/src/components/menu/MenuItem.vue +73 -0
  123. package/src/components/menu/MenuList.vue +101 -0
  124. package/src/components/referencec/index.ts +7 -0
  125. package/src/components/referencec/vs-reference-faq.vue +61 -0
  126. package/src/components/referencec/vs-reference-user-card.vue +40 -0
  127. package/src/components/settings/NotificationSettings.vue +32 -0
  128. package/src/components/settings/SettingsTable.vue +50 -0
  129. package/src/components/settings/SettingsTitle.vue +33 -0
  130. package/src/components/settings/SettingsToggleItem.vue +25 -0
  131. package/src/components/sidebar/DropdownMenu.vue +34 -0
  132. package/src/components/sidebar/SettingsSidebar.vue +121 -0
  133. package/src/components/sidebar/SidebarFooter.vue +52 -0
  134. package/src/components/sidebar/SidebarHeader.vue +57 -0
  135. package/src/components/sidebar/SidebarMenu.vue +78 -0
  136. package/src/components/ui/EmptyData.vue +76 -0
  137. package/src/components/ui/UniversalTable.vue +310 -0
  138. package/src/components/ui/UniversalTableFilters.vue +0 -0
  139. package/src/components/ui/UniversalTablePagination.vue +118 -0
  140. package/src/components/ui/VsPreview.vue +75 -0
  141. package/src/composables/useCollectionView.ts +21 -0
  142. package/src/composables/useDebounce.ts +26 -0
  143. package/src/composables/useMonaco.ts +28 -0
  144. package/src/composables/useTheme.ts +40 -0
  145. package/src/content/test-slug/metadata.json +1 -0
  146. package/src/i18n.ts +75 -0
  147. package/src/index.css +3 -0
  148. package/src/locales/en.json +778 -0
  149. package/src/locales/uk.json +797 -0
  150. package/src/main.ts +41 -0
  151. package/src/pages/Dashboard.vue +168 -0
  152. package/src/pages/EmailPage.vue +183 -0
  153. package/src/pages/FeedbackPage.vue +232 -0
  154. package/src/pages/MediaPage.vue +372 -0
  155. package/src/pages/TagsPage.vue +207 -0
  156. package/src/pages/builder/BuilderPage.vue +195 -0
  157. package/src/pages/builder/EditCollectionPage.vue +163 -0
  158. package/src/pages/collections/ArticlesPage.vue +385 -0
  159. package/src/pages/collections/CollectionsPage.vue +146 -0
  160. package/src/pages/collections/SingletonsPage.vue +119 -0
  161. package/src/pages/collections/contentForm.vue +484 -0
  162. package/src/pages/collections/schema/seo.ts +27 -0
  163. package/src/pages/menu/MenuAddPage.vue +123 -0
  164. package/src/pages/menu/MenuItemPage.vue +183 -0
  165. package/src/pages/menu/MenuPage.vue +133 -0
  166. package/src/pages/settings/ApiKeys.vue +75 -0
  167. package/src/pages/settings/Appearance.vue +80 -0
  168. package/src/pages/settings/Logs.vue +260 -0
  169. package/src/pages/settings/PermissionsPage.vue +237 -0
  170. package/src/pages/settings/Settings.vue +186 -0
  171. package/src/pages/settings/Users.vue +109 -0
  172. package/src/pages/settings/general.vue +154 -0
  173. package/src/pages/settings/generalScheme.js +132 -0
  174. package/src/pages/users/AddUser.vue +106 -0
  175. package/src/pages/users/UsersPage.vue +98 -0
  176. package/src/props/builder.ts +67 -0
  177. package/src/props/content.ts +56 -0
  178. package/src/props/media.ts +63 -0
  179. package/src/router/index.ts +181 -0
  180. package/src/types/fastify-auth.d.ts +4 -0
  181. package/src/utils/getField.js +270 -0
  182. package/src/utils/translit.js +19 -0
  183. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,138 @@
1
+ <template>
2
+ <div class="flex items-center justify-end col-span-3 gap-2">
3
+ <button
4
+ v-if="!['status']?.includes(data.name)"
5
+ @click="dialog = true"
6
+ class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 hover:text-accent-foreground h-8 w-8 rounded-full hover:bg-gray-100"
7
+ >
8
+ <Edit class="w-4 h-4" /></button
9
+ ><button
10
+ v-if="!data.required"
11
+ @click="openConfirm"
12
+ class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 h-8 w-8 rounded-full hover:bg-red-100 text-red-600 hover:text-red-700"
13
+ >
14
+ <Trash class="w-4 h-4" />
15
+ </button>
16
+ <button v-else class="w-8 h-4"></button>
17
+ <VsModal
18
+ teleport="#modal"
19
+ :visible="dialog"
20
+ :title="$t('builder.editField')"
21
+ @close="dialog = false"
22
+ >
23
+ <VsForm v-model="formValue" :schema="schema" v-model:form="form" />
24
+ <template #footer>
25
+ <div class="flex justify-end p-[20px] gap-[10px] border-t w-full">
26
+ <button
27
+ class="inline-flex items-center px-3 py-2 text-sm text-black duration-300 border border-gray-200 rounded-lg gap-x-2 whitespace-nowrap hover:bg-gray-100"
28
+ @click="dialog = false"
29
+ >
30
+ {{ $t("common.actions.cancel") }}
31
+ </button>
32
+ <button
33
+ class="py-2 px-3 inline-flex items-center gap-x-2 text-sm whitespace-nowrap text-white bg-blue-500 rounded-lg !border-gray-200 hover:bg-blue-700 duration-300"
34
+ @click="editColumn"
35
+ >
36
+ {{ $t("common.actions.save") }}
37
+ </button>
38
+ </div>
39
+ </template>
40
+ </VsModal>
41
+ </div>
42
+ </template>
43
+
44
+ <script setup>
45
+ import { Edit, Trash } from "lucide-vue-next";
46
+ import { formTypeSchema } from "./formTypeSchema.js";
47
+ import { ref, onMounted, computed } from "vue";
48
+ import { confirm, notify } from '@opengis/core';
49
+ import { useI18n } from "vue-i18n";
50
+ import VsForm from "@opengis/form";
51
+ import { VsModal } from "@opengis/core";
52
+ const { t } = useI18n();
53
+ // import VsForm from '../../../../form/src/index'
54
+
55
+ const props = defineProps({
56
+ index: {
57
+ type: Number,
58
+ required: true,
59
+ },
60
+ data: {
61
+ type: Object,
62
+ required: true,
63
+ },
64
+ });
65
+
66
+ const columns = defineModel("columns", {
67
+ type: Array,
68
+ default: () => [],
69
+ });
70
+ const dialog = ref(false);
71
+ const form = ref({});
72
+ const formValue = ref({ ...(props.data || {}) });
73
+
74
+ const schema = ref({});
75
+
76
+ onMounted(() => {
77
+ if (props.data.required) {
78
+
79
+ schema.value = {
80
+ ...formTypeSchema(0, t),
81
+ name: {
82
+ ...formTypeSchema(0, t).name,
83
+ disabled: true,
84
+ },
85
+ label: {
86
+ ...formTypeSchema(0, t).label,
87
+ disabled: true,
88
+ },
89
+ type: {
90
+ ...formTypeSchema(0, t).type,
91
+ disabled: true,
92
+ },
93
+ }
94
+ } else {
95
+ schema.value = formTypeSchema(0, t);
96
+ }
97
+ });
98
+
99
+ const openConfirm = () => {
100
+ confirm({
101
+ title: t("builder.deleteTitle"),
102
+ message: t("builder.deleteField"),
103
+ type: 'error',
104
+ onConfirm: () => {
105
+ deleteColumn();
106
+ },
107
+ })
108
+ };
109
+
110
+ const deleteColumn = () => {
111
+ columns.value = columns.value.filter((_, index) => index !== props.index);
112
+ };
113
+
114
+ const editColumn = async () => {
115
+ let result = await form.value.validate();
116
+
117
+ if (result) {
118
+ notify({
119
+ type: "warning",
120
+ title: t("common.actions.warning"),
121
+ message: t("builder.editFieldFailed"),
122
+ });
123
+ return;
124
+ }
125
+ try {
126
+ columns.value[props.index] = formValue.value;
127
+
128
+ dialog.value = false;
129
+ } catch (error) {
130
+ console.log(error);
131
+ }
132
+ };
133
+
134
+
135
+
136
+ </script>
137
+
138
+ <style lang="scss" scoped></style>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div>
3
+ <button
4
+ @click="dialog = true"
5
+ class="inline-flex items-center justify-center h-10 gap-2 px-4 py-2 text-sm font-medium transition-colors border rounded-md hover hover:bg-gray-200 whitespace-nowrap ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring 0"
6
+ >
7
+ <Plus class="w-4 h-4 mr-2" />
8
+ {{ $t("common.actions.addField") }}
9
+ </button>
10
+ <VsModal teleport="#modal" :title="$t('builder.createField')" size="small" v-model:visible="dialog" @close="dialog = false">
11
+ <VForm v-model="formValue" :schema="scheme" v-model:form="form" />
12
+ <template #footer>
13
+ <div class="flex justify-end p-[20px] gap-[10px] border-t w-full">
14
+ <button
15
+ class="inline-flex items-center px-3 py-2 text-sm text-black duration-300 border border-gray-200 rounded-lg gap-x-2 whitespace-nowrap hover:bg-gray-100"
16
+ @click="dialog = false"
17
+ >
18
+ {{ $t("common.actions.cancel") }}
19
+ </button>
20
+ <button
21
+ @click="createField"
22
+ class="py-2 px-3 inline-flex items-center gap-x-2 text-sm whitespace-nowrap text-white bg-blue-500 rounded-lg !border-gray-200 hover:bg-blue-700 duration-300"
23
+ >
24
+ {{ $t("common.actions.save") }}
25
+ </button>
26
+ </div>
27
+ </template>
28
+ </VsModal>
29
+ </div>
30
+ </template>
31
+
32
+ <script setup>
33
+ import { ref, computed, watch } from "vue";
34
+ import { Plus } from "lucide-vue-next";
35
+ import { formTypeSchema } from "./formTypeSchema";
36
+ import { VForm,inputs } from "@opengis/form";
37
+ import { VsModal, notify } from "@opengis/core";
38
+ import { useI18n } from "vue-i18n";
39
+ const { t } = useI18n();
40
+ // import { VForm,inputs } from '../../../../form/src/index'
41
+
42
+ inputs['vs-input-datalist'] = inputs.VsInputDatatable;
43
+
44
+
45
+ const columns = defineModel({
46
+ type: Array,
47
+ default: () => [],
48
+ });
49
+
50
+ const dialog = ref(false);
51
+ const form = ref({});
52
+ const formValue = ref({});
53
+
54
+ const scheme = computed(() => {
55
+ const i = formValue.value;
56
+ return formTypeSchema(0, t);
57
+ });
58
+
59
+ const createField = async () => {
60
+ let result = await form.value.validate();
61
+ if (result) {
62
+ notify({
63
+ type: "warning",
64
+ title: t("common.actions.warning"),
65
+ message: t("builder.createFieldFailed"),
66
+ });
67
+ return;
68
+ }
69
+
70
+ try {
71
+ columns.value = [...columns.value, formValue.value];
72
+ formValue.value = {};
73
+ dialog.value = false;
74
+ } catch (error) {
75
+ console.log(error);
76
+ }
77
+ };
78
+ </script>
79
+
80
+ <style lang="scss" scoped></style>
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <div class="flex items-center justify-between mb-6">
3
+ <div>
4
+ <h2 class="text-xl font-semibold text-gray-900">{{ $t("builder.collectionStructure") }}</h2>
5
+ <p class="mt-1 text-sm text-gray-600">
6
+ {{ $t("builder.defineFields") }}
7
+ </p>
8
+ </div>
9
+ <div class="flex items-center gap-2">
10
+ <VSBuilderDatatableForm v-model="data.columns" />
11
+ </div>
12
+ </div>
13
+ <div
14
+ class="overflow-hidden bg-white border border-gray-200 shadow-sm rounded-xl"
15
+ >
16
+ <div
17
+ class="grid grid-cols-12 gap-4 px-6 py-4 border-b border-gray-200 bg-gray-50"
18
+ >
19
+ <div class="col-span-5 font-medium text-gray-700">{{ $t("builder.name") }}</div>
20
+ <div class="col-span-3 font-medium text-gray-700">{{ $t("builder.type") }}</div>
21
+ <div class="col-span-2 font-medium text-gray-700">{{ $t("builder.localization") }}</div>
22
+ <div class="col-span-2 font-medium text-right text-gray-700">{{ $t("builder.actions") }}</div>
23
+ </div>
24
+ <div class="divide-y divide-gray-100">
25
+ <template v-if="data?.columns?.length">
26
+ <draggable
27
+ v-model="data.columns"
28
+ item-key="name"
29
+ handle=".drag-handle"
30
+ :animation="200"
31
+ >
32
+ <template #item="{ element: column, index }">
33
+ <div
34
+ class="grid items-center grid-cols-12 gap-4 px-6 py-4 transition-colors hover:bg-gray-50/50"
35
+ >
36
+ <div class="flex items-center col-span-5 gap-3">
37
+ <span class="drag-handle cursor-move mr-2 text-gray-400"
38
+ >☰</span
39
+ >
40
+ <div
41
+ class="flex items-center justify-center p-1 rounded"
42
+ :class="`bg-${getColorType(column.type?.toLowerCase())}-100`"
43
+ >
44
+ <component :is="getIconType(column.type?.toLowerCase())" class="w-4 h-4" />
45
+ </div>
46
+ <div>
47
+ <p class="font-medium text-gray-900">{{ column.label }}</p>
48
+ <p class="text-xs text-gray-500">{{ column.name }}</p>
49
+ </div>
50
+ <span
51
+ v-if="column.required"
52
+ class="inline-flex items-center px-2 py-1 text-xs font-medium text-blue-700 rounded-full bg-blue-50 ring-1 ring-inset ring-blue-700/10"
53
+ >{{ $t("builder.required") }}</span
54
+ >
55
+ </div>
56
+ <div class="col-span-3">
57
+ <span
58
+ class="inline-flex items-center px-2 py-1 text-sm font-medium text-gray-600 rounded-md bg-gray-50 ring-1 ring-inset ring-gray-500/10"
59
+ >{{ column.type }}</span
60
+ >
61
+ </div>
62
+ <div class="col-span-1">
63
+ <svg
64
+ v-if="column.localization"
65
+ xmlns="http://www.w3.org/2000/svg"
66
+ width="24"
67
+ height="24"
68
+ viewBox="0 0 24 24"
69
+ fill="none"
70
+ stroke="currentColor"
71
+ stroke-width="2"
72
+ stroke-linecap="round"
73
+ stroke-linejoin="round"
74
+ class="lucide lucide-circle-check w-4 h-4 text-emerald-600"
75
+ >
76
+ <circle cx="12" cy="12" r="10"></circle>
77
+ <path d="m9 12 2 2 4-4"></path>
78
+ </svg>
79
+ </div>
80
+
81
+ <VSBuilderDatatableControls
82
+ v-model:columns="data.columns"
83
+ :data="data.columns[index]"
84
+ :index
85
+ />
86
+ </div>
87
+ </template>
88
+ </draggable>
89
+ </template>
90
+ <template v-else>
91
+ <div
92
+ class="grid items-center grid-cols-12 gap-4 px-6 py-4 transition-colors hover:bg-gray-50/50"
93
+ >
94
+ <div class="col-span-5">
95
+ <p class="text-gray-500">{{ $t("builder.noColumnsFound") }}</p>
96
+ </div>
97
+ </div>
98
+ </template>
99
+ </div>
100
+ </div>
101
+ </template>
102
+
103
+ <script setup>
104
+ import VSBuilderDatatableForm from "./vs-builder-datatable-form.vue";
105
+ import VSBuilderDatatableControls from "./vs-builder-datatable-controls.vue";
106
+ import draggable from "vuedraggable";
107
+ import { List, CheckSquare, Calendar, Clock, Hash, Type, File, ListTree, Link, Image as LucideImage, LayoutTemplate } from "lucide-vue-next";
108
+
109
+ const data = defineModel();
110
+
111
+ const getColorType = (type) => {
112
+ if (type === "array") {
113
+ return "purple";
114
+ }
115
+ if (type === "boolean") {
116
+ return "red";
117
+ }
118
+ if (type === "date") {
119
+ return "red";
120
+ }
121
+ if (type === "datetime") {
122
+ return "purple";
123
+ }
124
+ if (type === "number") {
125
+ return "green";
126
+ }
127
+ if (type === "text") {
128
+ return "blue";
129
+ }
130
+ if (type === "file") {
131
+ return "yellow";
132
+ }
133
+ if (type === "select") {
134
+ return "yellow";
135
+ }
136
+ if (type === "slug") {
137
+ return "green";
138
+ }
139
+ if (type === "image") {
140
+ return "blue";
141
+ }
142
+ return "gray";
143
+ };
144
+
145
+ const getIconType = (type) => {
146
+ switch (type) {
147
+ case "text":
148
+ return Type;
149
+ case "number":
150
+ return Hash;
151
+ case "integer":
152
+ return Hash;
153
+ case "date":
154
+ return Calendar;
155
+ case "datetime":
156
+ return Clock;
157
+ case "file":
158
+ return File;
159
+ case "select":
160
+ return ListTree;
161
+ case "multiselect":
162
+ return List;
163
+ case "mediaselect":
164
+ return Image;
165
+ case "radio":
166
+ return CheckSquare;
167
+ case "boolean":
168
+ return CheckSquare;
169
+ case "datalist":
170
+ return ListTree;
171
+ case "image":
172
+ return LucideImage;
173
+ case "slug":
174
+ return Link;
175
+ case "richtext":
176
+ return Type;
177
+ case "markdown":
178
+ return Type;
179
+ case "reference":
180
+ return LayoutTemplate;
181
+ case "relation":
182
+ return Link;
183
+ case "FileList":
184
+ return File;
185
+ default:
186
+ return Type;
187
+ }
188
+ };
189
+ </script>
190
+
191
+ <style lang="scss" scoped></style>
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div
3
+ class="p-4 transition-shadow border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-700 dark:border-gray-600 hover:shadow-md"
4
+ >
5
+ <div class="flex items-start justify-between">
6
+ <div class="flex items-center">
7
+ <Database class="w-5 h-5 mr-2 text-sky-500" />
8
+ <h3
9
+ class="text-lg font-medium text-gray-900 cursor-pointer dark:text-white hover:underline"
10
+ @click="handleGoToContent(collection)"
11
+ >
12
+ {{ collection.title }}
13
+ </h3>
14
+ </div>
15
+ <div class="flex space-x-2">
16
+ <button
17
+ @click="handleEditCollection(collection)"
18
+ class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300"
19
+ >
20
+ <Edit class="w-4 h-4" />
21
+ </button>
22
+ <button
23
+ @click="openConfirm"
24
+ class="text-gray-400 hover:text-red-500 dark:hover:text-red-400"
25
+ >
26
+ <Trash2 class="w-4 h-4" />
27
+ </button>
28
+ </div>
29
+ </div>
30
+ <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
31
+ {{ collection.description }}
32
+ </p>
33
+ <div class="mt-4">
34
+ <h4
35
+ class="text-xs font-medium tracking-wider text-gray-500 uppercase dark:text-gray-400"
36
+ >
37
+ {{ $t("collections.form.fields") }}
38
+ </h4>
39
+ <div class="flex flex-wrap gap-2 mt-2">
40
+ <span
41
+ v-for="(field, index) in collection.fields"
42
+ :key="index"
43
+ class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-600 dark:text-gray-300"
44
+ >
45
+ {{ field.label }}
46
+ </span>
47
+ <button class="px-2 py-1 text-xs text-white bg-blue-500 rounded-lg">
48
+ {{ collection?.type || "single" }}
49
+ </button>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { Database, Edit, Trash2 } from "lucide-vue-next";
57
+ import { useRouter } from "vue-router";
58
+ import { confirm } from '@opengis/core';
59
+ import { useI18n } from "vue-i18n";
60
+ const { t } = useI18n();
61
+
62
+ interface Field {
63
+ name: string;
64
+ type: "text" | "textarea" | "number" | "date" | "select" | "boolean";
65
+ label: string;
66
+ required: boolean;
67
+ options?: string[];
68
+ }
69
+
70
+ interface Collection {
71
+ id: string;
72
+ name: string;
73
+ title: string;
74
+ slug: string;
75
+ description: string;
76
+ fields: Field[];
77
+ type: string;
78
+ }
79
+
80
+ const router = useRouter();
81
+ const props = defineProps<{
82
+ collection: any;
83
+ handleDeleteCollection: (collection: any) => void;
84
+ }>();
85
+
86
+ const openConfirm = () => {
87
+ confirm({
88
+ title: t("builder.deleteTitle"),
89
+ message: t("builder.deleteField"),
90
+ type: 'error',
91
+ onConfirm: () => {
92
+ props.handleDeleteCollection(props.collection.id);
93
+ },
94
+ })
95
+ };
96
+
97
+ const handleEditCollection = (collection: Collection) => {
98
+ router.push(`/settings/collections/edit/${collection.id || collection.name}`);
99
+ };
100
+
101
+ const handleGoToContent = (collection: Collection) => {
102
+ if (collection.type === "single") {
103
+ router.push(`/collections/single/${collection.name}`);
104
+ } else {
105
+ router.push(`/collections/${collection.name}`);
106
+ }
107
+ };
108
+ </script>
109
+
110
+ <style scoped></style>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <div class="flex items-center space-x-1 mb-4">
3
+ <button
4
+ class="flex gap-x-1 items-center px-2 py-1 rounded text-sm font-medium transition-all duration-200 text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/30"
5
+ @click="$emit('navigate', 'collections')"
6
+ >
7
+ <Layers class="w-3 h-3" />
8
+ {{ $t("navigation.collections") }}
9
+ </button>
10
+ <ChevronRight
11
+ v-if="items.length > 0"
12
+ class="w-3 h-3 text-slate-400 dark:text-slate-500"
13
+ />
14
+ <template v-for="(item, index) in items" :key="index">
15
+ <button
16
+ v-if="index < items.length - 1"
17
+ class="flex gap-x-1 items-center px-2 py-1 rounded text-sm font-medium transition-all duration-200 text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/30"
18
+ @click="$emit('navigate', item.route)"
19
+ >
20
+ {{ item.label }}
21
+ </button>
22
+ <span
23
+ v-else
24
+ class="flex gap-x-1 items-center px-2 py-1 rounded text-sm font-medium text-slate-700 dark:text-slate-300"
25
+ >
26
+ {{ item.label }}
27
+ </span>
28
+ <ChevronRight
29
+ v-if="index < items.length - 1"
30
+ class="w-3 h-3 text-slate-400 dark:text-slate-500"
31
+ />
32
+ </template>
33
+ </div>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { ChevronRight, Layers } from "lucide-vue-next";
38
+
39
+ interface BreadcrumbItem {
40
+ label: string;
41
+ route: string;
42
+ }
43
+
44
+ defineProps<{
45
+ items: BreadcrumbItem[];
46
+ }>();
47
+
48
+ defineEmits<{
49
+ (e: "navigate", route: string): void;
50
+ }>();
51
+ </script>
52
+