@dcodegroup-au/page-builder 0.2.8 → 0.3.0

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 (69) hide show
  1. package/dist/page-builder.css +2 -2
  2. package/dist/page-builder.es.js +33363 -11858
  3. package/dist/page-builder.umd.js +59 -59
  4. package/example/src/App.vue +40 -679
  5. package/example/src/main.js +2 -1
  6. package/example/src/pages/BestLife.js +351 -0
  7. package/example/src/pages/Home.js +677 -0
  8. package/package.json +1 -1
  9. package/src/assets/icons.json +3569 -0
  10. package/src/components/ItemEdit.vue +147 -71
  11. package/src/components/LinkCardEdit.vue +139 -0
  12. package/src/components/PageBuilder.vue +43 -10
  13. package/src/components/PageRender.vue +12 -0
  14. package/src/components/builders/CollectionCarousel.vue +62 -0
  15. package/src/components/builders/Header.vue +82 -0
  16. package/src/components/builders/ImageBlock.vue +56 -0
  17. package/src/components/builders/Items.vue +112 -0
  18. package/src/components/builders/Links.vue +123 -0
  19. package/src/components/builders/Logos.vue +122 -0
  20. package/src/components/builders/NewsGrid.vue +59 -0
  21. package/src/components/builders/Paragraph.vue +93 -0
  22. package/src/components/builders/VideoGrid.vue +101 -0
  23. package/src/components/common/Button.vue +53 -0
  24. package/src/components/common/Card.vue +5 -1
  25. package/src/components/common/FileUpload.vue +1 -1
  26. package/src/components/common/Icon.vue +41 -0
  27. package/src/components/common/IconSelector.vue +106 -0
  28. package/src/components/common/LinkedTo.vue +9 -3
  29. package/src/components/helpers/bundleIcons.js +1189 -0
  30. package/src/components/index.js +2 -1
  31. package/src/components/presenters/components/{VCollectionGridPresenter.vue → CollectionGridPresenter.vue} +0 -5
  32. package/src/components/presenters/modules/CollectionCarousel.vue +2 -2
  33. package/src/components/presenters/modules/CollectionGrid.vue +2 -2
  34. package/src/components/presenters/modules/HeroHeader.vue +2 -2
  35. package/src/components/presenters/modules/LinkCard.vue +55 -0
  36. package/src/components/presenters/modules/LinkList.vue +51 -0
  37. package/src/components/presenters/modules/Paragraph.vue +26 -0
  38. package/src/components/presenters/modules/QuickLinks.vue +2 -2
  39. package/src/components/presenters/modules/StandardHeader.vue +32 -0
  40. package/src/components/presenters/modules/Timeline.vue +53 -0
  41. package/src/components/presenters/modules/TwoColumnsImageContent.vue +36 -0
  42. package/src/components/presenters/modules/VTabs.vue +2 -2
  43. package/src/utils/generateIconBundle.js +33 -0
  44. package/src/utils/generateIconJson.js +30 -0
  45. package/tailwind.config.js +5 -0
  46. package/src/components/builders/BaseModuleForm.vue +0 -86
  47. package/src/components/builders/LogoBuilder.vue +0 -167
  48. package/src/components/builders/PageBuilderCarousel.vue +0 -18
  49. package/src/components/builders/PageBuilderGrid.vue +0 -18
  50. package/src/components/builders/PageBuilderSectionHeader.vue +0 -30
  51. package/src/components/builders/PageModal.vue +0 -92
  52. package/src/components/builders/VCollectionCarousel.vue +0 -58
  53. package/src/components/builders/VHeader.vue +0 -55
  54. package/src/components/builders/VItems.vue +0 -110
  55. package/src/components/builders/VLinks.vue +0 -121
  56. package/src/components/builders/VLogos.vue +0 -120
  57. package/src/components/builders/VNewsGrid.vue +0 -55
  58. package/src/components/builders/VVideoGrid.vue +0 -99
  59. package/src/components/common/forms/LogosForm.vue +0 -39
  60. package/src/components/common/forms/PageBuilderLinksForm.vue +0 -39
  61. package/src/components/common/forms/SectionHeaderForm.vue +0 -45
  62. package/src/components/common/forms/TabForm.vue +0 -90
  63. /package/src/components/common/{VModal.vue → Modal.vue} +0 -0
  64. /package/src/components/common/{VToggle.vue → Toggle.vue} +0 -0
  65. /package/src/components/presenters/components/{VCarouselPresenter.vue → CarouselPresenter.vue} +0 -0
  66. /package/src/components/presenters/components/{VHeaderPresenter.vue → HeaderPresenter.vue} +0 -0
  67. /package/src/components/presenters/components/{VLinkPresenter.vue → LinkPresenter.vue} +0 -0
  68. /package/src/components/presenters/components/{VSliderPresenter.vue → SliderPresenter.vue} +0 -0
  69. /package/src/components/presenters/components/{VVerticalTabPresenter.vue → VerticalTabPresenter.vue} +0 -0
