@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,73 @@
1
+ <template>
2
+ <div class="relative shrink-0" ref="dropdownRef">
3
+ <button
4
+ @click="isOpen = !isOpen"
5
+ class="rounded-md text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline-none flex items-center space-x-2"
6
+ aria-label="Select language"
7
+ >
8
+ <span class="text-xl">{{ currentLanguage }}</span>
9
+ </button>
10
+
11
+ <div
12
+ v-if="isOpen"
13
+ class="absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5"
14
+ >
15
+ <div class="py-1" role="menu" aria-orientation="vertical">
16
+ <button
17
+ v-for="(language, index) in languages"
18
+ :key="index"
19
+ @click="handleLanguageChange(language)"
20
+ class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center justify-between"
21
+ role="menuitem"
22
+ >
23
+ <div class="flex items-baseline space-x-2">
24
+ <span>{{ language }}</span>
25
+ </div>
26
+ <Check
27
+ v-if="currentLocale === language"
28
+ class="h-4 w-4 text-sky-500"
29
+ />
30
+ </button>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { ref, computed, onMounted, onUnmounted, getCurrentInstance } from 'vue';
38
+ import { setLocale, Locale } from '../i18n.ts';
39
+ import { useI18n } from 'vue-i18n';
40
+ import { Check } from 'lucide-vue-next';
41
+
42
+ const { locale } = useI18n();
43
+ const app = getCurrentInstance();
44
+
45
+ const languages = app?.appContext.config.globalProperties.$settings.locales;
46
+
47
+ const isOpen = ref(false);
48
+ const dropdownRef = ref<HTMLDivElement | null>(null);
49
+
50
+ const currentLocale = computed(() => locale.value);
51
+ const currentLanguage = computed(() => languages?.find(lang => lang === currentLocale.value));
52
+
53
+ const handleLanguageChange = async (langCode: string) => {
54
+ console.log('Changing language to:', langCode);
55
+ await setLocale(langCode as Locale);
56
+ console.log('Language changed to:', locale.value);
57
+ isOpen.value = false;
58
+ };
59
+
60
+ const handleClickOutside = (event: MouseEvent) => {
61
+ if (dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {
62
+ isOpen.value = false;
63
+ }
64
+ };
65
+
66
+ onMounted(() => {
67
+ document.addEventListener('mousedown', handleClickOutside);
68
+ });
69
+
70
+ onUnmounted(() => {
71
+ document.removeEventListener('mousedown', handleClickOutside);
72
+ });
73
+ </script>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div
3
+ class="rounded-xl text-card-foreground shadow-lg border-0 bg-white dark:bg-slate-800 backdrop-blur-sm hover:shadow-xl transition-all duration-200 transform hover:scale-105 cursor-pointer"
4
+ >
5
+ <div
6
+ class="flex flex-col space-y-1.5 p-6 border-b border-slate-200 dark:border-slate-700 bg-gradient-to-r from-slate-50 dark:from-slate-800 to-white dark:to-slate-800"
7
+ >
8
+ <h3
9
+ class="tracking-tight text-lg font-semibold text-slate-800 dark:text-slate-100 flex items-center"
10
+ >
11
+ <slot name="icon" />
12
+ {{ title }}
13
+ </h3>
14
+ </div>
15
+ <div class="p-6">
16
+ <p class="text-slate-600 dark:text-slate-300 mb-6">
17
+ {{ description }}
18
+ </p>
19
+ <button @click="goTo(path)"
20
+ class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border shadow-sm hover:text-accent-foreground h-9 px-4 py-2 w-full bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 text-slate-700 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-600"
21
+ >
22
+ {{ buttonText }}
23
+ </button>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { useRouter } from 'vue-router'
30
+ defineProps<{
31
+ path: string
32
+ title: string
33
+ description: string
34
+ buttonText?: string
35
+ }>()
36
+ const router = useRouter()
37
+ const goTo = (path: string) => {
38
+ router.push(path)
39
+ }
40
+ </script>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <div>
3
+ <button
4
+ @click="isOpen = true"
5
+ class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white shadow-md hover:shadow-lg transition-all duration-200 transform hover:scale-105"
6
+ >
7
+ <Plus class="w-4 h-4 mr-2" />
8
+ {{ $t("collections.createCollection") }}
9
+ </button>
10
+
11
+ <VsModal
12
+ teleport="#modal"
13
+ :visible="isOpen"
14
+ :title="$t('collections.createCollection')"
15
+ @close="isOpen = false"
16
+ >
17
+ <VsForm v-model:form="form" v-model="values" :schema="scheme" />
18
+ <template #footer>
19
+ <div class="flex justify-end p-[20px] gap-[10px] border-t w-full">
20
+ <button
21
+ 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"
22
+ @click="isOpen = false"
23
+ >
24
+ {{ $t("common.actions.cancel") }}
25
+ </button>
26
+ <button
27
+ @click="handleCreateCollection"
28
+ 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"
29
+ >
30
+ {{ $t("common.actions.save") }}
31
+ </button>
32
+ </div>
33
+ </template>
34
+ </VsModal>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup>
39
+ import { Plus } from "lucide-vue-next";
40
+ import { useRouter } from "vue-router";
41
+ import { ref, inject } from "vue";
42
+ import { useI18n } from "vue-i18n";
43
+ import { notify } from '@opengis/core'
44
+ const fetchContentTypes = inject("fetchContentTypes");
45
+ import VsForm from "@opengis/form";
46
+ import { VsModal } from "@opengis/core";
47
+ const { t } = useI18n();
48
+
49
+ const router = useRouter();
50
+
51
+ const form = ref({});
52
+ const isOpen = ref(false);
53
+ const values = ref({ type: "collection" });
54
+ const scheme = {
55
+ name: {
56
+ type: "text",
57
+ label: t("builder.scheme.name.label"),
58
+ required: true,
59
+ placeholder: t("builder.scheme.name.placeholder"),
60
+ validators: ["required"],
61
+ },
62
+ title: {
63
+ type: "text",
64
+ label: t("builder.scheme.title.label"),
65
+ required: true,
66
+ placeholder: t("builder.scheme.title.placeholder"),
67
+ validators: ["required"],
68
+ },
69
+ type: {
70
+ type: "combobox",
71
+ mode: "combo",
72
+ label: t("builder.scheme.type.label"),
73
+ required: true,
74
+ placeholder: t("builder.scheme.type.placeholder"),
75
+ validators: ["required"],
76
+ options: [
77
+ {
78
+ text: t("builder.scheme.type.options.collection"),
79
+ id: "collection",
80
+ },
81
+ {
82
+ text: t("builder.scheme.type.options.single"),
83
+ id: "single",
84
+ },
85
+ ],
86
+ },
87
+ customTable: {
88
+ type: "switcher",
89
+ label: t("builder.scheme.customTable.label"),
90
+ },
91
+ };
92
+
93
+ const handleCreateCollection = async () => {
94
+ let result = await form.value.validate();
95
+ if (result) {
96
+ notify({
97
+ type: "warning",
98
+ title: t("common.actions.warning"),
99
+ message: t("collections.collectionCreationFailed"),
100
+ });
101
+ return;
102
+ }
103
+ try {
104
+ const response = await fetch("/api/cms-type", {
105
+ method: 'POST',
106
+ headers: { 'Content-Type': 'application/json' },
107
+ body: JSON.stringify(values.value)
108
+ });
109
+ const data = await response.json();
110
+ router.push(`/settings/collections/edit/${data.id}`);
111
+ fetchContentTypes();
112
+ notify({
113
+ type: "success",
114
+ title: t("common.actions.success"),
115
+ message: t("collections.collectionCreated"),
116
+ });
117
+ } catch (error) {
118
+ notify({
119
+ type: "error",
120
+ title: t("common.actions.error"),
121
+ message: t("collections.collectionCreationFailed"),
122
+ });
123
+ console.error(error);
124
+ }
125
+ };
126
+ </script>
127
+
128
+ <style lang="scss" scoped></style>
@@ -0,0 +1,145 @@
1
+ export const formTypeSchema = (level = 0, t) => {
2
+
3
+ return {
4
+ name: {
5
+ type: "text",
6
+ label: t("builder.fieldLabels.name"),
7
+ required: true,
8
+ placeholder: t("builder.fieldPlaceholders.name"),
9
+ validators: ["required"],
10
+ },
11
+ label: {
12
+ type: "text",
13
+ label: t("builder.fieldLabels.label"),
14
+ required: true,
15
+ placeholder: t("builder.fieldPlaceholders.label"),
16
+ validators: ["required"],
17
+ },
18
+ placeholder: {
19
+ type: "text",
20
+ label: t("builder.fieldLabels.placeholder"),
21
+ required: true,
22
+ placeholder: t("builder.fieldPlaceholders.placeholder"),
23
+ },
24
+ help: {
25
+ type: "text",
26
+ label: t("builder.fieldLabels.help"),
27
+ placeholder: t("builder.fieldPlaceholders.help"),
28
+ },
29
+ type: {
30
+ type: "combobox",
31
+ mode: "combo",
32
+ label: t("builder.fieldLabels.type"),
33
+ required: true,
34
+ maxHeight: "300",
35
+ slots: {
36
+ option:
37
+ '<div class="flex items-center gap-2 p-2 py-1 rounded hover:bg-gray-100" :class="{ \'bg-gray-100\': selectedNavIndex === ind, \'bg-gray-100\': modelValue == ind }" ><div :class="`flex items-center gap-2 p-1 bg-${color }-100 rounded`"><component :is="`icon-${id}`" class="block" height="24" width="30" /></div><span class="text-sm text-gray-700">{{ text }}</span></div>',
38
+ },
39
+ options: [
40
+ { text: t("builder.fieldOptions.text"), id: "text", color: "blue" },
41
+ { text: t("builder.fieldOptions.number"), id: "number", color: "green" },
42
+ { text: t("builder.fieldOptions.date"), id: "date", color: "red" },
43
+ { text: t("builder.fieldOptions.datetime"), id: "datetime", color: "purple" },
44
+ { text: t("builder.fieldOptions.file"), id: "file", color: "yellow" },
45
+ { text: t("builder.fieldOptions.select"), id: "select", color: "yellow" },
46
+ { text: t("builder.fieldOptions.multiselect"), id: "multiselect", color: "blue" },
47
+ { text: t("builder.fieldOptions.mediaselect"), id: "mediaselect", color: "orange" },
48
+ { text: t("builder.fieldOptions.radio"), id: "radio", color: "blue" },
49
+ { text: t("builder.fieldOptions.boolean"), id: "boolean", color: "red" },
50
+ { text: t("builder.fieldOptions.datalist"), id: "datalist", color: "orange" },
51
+ { text: t("builder.fieldOptions.image"), id: "image", color: "blue" },
52
+ { text: t("builder.fieldOptions.slug"), id: "slug", color: "green" },
53
+ { text: t("builder.fieldOptions.richtext"), id: "richtext", color: "red" },
54
+ { text: t("builder.fieldOptions.reference"), id: "reference", color: "yellow" },
55
+ { text: t("builder.fieldOptions.relation"), id: "relation", color: "pink" },
56
+ { text: t("builder.fieldOptions.fileList"), id: "FileList", color: "orange" },
57
+ { text: t("builder.fieldOptions.tags"), id: "tags", color: "blue" },
58
+ ]?.filter((item) => level > 1 ? item.id !== "datalist" : true),
59
+ validators: ["required"],
60
+ },
61
+ subtype: {
62
+ type: "combobox",
63
+ mode: "combo",
64
+ label: t("builder.fieldLabels.subtype"),
65
+ placeholder: t("builder.fieldPlaceholders.subtype"),
66
+ options: [
67
+ { text: t("builder.fieldOptions.text"), id: "text" },
68
+ { text: t("builder.fieldOptions.number"), id: "number" },
69
+ { text: t("builder.fieldOptions.date"), id: "date" },
70
+ { text: t("builder.fieldOptions.datetime"), id: "datetime" },
71
+ ],
72
+ conditions: ["type", "==", "array"],
73
+ },
74
+ parent: {
75
+ type: "text",
76
+ label: t("builder.fieldLabels.parent"),
77
+ placeholder: t("builder.fieldPlaceholders.parent"),
78
+ conditions: ["type", "in", ["slug", "select", "multiselect", ]],
79
+ },
80
+ data: {
81
+ type: "text",
82
+ label: t("builder.fieldLabels.data"),
83
+ placeholder: t("builder.fieldPlaceholders.data"),
84
+ conditions: ["type", "in", ["select", "multiselect", ]],
85
+ },
86
+ options: {
87
+ type: "datalist",
88
+ label: t("builder.fieldLabels.options"),
89
+ conditions: ["type", "in", ["select", "multiselect", "radio"]],
90
+ colModel: [
91
+ {
92
+ key: "id",
93
+ ua: "ID",
94
+ type: "text",
95
+ validators: ["required"],
96
+ col: 6,
97
+ },
98
+ {
99
+ key: "text",
100
+ ua: "Text",
101
+ type: "text",
102
+ validators: ["required"],
103
+ col: 6,
104
+ },
105
+ ],
106
+ },
107
+ colModel: level <= 1 ? {
108
+ type: "datalist",
109
+ label: t("builder.fieldLabels.colModel"),
110
+ conditions: ["type", "==", "datalist"],
111
+ colModel: Object.entries(formTypeSchema(level + 1, t)).map(([key, value]) => ({
112
+ key,
113
+ ...value,
114
+ ua: value?.label || value?.ua,
115
+ }))
116
+ } : {
117
+ type: "switcher",
118
+ label: t("builder.fieldLabels.required"),
119
+ hidden: true,
120
+ required: true,
121
+ },
122
+ multiple: {
123
+ type: "switcher",
124
+ label: t("builder.fieldLabels.multiple"),
125
+ conditions: ["type", "==", "file"],
126
+ },
127
+ relation: {
128
+ type: "combobox",
129
+ data:'collection',
130
+ label: t("builder.fieldLabels.relation"),
131
+ conditions: ["type", "==", "relation"],
132
+ },
133
+ required: {
134
+ type: "switcher",
135
+ label: t("builder.fieldLabels.required"),
136
+ required: true,
137
+ },
138
+ localization: {
139
+ type: "switcher",
140
+ label: t("builder.fieldLabels.localization"),
141
+ conditions: ["type", "in", ["richtext","text","reference","multiselect","datalist"]],
142
+ required: true,
143
+ },
144
+ }
145
+ }
@@ -0,0 +1,9 @@
1
+ import VsBuilderMonaco from "./vs-builder-monaco.vue";
2
+ import VsBuilderEdit from "./vs-builder-edit.vue";
3
+ import VsBuilderPreview from "./vs-builder-preview.vue";
4
+
5
+ export default {
6
+ monaco: VsBuilderMonaco,
7
+ edit: VsBuilderEdit,
8
+ preview: VsBuilderPreview,
9
+ };
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <div>
3
+ <VsForm
4
+ v-model="data"
5
+ :schema="scheme"
6
+ v-model:form="form"
7
+ />
8
+ <VSBuilderDatatable v-model="data" />
9
+ </div>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { onBeforeUnmount, computed, ref } from "vue";
14
+ import VSBuilderDatatable from "../vs-builder-datatable.vue";
15
+ import { useI18n } from "vue-i18n";
16
+ import { notify } from '@opengis/core';
17
+ import VsForm from '@opengis/form'
18
+
19
+ const { t } = useI18n();
20
+
21
+ const data = defineModel("data");
22
+
23
+ const form = defineModel("form");
24
+
25
+ const formObject = ref({});
26
+
27
+ const scheme = computed(() => ({
28
+ name: {
29
+ type: "text",
30
+ label: t("builder.scheme.name.label"),
31
+ required: true,
32
+ placeholder: t("builder.scheme.name.placeholder"),
33
+ validators: ["required"],
34
+ col: 4,
35
+ },
36
+ title: {
37
+ type: "text",
38
+ label: t("builder.scheme.title.label"),
39
+ required: true,
40
+ placeholder: t("builder.scheme.title.placeholder"),
41
+ validators: ["required"],
42
+ col: 4,
43
+ },
44
+ preview_path: {
45
+ type: "text",
46
+ label: t("builder.scheme.preview_path.label"),
47
+ placeholder: t("builder.scheme.preview_path.placeholder"),
48
+ col: 4,
49
+ info: t("builder.scheme.preview_path.info"),
50
+ },
51
+ // slug: {
52
+ // type: "slug",
53
+ // label: "Title",
54
+ // parent: "title",
55
+ // required: true,
56
+ // placeholder: "Title",
57
+ // validators: ["required"],
58
+ // col: 4,
59
+ // },
60
+ type: {
61
+ type: "select",
62
+ label: t("builder.scheme.type.label"),
63
+ required: true,
64
+ placeholder: t("builder.scheme.type.placeholder"),
65
+ validators: ["required"],
66
+ col: 4,
67
+
68
+ options: [
69
+ {
70
+ text: t("builder.scheme.type.options.collection"),
71
+ id: "collection",
72
+ },
73
+ {
74
+ text: t("builder.scheme.type.options.single"),
75
+ id: "single",
76
+ },
77
+ ],
78
+ },
79
+ status: {
80
+ type: "select",
81
+ label: t("builder.scheme.status.label"),
82
+ required: true,
83
+ placeholder: t("builder.scheme.status.placeholder"),
84
+ col: 4,
85
+ options: [
86
+ {
87
+ text: t("builder.scheme.status.options.published"),
88
+ id: "published",
89
+ },
90
+ {
91
+ text: t("builder.scheme.status.options.draft"),
92
+ id: "draft",
93
+ },
94
+ {
95
+ text: t("builder.scheme.status.options.archived"),
96
+ id: "archived",
97
+ },
98
+ ],
99
+ },
100
+ include_search:{
101
+ type: "switcher",
102
+ label: t("builder.scheme.include_search.label"),
103
+ placeholder: t("builder.scheme.include_search.placeholder"),
104
+ col: 4,
105
+ },
106
+
107
+ description: {
108
+ type: "textarea",
109
+ label: t("builder.scheme.description.label"),
110
+ required: true,
111
+ placeholder: t("builder.scheme.description.placeholder"),
112
+ },
113
+ }));
114
+
115
+ const handleUpdate = async (value) => {
116
+ let result = await formObject.value.validate();
117
+ if (result) {
118
+ notify({
119
+ type: "warning",
120
+ title: t("common.actions.warning"),
121
+ message: t("builder.editFieldFailed"),
122
+ });
123
+ return;
124
+ }
125
+ data.value = { ...value, columns: data.value.columns };
126
+ };
127
+
128
+ onBeforeUnmount(() => {
129
+ form.value = null;
130
+ });
131
+ </script>
132
+
133
+ <style lang="scss" scoped></style>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div v-if="id" :key="id">
3
+ <MonacoEditor
4
+ v-model="code"
5
+ language="yaml"
6
+ theme="vs-light"
7
+ height="calc(100vh - 200px)"
8
+ width="100%"
9
+ :options="{
10
+ minimap: { enabled: false },
11
+ }"
12
+ />
13
+ </div>
14
+ </template>
15
+ <script setup>
16
+ import { ref, onMounted } from "vue";
17
+ import MonacoEditor from "../../form-components/MonacoEditor.vue";
18
+
19
+ const code = ref("");
20
+ const yaml = defineModel("yaml", { type: String, default: "" });
21
+
22
+ const id = ref(null);
23
+
24
+ onMounted(() => {
25
+ id.value = Math.random().toString(36).substring(2, 15);
26
+ });
27
+ </script>
28
+
29
+ <style lang="scss" scoped></style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <div ref="form">
3
+ <VForm v-if="scheme?.length > 0" v-model="data" :schema="scheme" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ import { ref, computed } from "vue";
9
+ import { getField } from "../../../utils/getField";
10
+ import { VForm, inputs } from '@opengis/form'
11
+ import VsDatatableForm from '@/components/form-components/vs-form-custom-datatable.vue'
12
+ import VsReference from '@/components/form-components/vs-form-reference-list.vue'
13
+ import VsTiptap from '@/components/form-components/vs-form-tiptap.vue'
14
+ import VsMediaSelect from '@/components/form-components/vs-form-media-select.vue'
15
+ import VsRichtextMd from '@/components/form-components/vs-richtext-md.vue'
16
+ import VsInteger from '@/components/form-components/vs-form-integer.vue'
17
+ import VsRelationLink from '@/components/form-components/vs-form-reletion-link.vue'
18
+
19
+ inputs['vs-input-custom-datatable'] = VsDatatableForm;
20
+ inputs['vs-input-reference'] = VsReference;
21
+ inputs['vs-input-texteditor'] = VsTiptap;
22
+ inputs['vs-input-mediaselect'] = VsMediaSelect;
23
+ inputs['vs-input-file'] = VsMediaSelect;
24
+ inputs['vs-input-image'] = VsMediaSelect;
25
+ inputs['vs-input-richtext-md'] = VsRichtextMd;
26
+ inputs['vs-input-integer'] = VsInteger;
27
+ inputs['vs-input-relation-link'] = VsRelationLink;
28
+
29
+ const data = ref({});
30
+
31
+ const columns = defineModel("data");
32
+ const form = defineModel("form");
33
+
34
+ const scheme = computed(() => {
35
+ return columns.value?.columns?.map(getField) || [];
36
+ });
37
+ </script>
38
+
39
+ <style lang="scss" scoped></style>