@opengis/cms 0.0.22 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-W-qQIppj-DRzFSjU1.js +2452 -0
- package/dist/index.html +28 -34
- package/dist/index.js +13915 -0
- package/dist/index.umd.cjs +153 -0
- package/package.json +4 -11
- package/dist/assets/AddUser-CX-McfRW.js +0 -1
- package/dist/assets/ApiKeys-DSv1exYv.js +0 -16
- package/dist/assets/Appearance-DDtOUvCV.js +0 -6
- package/dist/assets/ArticlesPage-D6B3cZsl.js +0 -6
- package/dist/assets/BuilderPage-CCeSMVWe.js +0 -1
- package/dist/assets/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-DVYVfYF4.js +0 -1
- package/dist/assets/CollectionsPage-CHk8Cn5k.js +0 -1
- package/dist/assets/Dashboard-Bs7sXO6h.js +0 -11
- package/dist/assets/EditCollectionPage-gPuLJrN8.js +0 -41
- package/dist/assets/EmailPage-DhlWsPxk.js +0 -1
- package/dist/assets/EmptyData-Ct-xQv_N.js +0 -1
- package/dist/assets/FeedbackPage-DtaOncVv.js +0 -1
- package/dist/assets/Logs-CZ5klHNK.js +0 -1
- package/dist/assets/MediaBreadcrumb-BpOxt5PK.js +0 -11
- package/dist/assets/MediaPage-DqRcZFlO.js +0 -16
- package/dist/assets/MenuAddPage-BLcoVgrS.js +0 -1
- package/dist/assets/MenuItemPage-B2otXqkz.js +0 -20
- package/dist/assets/MenuPage-C00m4Fc_.js +0 -1
- package/dist/assets/MonacoEditor.vue_vue_type_script_setup_true_lang-CjoEsC67.js +0 -3
- package/dist/assets/PermissionsPage-LtqcCJ14.js +0 -1
- package/dist/assets/Settings-BHH6RoBP.js +0 -1
- package/dist/assets/SettingsTable-CY5pZx1z.js +0 -1
- package/dist/assets/SettingsTitle-t4WJBFxZ.js +0 -1
- package/dist/assets/SingletonsPage-Bn2Ypjhs.js +0 -6
- package/dist/assets/TagsPage-DAiakEth.js +0 -1
- package/dist/assets/UniversalTable.vue_vue_type_script_setup_true_lang-BQ5m4aZd.js +0 -11
- package/dist/assets/UniversalTablePagination.vue_vue_type_script_setup_true_lang-DppVBws0.js +0 -1
- package/dist/assets/Users-CMH5j0db.js +0 -1
- package/dist/assets/UsersPage-CDGreEib.js +0 -1
- package/dist/assets/arrow-up-DCe0WsrM.js +0 -16
- package/dist/assets/calendar-o9t4MkD2.js +0 -6
- package/dist/assets/chevron-left-WFftVS9c.js +0 -6
- package/dist/assets/chevron-right-BiiSb3Be.js +0 -6
- package/dist/assets/contentForm-unZQhjCu.js +0 -6
- package/dist/assets/en-BDx3Svx8.js +0 -1
- package/dist/assets/eye-Dijywc6g.js +0 -6
- package/dist/assets/file-B_duymIT.js +0 -6
- package/dist/assets/general-CkN_0qIV.js +0 -1
- package/dist/assets/index-BIp7eSXk.js +0 -1
- package/dist/assets/index-DCW2e4Az.js +0 -9
- package/dist/assets/index-DGweaj24.js +0 -1
- package/dist/assets/index-W-qQIppj-BDlsxaGB.js +0 -1
- package/dist/assets/index-W-qQIppj-BsopI3Hz-BIZR-dhy.js +0 -1
- package/dist/assets/index-oQz9FOqL.css +0 -1
- package/dist/assets/index-yMJAVBXk.js +0 -290
- package/dist/assets/list-CXRbSNky.js +0 -6
- package/dist/assets/logo-Cct5WB26.png +0 -0
- package/dist/assets/pencil-CwnPP4IJ.js +0 -6
- package/dist/assets/plus-DLR44m6p.js +0 -6
- package/dist/assets/save-FeDrOUOd.js +0 -6
- package/dist/assets/search-C4-fHihx.js +0 -6
- package/dist/assets/square-pen-xVs4e8Yb.js +0 -6
- package/dist/assets/trash-2-BGXMNU3d.js +0 -6
- package/dist/assets/uk-BA7DIKEL.js +0 -1
- package/dist/assets/useDebounce-DFq3rxAW.js +0 -1
- package/dist/assets/vs-form-reletion-link-C-xrdHDl.js +0 -20
- package/dist/assets/vs-form-reletion-link-bk-9ZkDH.css +0 -1
- package/dist/assets/vue.-sixQ7xP-CUPNuJcq.js +0 -1
- package/dist/assets/vuedraggable.umd-W_2WTF6i.js +0 -14
- package/dist/assets/x-D2t-wfBe.js +0 -6
- package/module/cms/card/cms.content.table/index.yml +0 -17
- package/module/cms/card/cms.content.table/main_info.hbs +0 -26
- package/module/cms/card/cms.menu.table/content_info.hbs +0 -16
- package/module/cms/card/cms.menu.table/index.yml +0 -18
- package/module/cms/card/cms.menu.table/main_info.hbs +0 -22
- package/module/cms/card/cms.settings.table/index.yml +0 -13
- package/module/cms/card/cms.settings.table/main_info.hbs +0 -20
- package/module/cms/cls/content.status.json +0 -18
- package/module/cms/cls/user_type.json +0 -10
- package/module/cms/form/admin.users.form.json +0 -78
- package/module/cms/form/cms.content.form.json +0 -79
- package/module/cms/form/cms.menu.form.json +0 -69
- package/module/cms/form/cms.settings.form.json +0 -32
- package/module/cms/menu.json +0 -24
- package/module/cms/router.js +0 -169
- package/module/cms/select/cms.page_type.sql +0 -2
- package/module/cms/select/collection.sql +0 -1
- package/module/cms/select/locale.sql +0 -17
- package/module/cms/select/news_tag_id.sql +0 -12
- package/module/cms/select/tag_id.sql +0 -1
- package/module/cms/table/admin.users.table.json +0 -54
- package/module/cms/table/cms.content.table.json +0 -106
- package/module/cms/table/cms.menu.table.json +0 -73
- package/module/cms/table/cms.settings.table.json +0 -57
- package/module/cms/table/collection.default.table.json +0 -102
- package/module/cms/table/single.default.table.json +0 -115
- package/src/App.css +0 -52
- package/src/App.vue +0 -62
- package/src/assets/image.png +0 -0
- package/src/assets/main.css +0 -3
- package/src/assets/tailwind-3.4.17.js +0 -113
- package/src/components/LanguageSwitcher.vue +0 -73
- package/src/components/SettingsCard.vue +0 -40
- package/src/components/builder/CreateForm.vue +0 -128
- package/src/components/builder/formTypeSchema.js +0 -145
- package/src/components/builder/tabs/index.ts +0 -9
- package/src/components/builder/tabs/vs-builder-edit.vue +0 -133
- package/src/components/builder/tabs/vs-builder-monaco.vue +0 -29
- package/src/components/builder/tabs/vs-builder-preview.vue +0 -39
- package/src/components/builder/vs-builder-datatable-controls.vue +0 -138
- package/src/components/builder/vs-builder-datatable-form.vue +0 -80
- package/src/components/builder/vs-builder-datatable.vue +0 -191
- package/src/components/builder/vs-builder-list-item.vue +0 -110
- package/src/components/collections/CollectionsBreadcrumb.vue +0 -52
- package/src/components/collections/CollectionsGrid.vue +0 -176
- package/src/components/collections/ContentBlock.vue +0 -75
- package/src/components/collections/formWrapper.vue +0 -156
- package/src/components/dashboard/ContentItem.vue +0 -82
- package/src/components/dashboard/DashboardHeader.vue +0 -33
- package/src/components/dashboard/QuickActions.vue +0 -84
- package/src/components/dashboard/RecentContent.vue +0 -54
- package/src/components/dashboard/StatCard.vue +0 -63
- package/src/components/dashboard/StatsGrid.vue +0 -28
- package/src/components/form-components/MonacoEditor.vue +0 -104
- package/src/components/form-components/VsFormMeta.vue +0 -40
- package/src/components/form-components/VsFormTags.vue +0 -150
- package/src/components/form-components/custom-datatable/vs-form-custom-datatable-add.vue +0 -84
- package/src/components/form-components/custom-datatable/vs-form-custom-datatable-controls.vue +0 -106
- package/src/components/form-components/index.js +0 -23
- package/src/components/form-components/reference/vs-form-reference-add.vue +0 -92
- package/src/components/form-components/reference/vs-form-reference-controls.vue +0 -101
- package/src/components/form-components/reference-list/referenceOptionList.js +0 -78
- package/src/components/form-components/reference-list/vs-form-reference-add.vue +0 -145
- package/src/components/form-components/reference-list/vs-form-reference-choce.vue +0 -39
- package/src/components/form-components/reference-list/vs-form-reference-controls.vue +0 -110
- package/src/components/form-components/reference-skeleton/about-skeleton.vue +0 -37
- package/src/components/form-components/reference-skeleton/banner-skeleton.vue +0 -29
- package/src/components/form-components/reference-skeleton/body-skeleton.vue +0 -56
- package/src/components/form-components/reference-skeleton/cards-skeleton.vue +0 -47
- package/src/components/form-components/reference-skeleton/documents-skeleton.vue +0 -64
- package/src/components/form-components/reference-skeleton/faq-skeleton.vue +0 -64
- package/src/components/form-components/reference-skeleton/form-skeleton.vue +0 -41
- package/src/components/form-components/reference-skeleton/index.js +0 -36
- package/src/components/form-components/reference-skeleton/infoLine-skeleton.vue +0 -37
- package/src/components/form-components/reference-skeleton/news-skeleton.vue +0 -54
- package/src/components/form-components/reference-skeleton/slider-skeleton.vue +0 -41
- package/src/components/form-components/reference-skeleton/tabs-skeleton.vue +0 -40
- package/src/components/form-components/reference-skeleton/team-skeleton.vue +0 -103
- package/src/components/form-components/reference-skeleton/usefulLinks-skeleton.vue +0 -52
- package/src/components/form-components/reference-skeleton/video-skeleton.vue +0 -36
- package/src/components/form-components/testReferenceTypes.js +0 -773
- package/src/components/form-components/vs-form-color-picker.vue +0 -29
- package/src/components/form-components/vs-form-custom-datatable.vue +0 -214
- package/src/components/form-components/vs-form-integer.vue +0 -86
- package/src/components/form-components/vs-form-key-value.vue +0 -201
- package/src/components/form-components/vs-form-marcdown-md.vue +0 -3
- package/src/components/form-components/vs-form-media-select.vue +0 -780
- package/src/components/form-components/vs-form-reference-list.vue +0 -97
- package/src/components/form-components/vs-form-reference.vue +0 -59
- package/src/components/form-components/vs-form-relation.vue +0 -30
- package/src/components/form-components/vs-form-reletion-link.vue +0 -34
- package/src/components/form-components/vs-form-select-collection.vue +0 -0
- package/src/components/form-components/vs-form-slug.vue +0 -72
- package/src/components/form-components/vs-form-tiptap.vue +0 -7
- package/src/components/form-components/vs-richtext-md.vue +0 -3
- package/src/components/icons/BellIcon.vue +0 -17
- package/src/components/icons/GlobeIcon.vue +0 -18
- package/src/components/icons/KeyIcon.vue +0 -20
- package/src/components/icons/PaletteIcon.vue +0 -22
- package/src/components/icons/SettingsIcon.vue +0 -19
- package/src/components/icons/ShieldIcon.vue +0 -18
- package/src/components/icons/UsersIcon.vue +0 -19
- package/src/components/icons/icon-chevron-right.vue +0 -16
- package/src/components/icons/icon-drag.vue +0 -20
- package/src/components/icons/icon-file-text.vue +0 -21
- package/src/components/icons/icon-folder.vue +0 -18
- package/src/components/icons/icon-grid.vue +0 -17
- package/src/components/icons/icon-group.vue +0 -19
- package/src/components/icons/icon-home.vue +0 -16
- package/src/components/icons/icon-image.vue +0 -18
- package/src/components/icons/icon-list.vue +0 -20
- package/src/components/icons/icon-more.vue +0 -17
- package/src/components/icons/icon-plus.vue +0 -17
- package/src/components/icons-types/icon-array.vue +0 -22
- package/src/components/icons-types/icon-boolean.vue +0 -18
- package/src/components/icons-types/icon-datalist.vue +0 -22
- package/src/components/icons-types/icon-date.vue +0 -20
- package/src/components/icons-types/icon-datetime.vue +0 -20
- package/src/components/icons-types/icon-file.vue +0 -21
- package/src/components/icons-types/icon-gallery.vue +0 -18
- package/src/components/icons-types/icon-image.vue +0 -19
- package/src/components/icons-types/icon-integer.vue +0 -20
- package/src/components/icons-types/icon-merkdown.vue +0 -18
- package/src/components/icons-types/icon-multiselect.vue +0 -22
- package/src/components/icons-types/icon-number.vue +0 -20
- package/src/components/icons-types/icon-radio.vue +0 -22
- package/src/components/icons-types/icon-reference-list.vue +0 -22
- package/src/components/icons-types/icon-reference.vue +0 -20
- package/src/components/icons-types/icon-relation.vue +0 -22
- package/src/components/icons-types/icon-richtext.vue +0 -18
- package/src/components/icons-types/icon-select.vue +0 -22
- package/src/components/icons-types/icon-slug.vue +0 -19
- package/src/components/icons-types/icon-text.vue +0 -19
- package/src/components/icons-types/index.js +0 -43
- package/src/components/layout/Layout.vue +0 -67
- package/src/components/layout/Sidebar.vue +0 -128
- package/src/components/media/FileUploadProgress.vue +0 -29
- package/src/components/media/MediaBreadcrumb.vue +0 -42
- package/src/components/media/MediaCreateFolder.vue +0 -59
- package/src/components/media/MediaFileInfo.vue +0 -148
- package/src/components/media/MediaGrid.vue +0 -148
- package/src/components/media/MediaList.vue +0 -148
- package/src/components/media/MediaViewControls.vue +0 -38
- package/src/components/media/TypeTag.vue +0 -23
- package/src/components/menu/AddNewItemInTree.vue +0 -75
- package/src/components/menu/MenuBody.vue +0 -149
- package/src/components/menu/MenuItem.vue +0 -73
- package/src/components/menu/MenuList.vue +0 -101
- package/src/components/referencec/index.ts +0 -7
- package/src/components/referencec/vs-reference-faq.vue +0 -61
- package/src/components/referencec/vs-reference-user-card.vue +0 -40
- package/src/components/settings/NotificationSettings.vue +0 -32
- package/src/components/settings/SettingsTable.vue +0 -50
- package/src/components/settings/SettingsTitle.vue +0 -33
- package/src/components/settings/SettingsToggleItem.vue +0 -25
- package/src/components/sidebar/DropdownMenu.vue +0 -34
- package/src/components/sidebar/SettingsSidebar.vue +0 -121
- package/src/components/sidebar/SidebarFooter.vue +0 -52
- package/src/components/sidebar/SidebarHeader.vue +0 -57
- package/src/components/sidebar/SidebarMenu.vue +0 -78
- package/src/components/ui/EmptyData.vue +0 -76
- package/src/components/ui/UniversalTable.vue +0 -310
- package/src/components/ui/UniversalTableFilters.vue +0 -0
- package/src/components/ui/UniversalTablePagination.vue +0 -118
- package/src/components/ui/VsPreview.vue +0 -75
- package/src/composables/useCollectionView.ts +0 -21
- package/src/composables/useDebounce.ts +0 -26
- package/src/composables/useMonaco.ts +0 -28
- package/src/composables/useTheme.ts +0 -40
- package/src/content/test-slug/metadata.json +0 -1
- package/src/i18n.ts +0 -75
- package/src/index.css +0 -3
- package/src/index.ts +0 -122
- package/src/locales/en.json +0 -778
- package/src/locales/uk.json +0 -797
- package/src/main.ts +0 -41
- package/src/pages/Dashboard.vue +0 -168
- package/src/pages/EmailPage.vue +0 -183
- package/src/pages/FeedbackPage.vue +0 -232
- package/src/pages/MediaPage.vue +0 -372
- package/src/pages/TagsPage.vue +0 -207
- package/src/pages/builder/BuilderPage.vue +0 -195
- package/src/pages/builder/EditCollectionPage.vue +0 -163
- package/src/pages/collections/ArticlesPage.vue +0 -385
- package/src/pages/collections/CollectionsPage.vue +0 -146
- package/src/pages/collections/SingletonsPage.vue +0 -119
- package/src/pages/collections/contentForm.vue +0 -484
- package/src/pages/collections/schema/seo.ts +0 -27
- package/src/pages/menu/MenuAddPage.vue +0 -123
- package/src/pages/menu/MenuItemPage.vue +0 -183
- package/src/pages/menu/MenuPage.vue +0 -133
- package/src/pages/settings/ApiKeys.vue +0 -75
- package/src/pages/settings/Appearance.vue +0 -80
- package/src/pages/settings/Logs.vue +0 -260
- package/src/pages/settings/PermissionsPage.vue +0 -237
- package/src/pages/settings/Settings.vue +0 -186
- package/src/pages/settings/Users.vue +0 -109
- package/src/pages/settings/general.vue +0 -154
- package/src/pages/settings/generalScheme.js +0 -132
- package/src/pages/users/AddUser.vue +0 -106
- package/src/pages/users/UsersPage.vue +0 -98
- package/src/props/builder.ts +0 -67
- package/src/props/content.ts +0 -56
- package/src/props/media.ts +0 -63
- package/src/router/index.ts +0 -181
- package/src/types/fastify-auth.d.ts +0 -4
- package/src/utils/getField.js +0 -270
- package/src/utils/translit.js +0 -19
- 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="[&_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 [&:has([role=checkbox])]:pr-0 [&>[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 [&:has([role=checkbox])]:pr-0 [&>[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 [&:has([role=checkbox])]:pr-0 [&>[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="[&_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 [&:has([role=checkbox])]:pr-0 [&>[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 [&:has([role=checkbox])]:pr-0 [&>[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 [&:has([role=checkbox])]:pr-0 [&>[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>
|