@@ -1,167 +0,0 @@
1
- <template>
2
- <div class="flex flex-col gap-4">
3
- <input type="hidden" name="content" :value="JSON.stringify(content)" v-if="props.withInput" />
4
- <div class="flex justify-between">
5
- <div class="flex flex-col gap-1">
6
- <div class="font-semibold text-gray-900">
7
- {{ props.title }}
8
- </div>
9
- <div class="text-sm text-gray-600">
10
- {{ props.description }}
11
- </div>
12
- </div>
13
- <dsg-button
14
- @click="addLink"
15
- :disabled="content.items.length >= props.maximumItems"
16
- :label="props.addButtonLabel"
17
- type="button"
18
- icon-before="plus"
19
- v-tooltip="{
20
- content: $t('menu.tooltips.link_builder.navbar_top_limit'),
21
- disabled: content.items.length < props.maximumItems,
22
- theme: 'elaa-tooltip',
23
- }"
24
- ></dsg-button>
25
- </div>
26
- <div
27
- v-for="(item, index) in content.items"
28
- :class="itemClasses"
29
- class="flex flex-col gap-4 rounded-xl bg-gray-50 px-6 py-4"
30
- :key="index"
31
- :ref="index === content.items.length - 1 ? (el) => (lastItemRef = el) : null"
32
- >
33
- <div class="flex items-center justify-between">
34
- <div class="text-lg font-semibold text-gray-900">Logo#{{ index + 1 }}</div>
35
- <div class="relative flex items-end">
36
- <action-menu>
37
- <button
38
- class="flex min-w-[15rem] items-center gap-2 p-2.5 hover:rounded-md hover:bg-gray-100"
39
- type="button"
40
- @click="handleDeleteItem(index)"
41
- >
42
- <TrashIcon class="h-5 w-5 cursor-pointer stroke-gray-500" />
43
- <span class="text-sm font-medium text-gray-700">
44
- {{ $t("menu.generic.delete_link") }}
45
- </span>
46
- </button>
47
- </action-menu>
48
- </div>
49
- </div>
50
- <hr class="bg-gray-200" />
51
- <div class="flex flex-col gap-6">
52
- <div class="flex flex-col gap-1.5">
53
- <file-upload
54
- :key="index"
55
- description=".JPG, .PNG (Max file size: 2 MB)"
56
- @upload="(e) => (item.image = e)"
57
- :existing-file="item.image"
58
- @remove="() => (item.image = null)"
59
- />
60
- <p class="text-red-400" v-if="errors[props.errorKey + index + '.image']">
61
- {{ errors[props.errorKey + index + ".image"][0] }}
62
- </p>
63
- </div>
64
- <DsgInput label="URL" :required="true" v-model="item.url"></DsgInput>
65
- </div>
66
- </div>
67
- </div>
68
- <DeleteModal
69
- ref="deleteModal"
70
- :title="t('admin.modals.delete.title', { item: t('admin.labels.link') })"
71
- :description="t('admin.modals.delete.description', { item: t('admin.labels.link') })"
72
- :confirm-callback="removeItem"
73
- ></DeleteModal>
74
- </template>
75
- <script setup>
76
- import { nextTick, ref, useTemplateRef } from "vue";
77
- import TrashIcon from "@/assets/img/icons/trash-01.svg";
78
- import { DsgInput } from "@dcodegroup-au/dsg-vue";
79
- import { useI18n } from "vue-i18n";
80
- import DeleteModal from "../../DeleteModal.vue";
81
- import { createLogo } from "@/js/vue/components/admin/pages/common/pageBuilderFactory.js";
82
-
83
- const { t } = useI18n();
84
-
85
- const deleteModalRef = useTemplateRef(`deleteModal`);
86
- const deleteItemIndex = ref(null);
87
- const lastItemRef = ref(null);
88
-
89
- const emit = defineEmits(["update"]);
90
-
91
- const props = defineProps({
92
- title: {
93
- type: String,
94
- required: true,
95
- },
96
- description: {
97
- type: String,
98
- required: true,
99
- },
100
- addButtonLabel: {
101
- type: String,
102
- required: true,
103
- },
104
- content: {
105
- type: Object,
106
- required: true,
107
- },
108
- errors: {
109
- required: false,
110
- },
111
- maximumItems: {
112
- type: Number,
113
- default: 5,
114
- },
115
- sites: {
116
- type: Object,
117
- required: true,
118
- },
119
- itemClasses: {
120
- type: String,
121
- required: false,
122
- },
123
- withInput: {
124
- type: Boolean,
125
- default: false,
126
- },
127
- errorKey: {
128
- type: String,
129
- default: "content.items.",
130
- },
131
- });
132
-
133
- const content = ref(props.content);
134
- if (!content.value.items) {
135
- content.value.items = [];
136
- }
137
-
138
- function addLink() {
139
- if (content.value.items.length >= props.maximumItems) {
140
- return;
141
- }
142
- content.value.items.push(createLogo());
143
-
144
- nextTick(() => {
145
- if (lastItemRef.value) {
146
- lastItemRef.value.scrollIntoView({ behavior: "smooth" });
147
- }
148
- });
149
-
150
- emit("update", content.value);
151
- }
152
-
153
- function removeItem() {
154
- content.value.items.splice(deleteItemIndex.value, 1);
155
- deleteItemIndex.value = null;
156
- emit("update", content.value);
157
- }
158
-
159
- const openDeleteModal = () => {
160
- deleteModalRef.value?.openModal();
161
- };
162
-
163
- function handleDeleteItem(index) {
164
- deleteItemIndex.value = index;
165
- openDeleteModal();
166
- }
167
- </script>
@@ -1,18 +0,0 @@
1
- <template>
2
- <div class="flex flex-col gap-4">
3
- <div class="text-lg font-semibold text-gray-900">
4
- {{ props.data.item.name }}
5
- </div>
6
- <hr class="bg-gray-200" />
7
- <div class="text-gray-600">
8
- {{ props.data.item.description }}
9
- </div>
10
- </div>
11
- </template>
12
- <script setup>
13
- import { defaultProps } from "@/js/vue/components/admin/pages/common/defaultProps";
14
-
15
- const props = defineProps({
16
- ...defaultProps,
17
- });
18
- </script>
@@ -1,18 +0,0 @@
1
- <template>
2
- <div class="flex flex-col gap-4">
3
- <div class="text-lg font-semibold text-gray-900">
4
- {{ props.data.item.name }}
5
- </div>
6
- <hr class="bg-gray-200" />
7
- <div class="text-gray-600">
8
- {{ props.data.item.description }}
9
- </div>
10
- </div>
11
- </template>
12
- <script setup>
13
- import { defaultProps } from "@/js/vue/components/admin/pages/common/defaultProps";
14
-
15
- const props = defineProps({
16
- ...defaultProps,
17
- });
18
- </script>
@@ -1,30 +0,0 @@
1
- <template>
2
- <div class="flex flex-col gap-4">
3
- <div class="text-lg font-semibold text-gray-900">
4
- {{ props.data.item.name }}
5
- </div>
6
- <hr class="bg-gray-200" />
7
- <page-builder-base-module-form
8
- :form="props.data.item.form_component"
9
- :sub-type="props.data.item.sub_type"
10
- :page="props.data.page"
11
- :data="dataRef"
12
- :attribute="props.data.pageAttribute"
13
- :module-index="props.data.subModuleIndex"
14
- :back-url="route('admin.pages.edit', { page: props.data.page.id })"
15
- :sites="sites"
16
- ></page-builder-base-module-form>
17
- </div>
18
- </template>
19
- <script setup>
20
- import { defaultProps } from "@/js/vue/components/admin/pages/common/defaultProps";
21
-
22
- const emit = defineEmits(["update"]);
23
- const route = inject("route");
24
-
25
- const props = defineProps({
26
- ...defaultProps,
27
- });
28
-
29
- const dataRef = ref(props.data.item);
30
- </script>
@@ -1,92 +0,0 @@
1
- <script setup lang="ts">
2
- import { inject, reactive, useTemplateRef, onMounted, onBeforeUnmount, ref } from "vue";
3
- import DsgModal from "../../dsg-vue/DsgModal.vue";
4
- import { DsgButton, DsgInput, DsgToggle } from "@dcodegroup-au/dsg-vue";
5
- import { DsgButtonProps } from "@dcodegroup-au/dsg-vue";
6
- import Form from "form-backend-validation";
7
- import route from "@/js/routes/routes";
8
- import { useI18n } from 'vue-i18n';
9
- import axios from "axios";
10
- export interface FormFields {
11
- title: string,
12
- id?: number,
13
- }
14
-
15
- export interface PageProps {
16
- button?: DsgButtonProps | false;
17
- initForm?: FormFields,
18
- primaryButtonLabel?: string,
19
- secondaryButtonLabel?: string,
20
- }
21
-
22
- const {
23
- button = false,
24
- initForm = {
25
- title: '',
26
- },
27
- primaryButtonLabel = 'Confirm',
28
- secondaryButtonLabel = 'Cancel',
29
- }: PageProps = defineProps<PageProps>();
30
-
31
- const modalRef = useTemplateRef<typeof DsgModal | null>('modal');
32
-
33
- const form = reactive(initForm);
34
- const editMode = ref(true);
35
- const { t } = useI18n();
36
- const primaryButton = ref(primaryButtonLabel)
37
- const openModal = (): void => {
38
- editMode.value = true;
39
- primaryButton.value = t('admin.buttons.create_category')
40
- modalRef.value?.open();
41
- }
42
- const closeModal = (): void => {
43
- modalRef.value?.close();
44
- }
45
- const save = async (): Promise<void> => {
46
- try {
47
- const response = await axios.put(route('api.admin.pages.update', {page: form.id}), form)
48
- console.log(response);
49
- bus?.$emit("reloadTable");
50
- modalRef.value?.close();
51
- } catch (e) {
52
- console.log(e);
53
- }
54
- }
55
- const bus = inject('bus');
56
- onMounted(() => {
57
- bus?.$on('openPageModal', openPageModal)
58
- bus?.$on('closePageModal', closePageModal)
59
- })
60
-
61
- onBeforeUnmount(()=>{
62
- bus?.$off('openPageModal', openPageModal)
63
- bus?.$off('closePageModal', closePageModal)
64
- })
65
-
66
- const openPageModal = ((data: Object): void=>{
67
- editMode.value = true;
68
- form.title = data.data.title;
69
- form.id = Number(data.data.id)
70
- primaryButton.value = t('admin.buttons.confirm')
71
- modalRef.value?.open();
72
- })
73
-
74
- const closePageModal = ((data: Object): void =>{
75
- modalRef.value?.close();
76
- })
77
-
78
- defineExpose({openModal});
79
- </script>
80
-
81
- <template>
82
- <DsgModal :title="$t('pages.edit_modal.title')"
83
- ref="modal"
84
- :width="400"
85
- :secondary-button="{label: secondaryButtonLabel, size: 'lg', theme: 'gray-secondary', classes: 'max-w-[90px]'}"
86
- @secondary-button-clicked="closeModal"
87
- :primary-button="{label: primaryButton, disabled: form.title === ''}"
88
- @primary-button-clicked="save"
89
- >
90
- <DsgInput :label="$t('pages.edit_modal.fields.title')" :required="true" v-model="form.title"></DsgInput>
91
- </DsgModal>
92
- </template>
@@ -1,58 +0,0 @@
1
- <template>
2
- <div class="flex flex-col">
3
- <div class="flex flex-col gap-4 mb-4 border-b border-gray-200 pb-4">
4
- <p class="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-4">
5
- Carousel
6
- </p>
7
- <div class="flex flex-col gap-6">
8
- <div class="flex flex-col gap-1.5">
9
- <input-wrapper
10
- v-if="componentData.button"
11
- is-vertical
12
- field="title"
13
- label-text="Button label *"
14
- class="w-full mb-4"
15
- :value="componentData.button.title"
16
- :limit="51"
17
- >
18
- <input
19
- v-model="componentData.button.title"
20
- name="title"
21
- type="text"
22
- placeholder="Title"
23
- :maxlength="51"
24
- class="border-1 border-solid border-gray-300 rounded-lg bg-white w-full"
25
- />
26
- </input-wrapper>
27
- <linked-to
28
- v-if="componentData?.button"
29
- label="Link to"
30
- name="button"
31
- v-model:type="componentData.button.type"
32
- v-model:url="componentData.button.url"
33
- v-model:openInNewTab="componentData.button.open_in_new_tab"
34
- :sites="sites"
35
- />
36
- </div>
37
- </div>
38
- </div>
39
- <div>
40
- <h3 v-if="componentData.content?.label" class="text-base text-gray-900 font-semibold">{{ componentData.content.label }}</h3>
41
- <p v-if="componentData.content?.supportive_text" class="text-gray-600 text-base font-normal mt-2">{{ componentData.content.supportive_text }}</p>
42
- </div>
43
- </div>
44
- </template>
45
- <script setup>
46
- import {ref} from "vue";
47
- import {defaultProps} from "@/components/helpers/defaultProps";
48
- import LinkedTo from "@/components/common/LinkedTo.vue";
49
- import InputWrapper from "@/components/common/InputWrapper.vue";
50
-
51
- const emit = defineEmits(["update"]);
52
-
53
- const props = defineProps({
54
- ...defaultProps,
55
- });
56
-
57
- const componentData = ref(props.data.component);
58
- </script>
@@ -1,55 +0,0 @@
1
- <template>
2
- <div class="flex flex-col gap-4">
3
- <p class="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-4">
4
- {{ dataRef.name }}
5
- </p>
6
- <input-wrapper
7
- v-if="dataRef.hasOwnProperty('title')"
8
- is-vertical
9
- field="title"
10
- label-text="Title *"
11
- class="w-full mb-4"
12
- :value="dataRef.title"
13
- :limit="51"
14
- >
15
- <input
16
- v-model="dataRef.title"
17
- name="title"
18
- type="text"
19
- placeholder="Title"
20
- :maxlength="51"
21
- class="border-1 border-solid border-gray-300 rounded-lg bg-white w-full"
22
- />
23
- </input-wrapper>
24
- <input-wrapper
25
- is-vertical
26
- v-if="dataRef.hasOwnProperty('supporting_text')"
27
- field="supporting_text"
28
- label-text="Supporting Text *"
29
- class="w-full mb-4"
30
- :value="dataRef.supporting_text"
31
- :limit="dataRef.supporting_text_max_length ?? 100"
32
- >
33
- <input
34
- v-model="dataRef.supporting_text"
35
- name="supporting_text"
36
- type="text"
37
- placeholder="Supporting Text"
38
- :maxlength="dataRef.supporting_text_max_length ?? 100"
39
- class="border-1 border-solid border-gray-300 rounded-lg bg-white w-full"
40
- />
41
- </input-wrapper>
42
- </div>
43
- </template>
44
- <script setup>
45
- import { ref } from "vue";
46
- import { defaultProps } from "@/components/helpers/defaultProps";
47
- import InputWrapper from "@/components/common/InputWrapper.vue";
48
-
49
- const emit = defineEmits(["update"]);
50
- const props = defineProps({
51
- ...defaultProps,
52
- });
53
-
54
- const dataRef = ref(props.data.component);
55
- </script>
@@ -1,110 +0,0 @@
1
- <template>
2
- <div class="flex justify-between pb-2">
3
- <p class="text-lg font-semibold text-gray-900">
4
- {{ dataRef.name }}
5
- </p>
6
- </div>
7
- <div class="flex flex-col gap-4">
8
- <div class="text-gray-600 border-b border-gray-200 pb-4 text-sm">
9
- {{ dataRef.supportive_text }}
10
- </div>
11
- <div class="flex flex-col gap-3">
12
- <div class="flex justify-between">
13
- <div class="flex flex-col gap-1">
14
- <div class="font-semibold text-gray-900">{{ parseName(type) }}</div>
15
- <div class="text-sm text-gray-600">This {{ singularize(type) }} can contain up to {{ dataRef.max_items }} {{ parseName(type, false) }}</div>
16
- </div>
17
- <div>
18
- <button
19
- :disabled="dataRef.data.length >= dataRef.max_items"
20
- @click="addItem"
21
- type="button"
22
- class="text-sm cursor-pointer flex items-center justify-center gap-1 rounded-[99px] border border-brand-600 bg-brand-500 px-3.5 py-2 font-semibold text-white hover:bg-brand-600"
23
- :class="{ 'border-gray-100 bg-gray-100 !text-gray-400 hover:bg-gray-100': dataRef.data.length >= dataRef.max_items }"
24
- >
25
- <PlusIcon class="h-5 w-5"></PlusIcon>
26
- <span>Add</span>
27
- </button>
28
- </div>
29
- </div>
30
- <div class="flex flex-col gap-3">
31
- <div v-for="(item, index) in dataRef.data"
32
- class="flex items-center gap-4 px-2 py-1 hover:bg-gray-100 rounded-lg"
33
- :class="{'bg-gray-200 hover:bg-gray-200': openItemStates[index]}">
34
- <div class="flex flex-1 items-center justify-between relative" @click="toggleItem(index);">
35
- <div class="flex flex-1 flex-col cursor-pointer" @click="edit(item, index)">
36
- <div class="text-xs text-gray-600">
37
- {{ singularize(parseName(type)) }} #{{ index + 1 }}
38
- </div>
39
- <div class="text-sm font-medium text-gray-900">
40
- {{ item.title }}
41
- </div>
42
- </div>
43
- <ActionMenu @removeItem="handleDeleteItem(index)" :enable-edit="true" @editItem="edit(item, index)"/>
44
- </div>
45
- </div>
46
- </div>
47
- </div>
48
- </div>
49
- <VModal ref="modalRef" :entity="singularize(type)" :callback="deleteCallback"></VModal>
50
- </template>
51
- <script setup>
52
- import {ref} from "vue";
53
- import PlusIcon from "@/assets/img/icons/plus.svg";
54
- import { defaultProps } from "@/components/helpers/defaultProps";
55
- import { singularize, parseName } from "@/components/helpers/common";
56
- import { createItem } from "@/components/helpers/pageBuilderFactory";
57
- import ActionMenu from "@/components/common/ActionMenu.vue";
58
- import VModal from "@/components/common/VModal.vue";
59
-
60
- const emit = defineEmits(["update"]);
61
- const props = defineProps({
62
- ...defaultProps,
63
- });
64
-
65
- const dataRef = ref(props.data.component);
66
- const type = dataRef.value.type;
67
- const modalRef = ref(null);
68
-
69
- const key = `${type.value}-openItemStates`;
70
- const openItemStates = ref(JSON.parse(window.localStorage.getItem(key)));
71
- if (!openItemStates.value) {
72
- openItemStates.value = {};
73
-
74
- dataRef.value.data.forEach((item, index) => {
75
- openItemStates.value[index] = false;
76
- });
77
-
78
- window.localStorage.setItem(key, JSON.stringify(openItemStates.value));
79
- }
80
-
81
- const toggleItem = (index) => {
82
- Object.keys(openItemStates.value).forEach((key) => {
83
- openItemStates.value[key] = false;
84
- });
85
- openItemStates.value[index] = !openItemStates.value[index];
86
- window.localStorage.setItem(key, JSON.stringify(openItemStates.value));
87
- };
88
-
89
- const addItem = () => {
90
- dataRef.value.data.push(createItem({}, type === 'sliders'));
91
- emit("update", false);
92
- };
93
-
94
- const handleDeleteItem = (index) => {
95
- modalRef?.value?.open(index);
96
- };
97
-
98
- const deleteCallback = (index) => {
99
- dataRef.value.data.splice(index, 1);
100
- emit("update", false);
101
- };
102
-
103
- const edit = (item, index) => {
104
- if (item.hasOwnProperty('edit_url')) {
105
- window.location.href = item.edit_url;
106
- }
107
-
108
- window.location.href = `/admin/pages/${props?.data?.page?.id}/sections/${props?.data?.sectionIndex}/components/${props?.data?.componentIndex}/items/${index}`;
109
- };
110
- </script>
@@ -1,121 +0,0 @@
1
- <template>
2
- <div class="flex justify-between pb-2">
3
- <div class="flex justify-between w-full py-1">
4
- <div>
5
- <p class="text-lg font-semibold text-gray-900">
6
- {{ componentData.name }}
7
- </p>
8
- <p class="text-sm text-gray-600 mt-1">
9
- {{ componentData.supportive_text }}
10
- </p>
11
- </div>
12
- <div>
13
- <a
14
- @click="addItem"
15
- class="text-sm cursor-pointer flex items-center justify-center gap-1 rounded-[99px] border border-brand-600 bg-brand-500 px-3.5 py-2 font-semibold text-white hover:bg-brand-600"
16
- :class="{ 'border-gray-100 bg-gray-100 !text-gray-400 hover:bg-gray-100': componentData.data?.length >= componentData.max_items }"
17
- >
18
- <PlusIcon class="h-5 w-5"></PlusIcon>
19
- <span>Add</span>
20
- </a>
21
- </div>
22
- </div>
23
- </div>
24
- <div class="flex flex-col gap-3">
25
- <div
26
- v-for="(item, index) in componentData.data"
27
- class="flex flex-col gap-4 rounded-xl px-6 py-4 bg-gray-200"
28
- :key="index"
29
- :ref="index === componentData.data.length - 1 ? (el) => (lastItemRef = el) : null"
30
- >
31
- <div class="flex items-center justify-between">
32
- <div class="text-lg font-semibold text-gray-900">
33
- Link #{{index + 1}}
34
- </div>
35
- <div class="relative flex items-end">
36
- <ActionMenu @removeItem="handleDeleteItem(index)"/>
37
- </div>
38
- </div>
39
- <div class="flex flex-col gap-6">
40
- <div class="flex flex-col gap-1.5">
41
- <input-wrapper
42
- is-vertical
43
- field="title"
44
- label-text="Title *"
45
- class="w-full mb-4"
46
- :value="item.title"
47
- :limit="20"
48
- >
49
- <input
50
- v-model="item.title"
51
- name="title"
52
- type="text"
53
- placeholder="Title"
54
- :maxlength="20"
55
- class="border-1 border-solid border-gray-300 rounded-lg bg-white w-full"
56
- />
57
- </input-wrapper>
58
- <linked-to
59
- label="Linked to"
60
- :name="`link_${index + 1}`"
61
- v-model:type="item.type"
62
- v-model:url="item.url"
63
- v-model:openInNewTab="item.open_in_new_tab"
64
- :sites="sites"
65
- />
66
- </div>
67
- </div>
68
- </div>
69
- </div>
70
- <VModal ref="modalRef" entity="link" :callback="deleteCallback"></VModal>
71
- </template>
72
- <script setup>
73
- import {ref, nextTick} from "vue";
74
- import PlusIcon from "@/assets/img/icons/plus.svg";
75
- import {defaultProps} from "@/components/helpers/defaultProps";
76
- import {createLink} from "@/components/helpers/pageBuilderFactory";
77
- import ActionMenu from "@/components/common/ActionMenu.vue";
78
- import InputWrapper from "@/components/common/InputWrapper.vue";
79
- import LinkedTo from "@/components/common/LinkedTo.vue";
80
- import VModal from "@/components/common/VModal.vue";
81
-
82
- const emit = defineEmits(["update"]);
83
-
84
- const props = defineProps({
85
- ...defaultProps,
86
- });
87
-
88
- const componentData = ref(props.data.component);
89
- const modalRef = ref(null);
90
- const lastItemRef = ref(null);
91
- const deleteItemIndex = ref(null);
92
-
93
- function addItem() {
94
- if (!componentData.value.hasOwnProperty('data')) {
95
- componentData.value.data = [];
96
- }
97
-
98
- if (componentData.value.data?.length >= componentData.value.max_items) {
99
- return;
100
- }
101
- componentData.value.data?.push(createLink());
102
-
103
- nextTick(() => {
104
- if (lastItemRef.value) {
105
- lastItemRef.value.scrollIntoView({behavior: "smooth"});
106
- }
107
- });
108
-
109
- emit("update", false);
110
- }
111
-
112
- const handleDeleteItem = (index) => {
113
- deleteItemIndex.value = index;
114
- modalRef?.value?.open(index);
115
- }
116
-
117
- const deleteCallback = (index) => {
118
- componentData.value.data?.splice(index, 1);
119
- emit("update", false);
120
- };
121
- </script>