@dcodegroup-au/page-builder 0.1.8 → 0.1.9
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/page-builder.css +2 -2
- package/dist/page-builder.es.js +12470 -12316
- package/dist/page-builder.umd.js +51 -51
- package/example/src/App.vue +50 -1
- package/package.json +1 -1
- package/src/components/PageBuilder.vue +2 -0
- package/src/components/PageRender.vue +2 -0
- package/src/components/builders/VHeader.vue +4 -2
- package/src/components/builders/VLogos.vue +118 -0
- package/src/components/common/FileUpload.vue +6 -2
- package/src/components/presenters/modules/LogoCloud.vue +49 -0
- package/src/components/builders/PageBuilderLogos.vue +0 -29
package/example/src/App.vue
CHANGED
|
@@ -121,16 +121,29 @@ const page = {
|
|
|
121
121
|
{
|
|
122
122
|
title: "Logo cloud",
|
|
123
123
|
type: "logo",
|
|
124
|
+
display: "horizontal",
|
|
124
125
|
components: [
|
|
125
126
|
{
|
|
126
127
|
name: "Section header",
|
|
127
128
|
type: "header",
|
|
128
|
-
|
|
129
|
+
supporting_text: "ELAA is proudly supporting",
|
|
129
130
|
},
|
|
130
131
|
{
|
|
131
132
|
id: 2,
|
|
132
133
|
name: "Logos",
|
|
133
134
|
type: "logos",
|
|
135
|
+
max_items: 7,
|
|
136
|
+
height: 'medium',
|
|
137
|
+
data: [
|
|
138
|
+
{
|
|
139
|
+
url: "https://childroadsafety.org.au/",
|
|
140
|
+
logo: "https://beta-frontend.elaa.org.au/img/logos/starting_out_safely.png",
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
url: "https://carseatssavelives.com.au/",
|
|
144
|
+
logo: "https://beta-frontend.elaa.org.au/img/logos/car_seats_save_lives.jpg",
|
|
145
|
+
}
|
|
146
|
+
]
|
|
134
147
|
}
|
|
135
148
|
]
|
|
136
149
|
},
|
|
@@ -213,6 +226,42 @@ const page = {
|
|
|
213
226
|
}
|
|
214
227
|
]
|
|
215
228
|
},
|
|
229
|
+
{
|
|
230
|
+
title: "Logo cloud",
|
|
231
|
+
type: "logo",
|
|
232
|
+
display: "vertical",
|
|
233
|
+
components: [
|
|
234
|
+
{
|
|
235
|
+
name: "Section header",
|
|
236
|
+
type: "header",
|
|
237
|
+
supporting_text: "ELAA’s preferred partners offer special benefits to ELAA members and support ELAA’s activities",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: 2,
|
|
241
|
+
name: "Logos",
|
|
242
|
+
type: "logos",
|
|
243
|
+
max_items: 7,
|
|
244
|
+
height: 'small',
|
|
245
|
+
data: [
|
|
246
|
+
{
|
|
247
|
+
url: "/",
|
|
248
|
+
logo: "https://beta-frontend.elaa.org.au/img/logos/anzuk.png",
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
url: "/",
|
|
252
|
+
logo: "https://beta-frontend.elaa.org.au/img/logos/bunnings.png",
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
url: "/",
|
|
256
|
+
logo: "https://beta-frontend.elaa.org.au/img/logos/hesta.png",
|
|
257
|
+
},{
|
|
258
|
+
url: "/",
|
|
259
|
+
logo: "",
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
},
|
|
216
265
|
{
|
|
217
266
|
title: "Collection grid",
|
|
218
267
|
type: "collection_grid",
|
package/package.json
CHANGED
|
@@ -70,6 +70,7 @@ import Instructions from "@/components/builders/Instructions.vue";
|
|
|
70
70
|
import VItems from "@/components/builders/VItems.vue";
|
|
71
71
|
import VLinks from "@/components/builders/VLinks.vue";
|
|
72
72
|
import VHeader from "@/components/builders/VHeader.vue";
|
|
73
|
+
import VLogos from "@/components/builders/VLogos.vue";
|
|
73
74
|
|
|
74
75
|
const emit = defineEmits(["save", "close"]);
|
|
75
76
|
const props = defineProps({
|
|
@@ -94,6 +95,7 @@ const componentMaps = ref({
|
|
|
94
95
|
links: markRaw(VLinks),
|
|
95
96
|
header: markRaw(VHeader),
|
|
96
97
|
link_grid: markRaw(VLinks),
|
|
98
|
+
logos: markRaw(VLogos),
|
|
97
99
|
});
|
|
98
100
|
|
|
99
101
|
if (!openStates.value) {
|
|
@@ -14,6 +14,7 @@ import {ref, markRaw} from "vue";
|
|
|
14
14
|
import HeroHeader from "@/components/presenters/modules/HeroHeader.vue";
|
|
15
15
|
import QuickLinks from "@/components/presenters/modules/QuickLinks.vue";
|
|
16
16
|
import VTabs from "@/components/presenters/modules/VTabs.vue";
|
|
17
|
+
import LogoCloud from "@/components/presenters/modules/LogoCloud.vue";
|
|
17
18
|
|
|
18
19
|
const props = defineProps({
|
|
19
20
|
page: {
|
|
@@ -26,6 +27,7 @@ const componentMaps = ref({
|
|
|
26
27
|
header: markRaw(HeroHeader),
|
|
27
28
|
quick_links: markRaw(QuickLinks),
|
|
28
29
|
tabs: markRaw(VTabs),
|
|
30
|
+
logo: markRaw(LogoCloud),
|
|
29
31
|
});
|
|
30
32
|
|
|
31
33
|
const currentComponent = (section) => {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
{{ dataRef.name }}
|
|
5
5
|
</p>
|
|
6
6
|
<input-wrapper
|
|
7
|
+
v-if="dataRef.hasOwnProperty('title')"
|
|
7
8
|
is-vertical
|
|
8
9
|
field="title"
|
|
9
10
|
label-text="Title *"
|
|
@@ -22,18 +23,19 @@
|
|
|
22
23
|
</input-wrapper>
|
|
23
24
|
<input-wrapper
|
|
24
25
|
is-vertical
|
|
26
|
+
v-if="dataRef.hasOwnProperty('supporting_text')"
|
|
25
27
|
field="supporting_text"
|
|
26
28
|
label-text="Supporting Text *"
|
|
27
29
|
class="w-full mb-4"
|
|
28
30
|
:value="dataRef.supporting_text"
|
|
29
|
-
:limit="100"
|
|
31
|
+
:limit="dataRef.supporting_text_max_length ?? 100"
|
|
30
32
|
>
|
|
31
33
|
<input
|
|
32
34
|
v-model="dataRef.supporting_text"
|
|
33
35
|
name="supporting_text"
|
|
34
36
|
type="text"
|
|
35
37
|
placeholder="Supporting Text"
|
|
36
|
-
:maxlength="100"
|
|
38
|
+
:maxlength="dataRef.supporting_text_max_length ?? 100"
|
|
37
39
|
class="border-1 border-solid border-gray-300 rounded-lg bg-white w-full"
|
|
38
40
|
/>
|
|
39
41
|
</input-wrapper>
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
This section can contain up to {{ componentData.max_items }} logos
|
|
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
|
+
Logo #{{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
|
+
<FileUpload
|
|
42
|
+
name="image"
|
|
43
|
+
background="bg-white"
|
|
44
|
+
v-model="item.logo"
|
|
45
|
+
/>
|
|
46
|
+
<input-wrapper
|
|
47
|
+
is-vertical
|
|
48
|
+
field="url"
|
|
49
|
+
label-text="Url *"
|
|
50
|
+
class="w-full my-4"
|
|
51
|
+
:value="item.url"
|
|
52
|
+
>
|
|
53
|
+
<input
|
|
54
|
+
v-model="item.url"
|
|
55
|
+
name="url"
|
|
56
|
+
type="text"
|
|
57
|
+
placeholder="Enter your url"
|
|
58
|
+
class="border-1 border-solid border-gray-300 rounded-lg bg-white w-full"
|
|
59
|
+
/>
|
|
60
|
+
</input-wrapper>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<VModal ref="modalRef" entity="logo" :callback="deleteCallback"></VModal>
|
|
66
|
+
</template>
|
|
67
|
+
<script setup>
|
|
68
|
+
import {ref, nextTick} from "vue";
|
|
69
|
+
import PlusIcon from "@/assets/img/icons/plus.svg";
|
|
70
|
+
import {defaultProps} from "@/components/helpers/defaultProps";
|
|
71
|
+
import ActionMenu from "@/components/common/ActionMenu.vue";
|
|
72
|
+
import InputWrapper from "@/components/common/InputWrapper.vue";
|
|
73
|
+
import VModal from "@/components/common/VModal.vue";
|
|
74
|
+
import FileUpload from "@/components/common/FileUpload.vue";
|
|
75
|
+
|
|
76
|
+
const emit = defineEmits(["update"]);
|
|
77
|
+
|
|
78
|
+
const props = defineProps({
|
|
79
|
+
...defaultProps,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const componentData = ref(props.data.component);
|
|
83
|
+
const modalRef = ref(null);
|
|
84
|
+
const lastItemRef = ref(null);
|
|
85
|
+
const deleteItemIndex = ref(null);
|
|
86
|
+
|
|
87
|
+
function addItem() {
|
|
88
|
+
if (!componentData.value.hasOwnProperty('data')) {
|
|
89
|
+
componentData.value.data = [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (componentData.value.data?.length >= componentData.value.max_items) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
componentData.value.data?.push({
|
|
96
|
+
url: null,
|
|
97
|
+
logo: null,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
nextTick(() => {
|
|
101
|
+
if (lastItemRef.value) {
|
|
102
|
+
lastItemRef.value.scrollIntoView({behavior: "smooth"});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
emit("update", false);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const handleDeleteItem = (index) => {
|
|
110
|
+
deleteItemIndex.value = index;
|
|
111
|
+
modalRef?.value?.open(index);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const deleteCallback = (index) => {
|
|
115
|
+
componentData.value.data?.splice(index, 1);
|
|
116
|
+
emit("update", false);
|
|
117
|
+
};
|
|
118
|
+
</script>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
@todo handle upload here
|
|
6
6
|
<span class="file-upload-preview">
|
|
7
7
|
<img
|
|
8
|
-
class="img rounded-lg"
|
|
8
|
+
class="img rounded-lg h-[200px] object-contain"
|
|
9
9
|
:src="modelValue"
|
|
10
10
|
title="Image"
|
|
11
11
|
/>
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<i class="fal fa-times" @click="deleteFile(file)"></i>
|
|
28
28
|
</a>
|
|
29
29
|
</div>
|
|
30
|
-
<div class="relative" v-show="!modelValue">
|
|
30
|
+
<div :class="'relative rounded-lg ' + background" v-show="!modelValue">
|
|
31
31
|
<div class="dropzone border border-dashed rounded-lg z-10 h-[200px] w-full cursor-pointer relative"
|
|
32
32
|
ref="dropzone">
|
|
33
33
|
</div>
|
|
@@ -79,6 +79,10 @@ const props = defineProps({
|
|
|
79
79
|
type: String,
|
|
80
80
|
required: false,
|
|
81
81
|
},
|
|
82
|
+
background: {
|
|
83
|
+
type: String,
|
|
84
|
+
default: "",
|
|
85
|
+
}
|
|
82
86
|
});
|
|
83
87
|
const emit = defineEmits(["update:modelValue"]);
|
|
84
88
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full relative" :class="{'bg-gray-50': !isHorizontal}">
|
|
3
|
+
<div class="1xl:max-w-[1824px] mx-auto relative flex justify-center items-center"
|
|
4
|
+
:class="{'py-8': isHorizontal, 'flex-col py-6': !isHorizontal}">
|
|
5
|
+
<div v-for="(component, index) in section.components">
|
|
6
|
+
<p v-if="component?.type === 'header' && component?.supporting_text"
|
|
7
|
+
class="mr-[48px] text-base text-gray-600 font-medium"
|
|
8
|
+
:class="{'mb-6': !isHorizontal}"
|
|
9
|
+
>
|
|
10
|
+
{{ component?.supporting_text }}
|
|
11
|
+
</p>
|
|
12
|
+
<div v-if="component?.type === 'logos'" class="flex flex-wrap justify-center" :class="{'gap-6': isHorizontal, 'gap-12': !isHorizontal}">
|
|
13
|
+
<template v-for="logo in component.data">
|
|
14
|
+
<a :href="logo?.url" title="Brand">
|
|
15
|
+
<img v-if="logo?.logo" :src="logo?.logo" :class="getLogoHeight(component?.height)" alt="Brand Logo"/>
|
|
16
|
+
<span v-else class="text-sm">No photo</span>
|
|
17
|
+
</a>
|
|
18
|
+
</template>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup>
|
|
26
|
+
import {ref} from "vue";
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
section: {
|
|
30
|
+
required: true,
|
|
31
|
+
type: Object,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const section = ref(props.section);
|
|
36
|
+
const isHorizontal = section.value.display === 'horizontal';
|
|
37
|
+
|
|
38
|
+
const getLogoHeight = (size) => {
|
|
39
|
+
if (size === 'small') {
|
|
40
|
+
return 'h-[32px]';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (size === 'medium') {
|
|
44
|
+
return 'h-[40px]';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return 'h-[32px]';
|
|
48
|
+
};
|
|
49
|
+
</script>
|
|
@@ -1,29 +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
|
-
:page="props.data.page"
|
|
10
|
-
:data="dataRef"
|
|
11
|
-
:attribute="props.data.pageAttribute"
|
|
12
|
-
:module-index="props.data.subModuleIndex"
|
|
13
|
-
:back-url="route('admin.pages.edit', { page: props.data.page.id })"
|
|
14
|
-
:sites="sites"
|
|
15
|
-
></page-builder-base-module-form>
|
|
16
|
-
</div>
|
|
17
|
-
</template>
|
|
18
|
-
<script setup>
|
|
19
|
-
import { defaultProps } from "@/js/vue/components/admin/pages/common/defaultProps";
|
|
20
|
-
|
|
21
|
-
const emit = defineEmits(["update"]);
|
|
22
|
-
const route = inject("route");
|
|
23
|
-
|
|
24
|
-
const props = defineProps({
|
|
25
|
-
...defaultProps,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const dataRef = ref(props.data.item);
|
|
29
|
-
</script>
|