@opengis/cms 0.0.22 → 0.0.24

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 (211) hide show
  1. package/package.json +2 -10
  2. package/src/index.js +23 -0
  3. package/module/cms/card/cms.content.table/index.yml +0 -17
  4. package/module/cms/card/cms.content.table/main_info.hbs +0 -26
  5. package/module/cms/card/cms.menu.table/content_info.hbs +0 -16
  6. package/module/cms/card/cms.menu.table/index.yml +0 -18
  7. package/module/cms/card/cms.menu.table/main_info.hbs +0 -22
  8. package/module/cms/card/cms.settings.table/index.yml +0 -13
  9. package/module/cms/card/cms.settings.table/main_info.hbs +0 -20
  10. package/module/cms/cls/content.status.json +0 -18
  11. package/module/cms/cls/user_type.json +0 -10
  12. package/module/cms/form/admin.users.form.json +0 -78
  13. package/module/cms/form/cms.content.form.json +0 -79
  14. package/module/cms/form/cms.menu.form.json +0 -69
  15. package/module/cms/form/cms.settings.form.json +0 -32
  16. package/module/cms/menu.json +0 -24
  17. package/module/cms/router.js +0 -169
  18. package/module/cms/select/cms.page_type.sql +0 -2
  19. package/module/cms/select/collection.sql +0 -1
  20. package/module/cms/select/locale.sql +0 -17
  21. package/module/cms/select/news_tag_id.sql +0 -12
  22. package/module/cms/select/tag_id.sql +0 -1
  23. package/module/cms/table/admin.users.table.json +0 -54
  24. package/module/cms/table/cms.content.table.json +0 -106
  25. package/module/cms/table/cms.menu.table.json +0 -73
  26. package/module/cms/table/cms.settings.table.json +0 -57
  27. package/module/cms/table/collection.default.table.json +0 -102
  28. package/module/cms/table/single.default.table.json +0 -115
  29. package/src/App.css +0 -52
  30. package/src/App.vue +0 -62
  31. package/src/assets/image.png +0 -0
  32. package/src/assets/main.css +0 -3
  33. package/src/assets/tailwind-3.4.17.js +0 -113
  34. package/src/components/LanguageSwitcher.vue +0 -73
  35. package/src/components/SettingsCard.vue +0 -40
  36. package/src/components/builder/CreateForm.vue +0 -128
  37. package/src/components/builder/formTypeSchema.js +0 -145
  38. package/src/components/builder/tabs/index.ts +0 -9
  39. package/src/components/builder/tabs/vs-builder-edit.vue +0 -133
  40. package/src/components/builder/tabs/vs-builder-monaco.vue +0 -29
  41. package/src/components/builder/tabs/vs-builder-preview.vue +0 -39
  42. package/src/components/builder/vs-builder-datatable-controls.vue +0 -138
  43. package/src/components/builder/vs-builder-datatable-form.vue +0 -80
  44. package/src/components/builder/vs-builder-datatable.vue +0 -191
  45. package/src/components/builder/vs-builder-list-item.vue +0 -110
  46. package/src/components/collections/CollectionsBreadcrumb.vue +0 -52
  47. package/src/components/collections/CollectionsGrid.vue +0 -176
  48. package/src/components/collections/ContentBlock.vue +0 -75
  49. package/src/components/collections/formWrapper.vue +0 -156
  50. package/src/components/dashboard/ContentItem.vue +0 -82
  51. package/src/components/dashboard/DashboardHeader.vue +0 -33
  52. package/src/components/dashboard/QuickActions.vue +0 -84
  53. package/src/components/dashboard/RecentContent.vue +0 -54
  54. package/src/components/dashboard/StatCard.vue +0 -63
  55. package/src/components/dashboard/StatsGrid.vue +0 -28
  56. package/src/components/form-components/MonacoEditor.vue +0 -104
  57. package/src/components/form-components/VsFormMeta.vue +0 -40
  58. package/src/components/form-components/VsFormTags.vue +0 -150
  59. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-add.vue +0 -84
  60. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-controls.vue +0 -106
  61. package/src/components/form-components/index.js +0 -23
  62. package/src/components/form-components/reference/vs-form-reference-add.vue +0 -92
  63. package/src/components/form-components/reference/vs-form-reference-controls.vue +0 -101
  64. package/src/components/form-components/reference-list/referenceOptionList.js +0 -78
  65. package/src/components/form-components/reference-list/vs-form-reference-add.vue +0 -145
  66. package/src/components/form-components/reference-list/vs-form-reference-choce.vue +0 -39
  67. package/src/components/form-components/reference-list/vs-form-reference-controls.vue +0 -110
  68. package/src/components/form-components/reference-skeleton/about-skeleton.vue +0 -37
  69. package/src/components/form-components/reference-skeleton/banner-skeleton.vue +0 -29
  70. package/src/components/form-components/reference-skeleton/body-skeleton.vue +0 -56
  71. package/src/components/form-components/reference-skeleton/cards-skeleton.vue +0 -47
  72. package/src/components/form-components/reference-skeleton/documents-skeleton.vue +0 -64
  73. package/src/components/form-components/reference-skeleton/faq-skeleton.vue +0 -64
  74. package/src/components/form-components/reference-skeleton/form-skeleton.vue +0 -41
  75. package/src/components/form-components/reference-skeleton/index.js +0 -36
  76. package/src/components/form-components/reference-skeleton/infoLine-skeleton.vue +0 -37
  77. package/src/components/form-components/reference-skeleton/news-skeleton.vue +0 -54
  78. package/src/components/form-components/reference-skeleton/slider-skeleton.vue +0 -41
  79. package/src/components/form-components/reference-skeleton/tabs-skeleton.vue +0 -40
  80. package/src/components/form-components/reference-skeleton/team-skeleton.vue +0 -103
  81. package/src/components/form-components/reference-skeleton/usefulLinks-skeleton.vue +0 -52
  82. package/src/components/form-components/reference-skeleton/video-skeleton.vue +0 -36
  83. package/src/components/form-components/testReferenceTypes.js +0 -773
  84. package/src/components/form-components/vs-form-color-picker.vue +0 -29
  85. package/src/components/form-components/vs-form-custom-datatable.vue +0 -214
  86. package/src/components/form-components/vs-form-integer.vue +0 -86
  87. package/src/components/form-components/vs-form-key-value.vue +0 -201
  88. package/src/components/form-components/vs-form-marcdown-md.vue +0 -3
  89. package/src/components/form-components/vs-form-media-select.vue +0 -780
  90. package/src/components/form-components/vs-form-reference-list.vue +0 -97
  91. package/src/components/form-components/vs-form-reference.vue +0 -59
  92. package/src/components/form-components/vs-form-relation.vue +0 -30
  93. package/src/components/form-components/vs-form-reletion-link.vue +0 -34
  94. package/src/components/form-components/vs-form-select-collection.vue +0 -0
  95. package/src/components/form-components/vs-form-slug.vue +0 -72
  96. package/src/components/form-components/vs-form-tiptap.vue +0 -7
  97. package/src/components/form-components/vs-richtext-md.vue +0 -3
  98. package/src/components/icons/BellIcon.vue +0 -17
  99. package/src/components/icons/GlobeIcon.vue +0 -18
  100. package/src/components/icons/KeyIcon.vue +0 -20
  101. package/src/components/icons/PaletteIcon.vue +0 -22
  102. package/src/components/icons/SettingsIcon.vue +0 -19
  103. package/src/components/icons/ShieldIcon.vue +0 -18
  104. package/src/components/icons/UsersIcon.vue +0 -19
  105. package/src/components/icons/icon-chevron-right.vue +0 -16
  106. package/src/components/icons/icon-drag.vue +0 -20
  107. package/src/components/icons/icon-file-text.vue +0 -21
  108. package/src/components/icons/icon-folder.vue +0 -18
  109. package/src/components/icons/icon-grid.vue +0 -17
  110. package/src/components/icons/icon-group.vue +0 -19
  111. package/src/components/icons/icon-home.vue +0 -16
  112. package/src/components/icons/icon-image.vue +0 -18
  113. package/src/components/icons/icon-list.vue +0 -20
  114. package/src/components/icons/icon-more.vue +0 -17
  115. package/src/components/icons/icon-plus.vue +0 -17
  116. package/src/components/icons-types/icon-array.vue +0 -22
  117. package/src/components/icons-types/icon-boolean.vue +0 -18
  118. package/src/components/icons-types/icon-datalist.vue +0 -22
  119. package/src/components/icons-types/icon-date.vue +0 -20
  120. package/src/components/icons-types/icon-datetime.vue +0 -20
  121. package/src/components/icons-types/icon-file.vue +0 -21
  122. package/src/components/icons-types/icon-gallery.vue +0 -18
  123. package/src/components/icons-types/icon-image.vue +0 -19
  124. package/src/components/icons-types/icon-integer.vue +0 -20
  125. package/src/components/icons-types/icon-merkdown.vue +0 -18
  126. package/src/components/icons-types/icon-multiselect.vue +0 -22
  127. package/src/components/icons-types/icon-number.vue +0 -20
  128. package/src/components/icons-types/icon-radio.vue +0 -22
  129. package/src/components/icons-types/icon-reference-list.vue +0 -22
  130. package/src/components/icons-types/icon-reference.vue +0 -20
  131. package/src/components/icons-types/icon-relation.vue +0 -22
  132. package/src/components/icons-types/icon-richtext.vue +0 -18
  133. package/src/components/icons-types/icon-select.vue +0 -22
  134. package/src/components/icons-types/icon-slug.vue +0 -19
  135. package/src/components/icons-types/icon-text.vue +0 -19
  136. package/src/components/icons-types/index.js +0 -43
  137. package/src/components/layout/Layout.vue +0 -67
  138. package/src/components/layout/Sidebar.vue +0 -128
  139. package/src/components/media/FileUploadProgress.vue +0 -29
  140. package/src/components/media/MediaBreadcrumb.vue +0 -42
  141. package/src/components/media/MediaCreateFolder.vue +0 -59
  142. package/src/components/media/MediaFileInfo.vue +0 -148
  143. package/src/components/media/MediaGrid.vue +0 -148
  144. package/src/components/media/MediaList.vue +0 -148
  145. package/src/components/media/MediaViewControls.vue +0 -38
  146. package/src/components/media/TypeTag.vue +0 -23
  147. package/src/components/menu/AddNewItemInTree.vue +0 -75
  148. package/src/components/menu/MenuBody.vue +0 -149
  149. package/src/components/menu/MenuItem.vue +0 -73
  150. package/src/components/menu/MenuList.vue +0 -101
  151. package/src/components/referencec/index.ts +0 -7
  152. package/src/components/referencec/vs-reference-faq.vue +0 -61
  153. package/src/components/referencec/vs-reference-user-card.vue +0 -40
  154. package/src/components/settings/NotificationSettings.vue +0 -32
  155. package/src/components/settings/SettingsTable.vue +0 -50
  156. package/src/components/settings/SettingsTitle.vue +0 -33
  157. package/src/components/settings/SettingsToggleItem.vue +0 -25
  158. package/src/components/sidebar/DropdownMenu.vue +0 -34
  159. package/src/components/sidebar/SettingsSidebar.vue +0 -121
  160. package/src/components/sidebar/SidebarFooter.vue +0 -52
  161. package/src/components/sidebar/SidebarHeader.vue +0 -57
  162. package/src/components/sidebar/SidebarMenu.vue +0 -78
  163. package/src/components/ui/EmptyData.vue +0 -76
  164. package/src/components/ui/UniversalTable.vue +0 -310
  165. package/src/components/ui/UniversalTableFilters.vue +0 -0
  166. package/src/components/ui/UniversalTablePagination.vue +0 -118
  167. package/src/components/ui/VsPreview.vue +0 -75
  168. package/src/composables/useCollectionView.ts +0 -21
  169. package/src/composables/useDebounce.ts +0 -26
  170. package/src/composables/useMonaco.ts +0 -28
  171. package/src/composables/useTheme.ts +0 -40
  172. package/src/content/test-slug/metadata.json +0 -1
  173. package/src/i18n.ts +0 -75
  174. package/src/index.css +0 -3
  175. package/src/index.ts +0 -122
  176. package/src/locales/en.json +0 -778
  177. package/src/locales/uk.json +0 -797
  178. package/src/main.ts +0 -41
  179. package/src/pages/Dashboard.vue +0 -168
  180. package/src/pages/EmailPage.vue +0 -183
  181. package/src/pages/FeedbackPage.vue +0 -232
  182. package/src/pages/MediaPage.vue +0 -372
  183. package/src/pages/TagsPage.vue +0 -207
  184. package/src/pages/builder/BuilderPage.vue +0 -195
  185. package/src/pages/builder/EditCollectionPage.vue +0 -163
  186. package/src/pages/collections/ArticlesPage.vue +0 -385
  187. package/src/pages/collections/CollectionsPage.vue +0 -146
  188. package/src/pages/collections/SingletonsPage.vue +0 -119
  189. package/src/pages/collections/contentForm.vue +0 -484
  190. package/src/pages/collections/schema/seo.ts +0 -27
  191. package/src/pages/menu/MenuAddPage.vue +0 -123
  192. package/src/pages/menu/MenuItemPage.vue +0 -183
  193. package/src/pages/menu/MenuPage.vue +0 -133
  194. package/src/pages/settings/ApiKeys.vue +0 -75
  195. package/src/pages/settings/Appearance.vue +0 -80
  196. package/src/pages/settings/Logs.vue +0 -260
  197. package/src/pages/settings/PermissionsPage.vue +0 -237
  198. package/src/pages/settings/Settings.vue +0 -186
  199. package/src/pages/settings/Users.vue +0 -109
  200. package/src/pages/settings/general.vue +0 -154
  201. package/src/pages/settings/generalScheme.js +0 -132
  202. package/src/pages/users/AddUser.vue +0 -106
  203. package/src/pages/users/UsersPage.vue +0 -98
  204. package/src/props/builder.ts +0 -67
  205. package/src/props/content.ts +0 -56
  206. package/src/props/media.ts +0 -63
  207. package/src/router/index.ts +0 -181
  208. package/src/types/fastify-auth.d.ts +0 -4
  209. package/src/utils/getField.js +0 -270
  210. package/src/utils/translit.js +0 -19
  211. package/src/vite-env.d.ts +0 -1
@@ -1,29 +0,0 @@
1
- <template>
2
- <input
3
- type="color"
4
- v-model="modelValueLocal"
5
- class="w-8 h-8 p-0 border border-gray-300 rounded cursor-pointer bg-transparent"
6
- @input="onInput"
7
- />
8
- </template>
9
-
10
- <script setup lang="ts">
11
- import { defineProps, defineEmits, computed } from 'vue';
12
-
13
- const props = defineProps<{
14
- modelValue: string
15
- }>();
16
- const emit = defineEmits<{
17
- (e: 'update:modelValue', value: string): void
18
- }>();
19
-
20
- const modelValueLocal = computed({
21
- get: () => props.modelValue,
22
- set: (val: string) => emit('update:modelValue', val)
23
- });
24
-
25
- function onInput(e: Event) {
26
- const value = (e.target as HTMLInputElement).value;
27
- emit('update:modelValue', value);
28
- }
29
- </script>
@@ -1,214 +0,0 @@
1
- <template>
2
- <div class="p-0 shadow w-full">
3
- <div class="overflow-x-auto">
4
- <div class="relative w-full overflow-auto">
5
- <table class="w-full caption-bottom text-sm">
6
- <thead class="[&amp;_tr]:border-b">
7
- <tr
8
- class="border-b data-[state=selected]:bg-muted bg-slate-50/50 dark:bg-slate-700/50 hover:bg-slate-50/80 dark:hover:bg-slate-700/80 transition-colors"
9
- >
10
- <th
11
- class="h-10 px-2 align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0 [&amp;&gt;[role=checkbox]]:translate-y-[2px] w-12 text-center"
12
- ></th>
13
- <th
14
- v-for="field in colModel"
15
- :key="field.name"
16
- class="h-10 px-2 text-left align-middle [&amp;:has([role=checkbox])]:pr-0 [&amp;&gt;[role=checkbox]]:translate-y-[2px] font-semibold text-slate-700 dark:text-slate-300 min-w-[150px]"
17
- >
18
- {{ field.label || field.title || field.name }}
19
- </th>
20
-
21
- <th
22
- class="h-10 px-2 align-middle [&amp;:has([role=checkbox])]:pr-0 [&amp;&gt;[role=checkbox]]:translate-y-[2px] font-semibold text-slate-700 dark:text-slate-300 text-end"
23
- >
24
- {{ $t('table.actions') }}
25
- </th>
26
- </tr>
27
- </thead>
28
- <tbody class="[&amp;_tr:last-child]:border-0">
29
- <tr
30
- v-for="(item, index) in data"
31
- :key="item?.id"
32
- class="border-b data-[state=selected]:bg-muted transition-all duration-200 hover:bg-slate-50/60 dark:hover:bg-slate-700/60 cursor-move"
33
- :class="{ 'opacity-50': draggedItem === item }"
34
- draggable="true"
35
- @dragstart="handleDragStart($event, item, index)"
36
- @dragover="handleDragOver($event, index)"
37
- @drop="handleDrop($event, index)"
38
- @dragenter="handleDragEnter($event, index)"
39
- @dragleave="handleDragLeave($event)"
40
- >
41
- <td
42
- class="p-2 align-middle [&amp;:has([role=checkbox])]:pr-0 [&amp;&gt;[role=checkbox]]:translate-y-[2px] text-center"
43
- >
44
- <div class="flex items-center justify-center text-slate-400">
45
- <GripVertical />
46
- </div>
47
- </td>
48
-
49
- <td
50
- v-for="field in colModel"
51
- :key="field.name"
52
- class="p-2 align-middle [&amp;:has([role=checkbox])]:pr-0 [&amp;&gt;[role=checkbox]]:translate-y-[2px] text-slate-600 dark:text-slate-400 text-sm"
53
- >
54
- <span v-if="field.type === 'Texteditor'" v-html="item[field.key] || '-'"></span>
55
- <div v-else-if="field.type === 'File'" class="flex items-center gap-2">
56
- <div v-if="Array.isArray(item[field.key]) && item[field.key].length > 0" class="flex items-center gap-1">
57
- <div
58
- v-for="(file, fileIndex) in getDisplayFiles(item[field.key])"
59
- :key="fileIndex"
60
- class="relative w-8 h-8 rounded overflow-hidden bg-gray-100 dark:bg-gray-700 flex-shrink-0"
61
- >
62
- <img
63
- :src="file"
64
- :alt="`Image ${fileIndex + 1}`"
65
- class="w-full h-full object-cover"
66
- @error="handleImageError($event)"
67
- />
68
- </div>
69
- <span v-if="getRemainingFilesCount(item[field.key]) > 0" class="text-xs text-gray-500 dark:text-gray-400 ml-1">
70
- +{{ getRemainingFilesCount(item[field.key]) }}
71
- </span>
72
- </div>
73
- <div v-else class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-700 flex items-center justify-center">
74
- <svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
75
- <path fill-rule="evenodd" d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V5a2 2 0 00-2-2H4zm12 12H4l4-8 3 6 2-4 3 6z" clip-rule="evenodd" />
76
- </svg>
77
- </div>
78
- </div>
79
- <span v-else>{{ item[field.key] || "-" }}</span>
80
- </td>
81
-
82
- <td
83
- class="p-2 align-middle [&amp;:has([role=checkbox])]:pr-0 [&amp;&gt;[role=checkbox]]:translate-y-[2px]"
84
- >
85
- <VsFormCustomDatatableControls
86
- :item="item"
87
- :colModel="colModel"
88
- v-model="data"
89
- />
90
- </td>
91
- </tr>
92
-
93
- <!-- Drop zone indicator -->
94
- <tr
95
- v-if="showDropZone"
96
- class="h-2 bg-blue-200 dark:bg-blue-800 transition-all duration-200"
97
- ></tr>
98
- </tbody>
99
- </table>
100
- </div>
101
- </div>
102
- <VsFormCustomDatatableAdd :colModel="colModel" v-model="data" />
103
- </div>
104
- </template>
105
-
106
- <script setup>
107
- import { GripVertical } from "lucide-vue-next";
108
- import VsFormCustomDatatableControls from "./custom-datatable/vs-form-custom-datatable-controls.vue";
109
- import VsFormCustomDatatableAdd from "./custom-datatable/vs-form-custom-datatable-add.vue";
110
- import { onMounted, ref } from "vue";
111
-
112
- const props = defineProps({
113
- colModel: {
114
- type: Array,
115
- required: true,
116
- },
117
- });
118
-
119
- const data = defineModel({
120
- type: Array,
121
- required: true,
122
- });
123
-
124
- // Drag and drop state
125
- const draggedItem = ref(null);
126
- const draggedIndex = ref(-1);
127
- const showDropZone = ref(false);
128
-
129
- // Drag and drop handlers
130
- const handleDragStart = (event, item, index) => {
131
- draggedItem.value = item;
132
- draggedIndex.value = index;
133
- event.dataTransfer.effectAllowed = "move";
134
- event.dataTransfer.setData("text/html", ""); // Required for Firefox
135
- };
136
-
137
- const handleDragOver = (event, index) => {
138
- event.preventDefault();
139
- event.dataTransfer.dropEffect = "move";
140
- };
141
-
142
- const handleDragEnter = (event, index) => {
143
- if (draggedIndex.value !== index) {
144
- showDropZone.value = true;
145
- }
146
- };
147
-
148
- const handleDragLeave = (event) => {
149
- // Only hide drop zone if we're leaving the table entirely
150
- if (!event.currentTarget.contains(event.relatedTarget)) {
151
- showDropZone.value = false;
152
- }
153
- };
154
-
155
- const handleDrop = (event, dropIndex) => {
156
- event.preventDefault();
157
- showDropZone.value = false;
158
-
159
- if (draggedIndex.value === -1 || draggedIndex.value === dropIndex) {
160
- return;
161
- }
162
-
163
- // Reorder the array
164
- const newData = [...data.value];
165
- const [removed] = newData.splice(draggedIndex.value, 1);
166
- newData.splice(dropIndex, 0, removed);
167
-
168
- // Update the model
169
- data.value = newData;
170
-
171
- // Reset drag state
172
- draggedItem.value = null;
173
- draggedIndex.value = -1;
174
- };
175
-
176
- // Constants for file display
177
- const MAX_DISPLAY_FILES = 3;
178
-
179
- // Get files to display (limited to MAX_DISPLAY_FILES)
180
- const getDisplayFiles = (files) => {
181
- if (!Array.isArray(files)) return [];
182
- return files.slice(0, MAX_DISPLAY_FILES);
183
- };
184
-
185
- // Get count of remaining files not displayed
186
- const getRemainingFilesCount = (files) => {
187
- if (!Array.isArray(files)) return 0;
188
- return Math.max(0, files.length - MAX_DISPLAY_FILES);
189
- };
190
-
191
- // Handle image loading errors
192
- const handleImageError = (event) => {
193
- const img = event.target;
194
- img.style.display = 'none';
195
- const placeholder = document.createElement('div');
196
- placeholder.className = 'w-full h-full flex items-center justify-center bg-gray-200 dark:bg-gray-600';
197
- placeholder.innerHTML = `
198
- <svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
199
- <path fill-rule="evenodd" d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V5a2 2 0 00-2-2H4zm12 12H4l4-8 3 6 2-4 3 6z" clip-rule="evenodd" />
200
- </svg>
201
- `;
202
- img.parentNode.appendChild(placeholder);
203
- };
204
-
205
- onMounted(() => {
206
- data.value
207
- ?.filter((el) => typeof el === "object")
208
- ?.forEach((item) =>
209
- item.id
210
- ? item.id
211
- : (item.id = Math.random().toString(36).substring(2, 15))
212
- );
213
- });
214
- </script>
@@ -1,86 +0,0 @@
1
- <template>
2
- <div class="p-0">
3
- <slot name="label" v-bind="{ id }"></slot>
4
- <input
5
- v-model="inputValue"
6
- type="number"
7
- @keydown="validateInput"
8
- @blur="handleBlur"
9
- :step="step"
10
- :min="min"
11
- :max="max"
12
- :id="id"
13
- aria-describedby="helper-text-explanation"
14
- class="vs-number__input py-2 px-3 block w-full h-[38px] border border-solid border-stone-200 rounded-lg text-sm text-stone-800 placeholder:text-stone-500 focus:z-10 focus:border-1 focus:outline-none focus:border-blue-600 dark:bg-neutral-800 dark:border-neutral-700 dark:text-neutral-200 dark:placeholder:text-neutral-500 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600"
15
- :placeholder="placeholder"
16
- :disabled="disabled"
17
- :class="{ 'cursor-not-allowed': disabled }"
18
- />
19
- </div>
20
- </template>
21
- <script>
22
- export default {
23
- props: {
24
- min: { type: Number },
25
- step: { type: Number, default: () => 1 },
26
- max: { type: Number, default: () => Infinity },
27
- modelValue: { type: Number, default: () => null },
28
- label: { type: String, default: () => "" },
29
- placeholder: { type: String, default: () => "0" },
30
- disabled: { type: Boolean, default: () => false },
31
- },
32
- data() {
33
- return {
34
- id: `input-number-${Math.floor(Math.random() * 1000)}`,
35
- inputValue: this.modelValue,
36
- };
37
- },
38
- watch: {
39
- modelValue(newVal) {
40
- this.inputValue = newVal;
41
- },
42
- inputValue(newVal) {
43
- this.$emit("update:modelValue", newVal);
44
- },
45
- },
46
- methods: {
47
- validateInput(event) {
48
- if (
49
- event.key === "+" ||
50
- event.key === "," ||
51
- event.key === "." ||
52
- (event.key === "-" &&
53
- this.inputValue &&
54
- this.inputValue.toString().length > 0)
55
- ) {
56
- event.preventDefault();
57
- }
58
- },
59
- handleBlur() {
60
- let value = parseFloat(this.inputValue);
61
-
62
- this.$emit("blur");
63
-
64
- if (isNaN(value)) {
65
- value = this.min;
66
- } else if (value > this.max) {
67
- value = this.max;
68
- } else if (value < this.min) {
69
- value = this.min;
70
- }
71
- this.inputValue = value;
72
- this.$emit("update:modelValue", this.inputValue);
73
- },
74
- },
75
- };
76
- </script>
77
-
78
- <style>
79
- .col-error .vs-number__input {
80
- border: 1px solid red;
81
- }
82
-
83
- .vs-number__input::placeholder {
84
- opacity: 0.5;
85
- }
86
- </style>
@@ -1,201 +0,0 @@
1
- <template>
2
- <div class="w-full">
3
- <div ref="sortableContainer" class="flex flex-col gap-1">
4
- <div
5
- v-for="item in value"
6
- :key="item?.id"
7
- class="flex items-center gap-2 w-full"
8
- >
9
- <button class="drag-handle cursor-move">
10
- <svg
11
- fill="#000000"
12
- width="20"
13
- height="20"
14
- viewBox="0 0 36 36"
15
- version="1.1"
16
- preserveAspectRatio="xMidYMid meet"
17
- xmlns="http://www.w3.org/2000/svg"
18
- xmlns:xlink="http://www.w3.org/1999/xlink"
19
- >
20
- <title>drag-handle-line</title>
21
- <circle
22
- cx="15"
23
- cy="12"
24
- r="1.5"
25
- class="clr-i-outline clr-i-outline-path-1"
26
- ></circle>
27
- <circle
28
- cx="15"
29
- cy="24"
30
- r="1.5"
31
- class="clr-i-outline clr-i-outline-path-2"
32
- ></circle>
33
- <circle
34
- cx="21"
35
- cy="12"
36
- r="1.5"
37
- class="clr-i-outline clr-i-outline-path-3"
38
- ></circle>
39
- <circle
40
- cx="21"
41
- cy="24"
42
- r="1.5"
43
- class="clr-i-outline clr-i-outline-path-4"
44
- ></circle>
45
- <circle
46
- cx="21"
47
- cy="18"
48
- r="1.5"
49
- class="clr-i-outline clr-i-outline-path-5"
50
- ></circle>
51
- <circle
52
- cx="15"
53
- cy="18"
54
- r="1.5"
55
- class="clr-i-outline clr-i-outline-path-6"
56
- ></circle>
57
- <rect x="0" y="0" width="36" height="36" fill-opacity="0" />
58
- </svg>
59
- </button>
60
-
61
- <!-- Key field -->
62
- <div class="w-1/3">
63
- <VsText v-model="item.key" type="text" :placeholder="t('form.key')" />
64
- </div>
65
-
66
- <!-- Value field -->
67
- <div class="w-2/3">
68
- <VsText v-model="item.value" type="text" :placeholder="t('form.value')" />
69
- </div>
70
-
71
- <button
72
- @click="deleteItem(item?.id)"
73
- class="shrink-0 w-[30px] text-gray-600 h-[30px] rounded-full flex items-center justify-center bg-gray-100 duration-300 hover:bg-gray-200"
74
- >
75
- <X height="16" width="16" />
76
- </button>
77
- </div>
78
- </div>
79
-
80
- <span v-if="!value.length" class="text-[14px] text-gray-700"
81
- >{{ t('form.noDataToDisplay') }}</span
82
- >
83
- <div class="mt-2 w-full flex items-center">
84
- <button
85
- type="button"
86
- @click="addItem"
87
- :disabled="disabled"
88
- class="py-1.5 px-2 flex items-center gap-x-1 text-xs font-medium rounded-full border border-dashed border-gray-200 bg-white text-gray-800 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed focus:outline-hidden focus:bg-gray-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-700 dark:focus:bg-neutral-700"
89
- >
90
- <Plus height="14" width="14" /> {{ t('form.add') }}
91
- </button>
92
- </div>
93
- </div>
94
- </template>
95
-
96
- <script setup>
97
- import { computed, ref, watch, onMounted, inject } from "vue";
98
- import { Plus, X } from "lucide-vue-next";
99
- import Sortable from "sortablejs";
100
- import { useI18n } from 'vue-i18n';
101
- const { t } = useI18n();
102
-
103
- const getRandomId = (prefix) => {
104
- return `${prefix}-${Math.random().toString(36).substring(2, 15)}`;
105
- };
106
-
107
- const props = defineProps({
108
- colModel: { type: Object, default: () => ({ type: "Text" }) },
109
- ignore: { type: Array, default: () => [] },
110
- addButtonText: { type: String, default: () => "Додати" },
111
- });
112
-
113
- const metaParentValue = inject("metaParentValue");
114
-
115
- // Convert object to array of key-value pairs, исключая игнорируемые ключи
116
- const value = ref(
117
- Object.entries(metaParentValue.value || {})
118
- .filter(([key]) => !props.ignore.includes(key))
119
- .map(([key, val]) => ({
120
- id: getRandomId("key-value-"),
121
- key: key,
122
- value: val,
123
- }))
124
- );
125
-
126
- const sortableContainer = ref(null);
127
-
128
- onMounted(() => {
129
- if (sortableContainer.value) {
130
- new Sortable(sortableContainer.value, {
131
- handle: ".drag-handle",
132
- animation: 150,
133
- ghostClass: "sortable-ghost",
134
- onEnd: ({ oldIndex, newIndex }) => {
135
- if (oldIndex !== newIndex) {
136
- const item = value.value.splice(oldIndex, 1)[0];
137
- value.value.splice(newIndex, 0, item);
138
- }
139
- },
140
- });
141
- }
142
- });
143
-
144
- const disabled = computed(() => {
145
- // Отключаем кнопку только если есть незавершенные записи
146
- return value.value?.some(
147
- (i) => (i?.key && !i?.value) || (!i?.key && i?.value)
148
- );
149
- });
150
-
151
- const addItem = () => {
152
- value.value.push({ id: getRandomId("key-value-"), key: "", value: "" });
153
- };
154
-
155
- const deleteItem = (id) => {
156
- value.value = value.value?.filter((i) => i?.id !== id);
157
- };
158
-
159
- watch(
160
- value,
161
- (n) => {
162
- // Convert array back to object
163
- const result = {};
164
- n.forEach((item) => {
165
- if (item.key && item.value !== undefined) {
166
- result[item.key] = item.value;
167
- }
168
- });
169
- const tempValue = {};
170
- if (props.ignore.length) {
171
- props.ignore.forEach((item) => {
172
- tempValue[item] = metaParentValue.value[item];
173
- });
174
- }
175
-
176
- // Сохраняем игнорируемые поля и добавляем новые/измененные
177
- metaParentValue.value = {
178
- ...tempValue,
179
- ...result,
180
- };
181
- },
182
- { deep: true }
183
- );
184
- </script>
185
-
186
- <style scoped>
187
- .list-enter-active,
188
- .list-leave-active {
189
- transition: all 0.3s ease;
190
- }
191
- .list-enter-from,
192
- .list-leave-to {
193
- opacity: 0;
194
- transform: translateY(10px);
195
- }
196
-
197
- .sortable-ghost {
198
- opacity: 0.5;
199
- background: #f0f0f0;
200
- }
201
- </style>
@@ -1,3 +0,0 @@
1
- <template>
2
- <vs-richtext-md v-bind="$attrs" />
3
- </template>