@myissue/vue-website-page-builder 3.4.10 → 3.4.12
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/README.md +2 -0
- package/dist/style.css +1 -1
- package/dist/vue-website-page-builder.js +8093 -7836
- package/dist/vue-website-page-builder.umd.cjs +217 -103
- package/package.json +1 -1
- package/src/App.vue +0 -1
- package/src/Components/Homepage/Footer.vue +22 -23
- package/src/Components/PageBuilder/EditorMenu/Editables/HTMLEditor.vue +4 -16
- package/src/Components/PageBuilder/ToolbarOption/ToolbarOption.vue +4 -3
- package/src/css/style.css +9 -16
- package/src/services/PageBuilderService.ts +65 -1
- package/src/tests/DefaultComponents/DefaultBuilderComponents.vue +152 -55
- package/src/tests/PageBuilderTest.vue +8 -69
- package/src/utils/html-elements/component.ts +159 -46
- package/src/utils/html-elements/themes.ts +85 -0
package/package.json
CHANGED
package/src/App.vue
CHANGED
|
@@ -4,30 +4,29 @@ const version = __APP_VERSION__
|
|
|
4
4
|
|
|
5
5
|
<template>
|
|
6
6
|
<div
|
|
7
|
-
class="pbx-flex pbx-justify-between pbx-gap-2 pbx-
|
|
7
|
+
class="pbx-flex pbx-justify-between pbx-gap-2 lg:pbx-px-12 pbx-mx-2 pbx-py-3 pbx-border-t pbx-border-t-gray-900"
|
|
8
8
|
>
|
|
9
|
-
<
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<span class="pbx-text-myPrimaryDarkGrayColor pbx-text-sm">{{ version }}</span>
|
|
9
|
+
<p class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-medium pbx-underline">
|
|
10
|
+
<a
|
|
11
|
+
href="https://www.npmjs.com/package/@myissue/vue-website-page-builder"
|
|
12
|
+
target="_blank"
|
|
13
|
+
class="pbx-myPrimaryLink pbx-text-myPrimaryDarkGrayColor"
|
|
14
|
+
>
|
|
15
|
+
Install via npm
|
|
16
|
+
</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-medium pbx-underline">
|
|
20
|
+
<a
|
|
21
|
+
href="https://github.com/myissue-org/vue-website-page-builder"
|
|
22
|
+
target="_blank"
|
|
23
|
+
class="pbx-myPrimaryLink pbx-text-myPrimaryDarkGrayColor"
|
|
24
|
+
>
|
|
25
|
+
View on GitHub
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
|
+
<p class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-medium pbx-underline">
|
|
29
|
+
<span class="pbx-text-myPrimaryDarkGrayColor">{{ version }}</span>
|
|
31
30
|
</p>
|
|
32
31
|
</div>
|
|
33
32
|
</template>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { ref, computed } from 'vue'
|
|
2
|
+
import { ref, computed, nextTick } from 'vue'
|
|
3
3
|
import { sharedPageBuilderStore } from '../../../../stores/shared-store'
|
|
4
4
|
import ModalBuilder from '../../../../Components/Modals/ModalBuilder.vue'
|
|
5
5
|
import EditorAccordion from '../EditorAccordion.vue'
|
|
@@ -18,7 +18,6 @@ const props = defineProps({
|
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
const getElement = computed(() => pageBuilderStateStore.getElement)
|
|
21
|
-
const getComponents = computed(() => pageBuilderStateStore.getComponents)
|
|
22
21
|
|
|
23
22
|
const elementHTML = computed(() => {
|
|
24
23
|
if (!getElement.value || !(getElement.value instanceof HTMLElement)) {
|
|
@@ -32,26 +31,15 @@ const showModalHTMLEditor = ref(false)
|
|
|
32
31
|
const editableHtml = ref('')
|
|
33
32
|
const editableComponents = ref('')
|
|
34
33
|
|
|
35
|
-
const handleShowHTMLEditor = () => {
|
|
34
|
+
const handleShowHTMLEditor = async () => {
|
|
36
35
|
showModalHTMLEditor.value = true
|
|
37
36
|
|
|
38
37
|
if (!props.globalPage) {
|
|
39
38
|
editableHtml.value = elementHTML.value
|
|
39
|
+
return
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
const compsHTMLString =
|
|
44
|
-
Array.isArray(getComponents.value) &&
|
|
45
|
-
getComponents.value
|
|
46
|
-
.map((comp) => {
|
|
47
|
-
return comp.html_code
|
|
48
|
-
.replace(/data-componentid="[^"]*"/g, '') // remove data-componentid
|
|
49
|
-
.replace(/\s{2,}/g, ' ') // optional: clean up excess spaces
|
|
50
|
-
})
|
|
51
|
-
.join('\n')
|
|
52
|
-
|
|
53
|
-
editableComponents.value = compsHTMLString
|
|
54
|
-
}
|
|
42
|
+
editableComponents.value = await pageBuilderService.generateHtmlFromComponents()
|
|
55
43
|
}
|
|
56
44
|
|
|
57
45
|
const handleCloseHTMLEditor = () => {
|
|
@@ -82,11 +82,12 @@ const openMainSettings = function () {
|
|
|
82
82
|
const showHTMLSettings = ref(false)
|
|
83
83
|
|
|
84
84
|
// handle slideover window
|
|
85
|
-
const
|
|
85
|
+
const closeHTMLSettings = function () {
|
|
86
86
|
showHTMLSettings.value = false
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
const openHTMLSettings = function () {
|
|
89
|
+
const openHTMLSettings = async function () {
|
|
90
|
+
await pageBuilderService.generateHtmlFromComponents()
|
|
90
91
|
showHTMLSettings.value = true
|
|
91
92
|
}
|
|
92
93
|
</script>
|
|
@@ -219,7 +220,7 @@ const openHTMLSettings = function () {
|
|
|
219
220
|
maxWidth="5xl"
|
|
220
221
|
:showModalBuilder="showHTMLSettings"
|
|
221
222
|
:title="translate('Selected HTML')"
|
|
222
|
-
@closeMainModalBuilder="
|
|
223
|
+
@closeMainModalBuilder="closeHTMLSettings"
|
|
223
224
|
minHeight=""
|
|
224
225
|
maxHeight=""
|
|
225
226
|
>
|
package/src/css/style.css
CHANGED
|
@@ -440,10 +440,6 @@
|
|
|
440
440
|
width: 100%;
|
|
441
441
|
cursor: pointer;
|
|
442
442
|
}
|
|
443
|
-
#page-builder-editor strong,
|
|
444
|
-
#pagebuilder strong {
|
|
445
|
-
font-weight: 500;
|
|
446
|
-
}
|
|
447
443
|
|
|
448
444
|
.pbx-reorder-highlight {
|
|
449
445
|
animation: pbx-reorder-flash 0.4s ease-in-out;
|
|
@@ -520,18 +516,9 @@
|
|
|
520
516
|
#page-builder-editor ul,
|
|
521
517
|
#pagebuilder ul {
|
|
522
518
|
list-style: disc !important;
|
|
523
|
-
padding: 1rem 0 0
|
|
519
|
+
padding: 1rem 0 0 1.4rem;
|
|
524
520
|
margin-left: 1em;
|
|
525
|
-
line-height:
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
#page-builder-editor ol,
|
|
529
|
-
#page-builder-editor-editable-area ol,
|
|
530
|
-
#page-builder-editor ul,
|
|
531
|
-
#page-builder-editor-editable-area ul {
|
|
532
|
-
list-style: disc !important;
|
|
533
|
-
padding: 1rem 0 0 1rem;
|
|
534
|
-
line-height: 1.2;
|
|
521
|
+
line-height: 2rem;
|
|
535
522
|
}
|
|
536
523
|
|
|
537
524
|
.pbx-headless-dropdown {
|
|
@@ -593,9 +580,15 @@
|
|
|
593
580
|
color: inherit;
|
|
594
581
|
text-decoration: none;
|
|
595
582
|
}
|
|
583
|
+
|
|
584
|
+
#page-builder-editor strong,
|
|
585
|
+
#pagebuilder strong {
|
|
586
|
+
font: inherit;
|
|
587
|
+
font-weight: 500;
|
|
588
|
+
}
|
|
589
|
+
|
|
596
590
|
#pagebuilder code,
|
|
597
591
|
#pagebuilder pre,
|
|
598
|
-
#pagebuilder strong,
|
|
599
592
|
#pagebuilder em {
|
|
600
593
|
font: inherit;
|
|
601
594
|
font-weight: inherit;
|
|
@@ -1599,6 +1599,29 @@ export class PageBuilderService {
|
|
|
1599
1599
|
}
|
|
1600
1600
|
}
|
|
1601
1601
|
}
|
|
1602
|
+
} else if (parentSection) {
|
|
1603
|
+
// If the section is not empty, update its HTML content in the store
|
|
1604
|
+
const componentId = parentSection.getAttribute('data-componentid')
|
|
1605
|
+
if (componentId) {
|
|
1606
|
+
const components = this.pageBuilderStateStore.getComponents
|
|
1607
|
+
if (components) {
|
|
1608
|
+
const componentIndex = components.findIndex(
|
|
1609
|
+
(c: ComponentObject) => c.id === componentId,
|
|
1610
|
+
)
|
|
1611
|
+
if (componentIndex !== -1) {
|
|
1612
|
+
const updatedComponent = {
|
|
1613
|
+
...components[componentIndex],
|
|
1614
|
+
html_code: parentSection.outerHTML,
|
|
1615
|
+
}
|
|
1616
|
+
const newComponents = [
|
|
1617
|
+
...components.slice(0, componentIndex),
|
|
1618
|
+
updatedComponent,
|
|
1619
|
+
...components.slice(componentIndex + 1),
|
|
1620
|
+
]
|
|
1621
|
+
this.pageBuilderStateStore.setComponents(newComponents)
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1602
1625
|
}
|
|
1603
1626
|
}
|
|
1604
1627
|
|
|
@@ -1888,7 +1911,7 @@ export class PageBuilderService {
|
|
|
1888
1911
|
* Syncs the current DOM state of components to the in-memory store.
|
|
1889
1912
|
* @private
|
|
1890
1913
|
*/
|
|
1891
|
-
|
|
1914
|
+
public syncDomToStoreOnly() {
|
|
1892
1915
|
const pagebuilder = document.querySelector('#pagebuilder')
|
|
1893
1916
|
if (!pagebuilder) return
|
|
1894
1917
|
|
|
@@ -1906,6 +1929,30 @@ export class PageBuilderService {
|
|
|
1906
1929
|
this.pageBuilderStateStore.setComponents(componentsToSave)
|
|
1907
1930
|
}
|
|
1908
1931
|
|
|
1932
|
+
public async generateHtmlFromComponents(): Promise<string> {
|
|
1933
|
+
this.syncDomToStoreOnly()
|
|
1934
|
+
await nextTick()
|
|
1935
|
+
|
|
1936
|
+
const components = this.pageBuilderStateStore.getComponents
|
|
1937
|
+
|
|
1938
|
+
if (!Array.isArray(components)) {
|
|
1939
|
+
return ''
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
1943
|
+
await nextTick()
|
|
1944
|
+
// Attach event listeners to all editable elements in the Builder
|
|
1945
|
+
await this.addListenersToEditableElements()
|
|
1946
|
+
|
|
1947
|
+
return components
|
|
1948
|
+
.map((comp) => {
|
|
1949
|
+
return comp.html_code
|
|
1950
|
+
.replace(/data-componentid="[^"]*"/g, '') // remove data-componentid
|
|
1951
|
+
.replace(/\s{2,}/g, ' ') // optional: clean up excess spaces
|
|
1952
|
+
})
|
|
1953
|
+
.join('\n')
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1909
1956
|
/**
|
|
1910
1957
|
* Saves the current DOM state of components to local storage.
|
|
1911
1958
|
* @private
|
|
@@ -2166,6 +2213,15 @@ export class PageBuilderService {
|
|
|
2166
2213
|
this.pageBuilderStateStore.setIsRestoring(false)
|
|
2167
2214
|
}
|
|
2168
2215
|
|
|
2216
|
+
public async returnLatestComponents() {
|
|
2217
|
+
this.syncDomToStoreOnly()
|
|
2218
|
+
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
2219
|
+
await nextTick()
|
|
2220
|
+
// Attach event listeners to all editable elements in the Builder
|
|
2221
|
+
await this.addListenersToEditableElements()
|
|
2222
|
+
|
|
2223
|
+
return this.pageBuilderStateStore.getComponents
|
|
2224
|
+
}
|
|
2169
2225
|
/**
|
|
2170
2226
|
* Gets the local storage key for the current resource.
|
|
2171
2227
|
* @returns {string | null} The local storage key.
|
|
@@ -2444,6 +2500,14 @@ export class PageBuilderService {
|
|
|
2444
2500
|
this.addHyperlinkToElement(hyperlinkEnable, urlInput || null, openHyperlinkInNewTab || false)
|
|
2445
2501
|
}
|
|
2446
2502
|
|
|
2503
|
+
public async addTheme(components: string): Promise<void> {
|
|
2504
|
+
if (components) {
|
|
2505
|
+
this.validateMountingHTML(components)
|
|
2506
|
+
await this.mountComponentsToDOM(components)
|
|
2507
|
+
}
|
|
2508
|
+
await this.handleAutoSave()
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2447
2511
|
/**
|
|
2448
2512
|
* Adds a new component to the page builder.
|
|
2449
2513
|
* @param {ComponentObject} componentObject - The component to add.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
3
|
import componentHelpers from '../../utils/html-elements/componentHelpers'
|
|
4
4
|
import components from '../../utils/html-elements/component'
|
|
5
|
+
import themes from '../../utils/html-elements/themes'
|
|
5
6
|
import { usePageBuilderModal } from '../../composables/usePageBuilderModal'
|
|
6
7
|
import type { ComponentObject } from '../../types'
|
|
7
8
|
import { getPageBuilder } from '../../composables/builderInstance'
|
|
@@ -20,6 +21,9 @@ defineProps({
|
|
|
20
21
|
|
|
21
22
|
const isLoading = ref(false)
|
|
22
23
|
|
|
24
|
+
const selectedThemeSelection = ref('Components')
|
|
25
|
+
|
|
26
|
+
const componentOrThemes = ['Components', 'Themes']
|
|
23
27
|
const selectedCategory = ref('All')
|
|
24
28
|
|
|
25
29
|
const categories = computed(() => {
|
|
@@ -34,9 +38,32 @@ const filteredComponents = computed(() => {
|
|
|
34
38
|
return components[0].components.data.filter((comp) => comp.category === selectedCategory.value)
|
|
35
39
|
})
|
|
36
40
|
|
|
41
|
+
const selectedThemeCategory = ref('All')
|
|
42
|
+
|
|
43
|
+
const themeCategories = computed(() => {
|
|
44
|
+
const allCategories = themes[0].themes.data.map((comp) => comp.category)
|
|
45
|
+
return ['All', ...new Set(allCategories)]
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const filteredThemes = computed(() => {
|
|
49
|
+
if (selectedThemeCategory.value === 'All') {
|
|
50
|
+
return themes[0].themes.data
|
|
51
|
+
}
|
|
52
|
+
return themes[0].themes.data.filter((comp) => comp.category === selectedThemeCategory.value)
|
|
53
|
+
})
|
|
54
|
+
|
|
37
55
|
// Get modal close function
|
|
38
56
|
const { closeAddComponentModal } = usePageBuilderModal()
|
|
39
57
|
|
|
58
|
+
// Super simple component addition with professional modal closing!
|
|
59
|
+
const handleDropTheme = async function (components: string) {
|
|
60
|
+
isLoading.value = true
|
|
61
|
+
|
|
62
|
+
await pageBuilderService.addTheme(components)
|
|
63
|
+
closeAddComponentModal()
|
|
64
|
+
isLoading.value = false
|
|
65
|
+
}
|
|
66
|
+
|
|
40
67
|
// Super simple component addition with professional modal closing!
|
|
41
68
|
const handleDropComponent = async function (componentObject: ComponentObject) {
|
|
42
69
|
isLoading.value = true
|
|
@@ -104,81 +131,151 @@ const convertToComponentObject = function (comp: any): ComponentObject {
|
|
|
104
131
|
</div>
|
|
105
132
|
</template>
|
|
106
133
|
<div v-if="!isLoading">
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
134
|
+
<div class="pbx-mb-4 pbx-flex pbx-jusitify-left pbx-items-center pbx-gap-2">
|
|
135
|
+
<button
|
|
136
|
+
v-for="category in componentOrThemes"
|
|
137
|
+
:key="category"
|
|
138
|
+
@click="selectedThemeSelection = category"
|
|
139
|
+
class="pbx-mySecondaryButton pbx-text-xs pbx-px-4"
|
|
140
|
+
:class="[
|
|
141
|
+
selectedThemeSelection === category
|
|
142
|
+
? 'pbx-bg-myPrimaryLinkColor pbx-text-white hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white'
|
|
143
|
+
: 'hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white',
|
|
144
|
+
]"
|
|
112
145
|
>
|
|
146
|
+
{{ translate(category) }}
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<!-- theme is selected start -->
|
|
151
|
+
<template v-if="selectedThemeSelection === 'Themes'">
|
|
152
|
+
<div class="pbx-mb-8">
|
|
153
|
+
<h3 class="pbx-myQuaternaryHeader pbx-mb-4">{{ translate('Themes') }}</h3>
|
|
154
|
+
<div class="pbx-mb-4 pbx-flex pbx-jusitify-left pbx-items-center pbx-gap-2">
|
|
155
|
+
<button
|
|
156
|
+
v-for="category in themeCategories"
|
|
157
|
+
:key="category"
|
|
158
|
+
@click="selectedThemeCategory = category"
|
|
159
|
+
class="pbx-mySecondaryButton pbx-text-xs pbx-px-4"
|
|
160
|
+
:class="[
|
|
161
|
+
selectedThemeCategory === category
|
|
162
|
+
? 'pbx-bg-myPrimaryLinkColor pbx-text-white hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white'
|
|
163
|
+
: 'hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white',
|
|
164
|
+
]"
|
|
165
|
+
>
|
|
166
|
+
{{ translate(category) }}
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
113
170
|
<div
|
|
114
|
-
|
|
115
|
-
:key="helper.title"
|
|
116
|
-
class="pbx-border-solid pbx-border pbx-border-gray-400 pbx-overflow-hidden hover:pbx-border-myPrimaryLinkColor pbx-duration-100 pbx-cursor-pointer pbx-p-4"
|
|
117
|
-
@click="handleDropComponent(helper)"
|
|
171
|
+
class="pbx-grid pbx-grid-cols-1 sm:pbx-grid-cols-2 md:pbx-grid-cols-3 pbx-gap-4 pbx-pb-4 pbx-min-h-[96rem]"
|
|
118
172
|
>
|
|
119
173
|
<div
|
|
120
|
-
|
|
174
|
+
v-for="theme in filteredThemes"
|
|
175
|
+
:key="theme.title"
|
|
176
|
+
class="pbx-border-solid pbx-border pbx-border-gray-400 pbx-overflow-hidden hover:pbx-border-myPrimaryLinkColor pbx-duration-100 pbx-cursor-pointer pbx-max-h-96"
|
|
177
|
+
@click="handleDropTheme(theme.html_code)"
|
|
121
178
|
>
|
|
122
|
-
<div
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
179
|
+
<div
|
|
180
|
+
class="pbx-overflow-hidden pbx-whitespace-pre-line pbx-flex-1 pbx-h-auto pbx-border-0 pbx-border-solid pbx-border-b pbx-border-gray-200 lg:pbx-py-10 pbx-py-8 pbx-px-2"
|
|
181
|
+
>
|
|
182
|
+
<!-- Use SVG preview instead of external images -->
|
|
183
|
+
<div
|
|
184
|
+
class="pbx-max-h-72 pbx-cursor-pointer pbx-bg-white pbx-mx-auto pbx-flex pbx-items-center pbx-justify-center"
|
|
185
|
+
v-html="theme.cover_image"
|
|
186
|
+
></div>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="pbx-p-3">
|
|
189
|
+
<h4 class="pbx-myPrimaryParagraph pbx-text-sm pbx-font-normal">
|
|
190
|
+
{{ translate(theme.title) }}
|
|
191
|
+
</h4>
|
|
192
|
+
<div class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-normal pbx-pt-2">
|
|
193
|
+
{{ translate('Click to add theme') }}
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
130
196
|
</div>
|
|
131
197
|
</div>
|
|
132
198
|
</div>
|
|
133
|
-
</
|
|
199
|
+
</template>
|
|
200
|
+
<!-- theme is selected end -->
|
|
134
201
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
:key="category"
|
|
142
|
-
@click="selectedCategory = category"
|
|
143
|
-
class="pbx-mySecondaryButton pbx-text-xs pbx-px-4"
|
|
144
|
-
:class="[
|
|
145
|
-
selectedCategory === category
|
|
146
|
-
? 'pbx-bg-myPrimaryLinkColor pbx-text-white hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white'
|
|
147
|
-
: 'hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white',
|
|
148
|
-
]"
|
|
202
|
+
<template v-if="selectedThemeSelection === 'Components'">
|
|
203
|
+
<!-- Helper Components Section -->
|
|
204
|
+
<div class="pbx-mb-8">
|
|
205
|
+
<h3 class="pbx-myQuaternaryHeader pbx-mb-4">{{ translate('Helper Components') }}</h3>
|
|
206
|
+
<div
|
|
207
|
+
class="pbx-px-2 pbx-grid pbx-grid-cols-1 sm:pbx-grid-cols-2 md:pbx-grid-cols-3 lg:pbx-grid-cols-4 pbx-gap-4"
|
|
149
208
|
>
|
|
150
|
-
|
|
151
|
-
|
|
209
|
+
<div
|
|
210
|
+
v-for="helper in componentHelpers"
|
|
211
|
+
:key="helper.title"
|
|
212
|
+
class="pbx-border-solid pbx-border pbx-border-gray-400 pbx-overflow-hidden hover:pbx-border-myPrimaryLinkColor pbx-duration-100 pbx-cursor-pointer pbx-max-h-96 pbx-p-4"
|
|
213
|
+
@click="handleDropComponent(helper)"
|
|
214
|
+
>
|
|
215
|
+
<div
|
|
216
|
+
class="pbx-max-h-72 pbx-cursor-pointer pbx-object-contain pbx-bg-white pbx-mx-auto"
|
|
217
|
+
>
|
|
218
|
+
<div v-if="false" class="pbx-mr-2" v-html="helper.icon"></div>
|
|
219
|
+
<h4 class="pbx-myPrimaryParagraph pbx-text-base pbx-font-medium">
|
|
220
|
+
{{ translate(helper.title) }}
|
|
221
|
+
</h4>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-normal pbx-pt-2">
|
|
224
|
+
{{ translate('Click to add') }} {{ helper.title.toLowerCase() }}
|
|
225
|
+
{{ translate('component') }}
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
152
229
|
</div>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
>
|
|
230
|
+
|
|
231
|
+
<!-- Regular Components Section -->
|
|
232
|
+
<div class="pbx-px-2" v-if="customMediaComponent">
|
|
233
|
+
<h3 class="pbx-myQuaternaryHeader pbx-mb-4">{{ translate('Layout Components') }}</h3>
|
|
234
|
+
<div class="pbx-mb-4 pbx-flex pbx-jusitify-left pbx-items-center pbx-gap-2">
|
|
235
|
+
<button
|
|
236
|
+
v-for="category in categories"
|
|
237
|
+
:key="category"
|
|
238
|
+
@click="selectedCategory = category"
|
|
239
|
+
class="pbx-mySecondaryButton pbx-text-xs pbx-px-4"
|
|
240
|
+
:class="[
|
|
241
|
+
selectedCategory === category
|
|
242
|
+
? 'pbx-bg-myPrimaryLinkColor pbx-text-white hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white'
|
|
243
|
+
: 'hover:pbx-bg-myPrimaryLinkColor hover:pbx-text-white',
|
|
244
|
+
]"
|
|
245
|
+
>
|
|
246
|
+
{{ translate(category) }}
|
|
247
|
+
</button>
|
|
248
|
+
</div>
|
|
156
249
|
<div
|
|
157
|
-
|
|
158
|
-
:key="comp.title"
|
|
159
|
-
class="pbx-border-solid pbx-border pbx-border-gray-400 pbx-overflow-hidden hover:pbx-border-myPrimaryLinkColor pbx-duration-100 pbx-cursor-pointer"
|
|
160
|
-
@click="handleDropComponent(convertToComponentObject(comp))"
|
|
250
|
+
class="pbx-grid pbx-grid-cols-1 sm:pbx-grid-cols-2 md:pbx-grid-cols-3 pbx-gap-4 pbx-pb-4 pbx-min-h-[96rem]"
|
|
161
251
|
>
|
|
162
252
|
<div
|
|
163
|
-
|
|
253
|
+
v-for="comp in filteredComponents"
|
|
254
|
+
:key="comp.title"
|
|
255
|
+
class="pbx-border-solid pbx-border pbx-border-gray-400 pbx-overflow-hidden hover:pbx-border-myPrimaryLinkColor pbx-duration-100 pbx-cursor-pointer pbx-max-h-96"
|
|
256
|
+
@click="handleDropComponent(convertToComponentObject(comp))"
|
|
164
257
|
>
|
|
165
|
-
<!-- Use SVG preview instead of external images -->
|
|
166
258
|
<div
|
|
167
|
-
class="pbx-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
</
|
|
175
|
-
<div class="pbx-
|
|
176
|
-
|
|
259
|
+
class="pbx-overflow-hidden pbx-whitespace-pre-line pbx-flex-1 pbx-h-auto pbx-border-0 pbx-border-solid pbx-border-b pbx-border-gray-200 lg:pbx-py-10 pbx-py-8 pbx-px-2"
|
|
260
|
+
>
|
|
261
|
+
<!-- Use SVG preview instead of external images -->
|
|
262
|
+
<div
|
|
263
|
+
class="pbx-max-h-72 pbx-cursor-pointer pbx-bg-white pbx-mx-auto pbx-flex pbx-items-center pbx-justify-center"
|
|
264
|
+
v-html="comp.cover_image"
|
|
265
|
+
></div>
|
|
266
|
+
</div>
|
|
267
|
+
<div class="pbx-p-3">
|
|
268
|
+
<h4 class="pbx-myPrimaryParagraph pbx-text-sm pbx-font-normal">
|
|
269
|
+
{{ translate(comp.title) }}
|
|
270
|
+
</h4>
|
|
271
|
+
<div class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-normal pbx-pt-2">
|
|
272
|
+
{{ translate('Click to add component') }}
|
|
273
|
+
</div>
|
|
177
274
|
</div>
|
|
178
275
|
</div>
|
|
179
276
|
</div>
|
|
180
277
|
</div>
|
|
181
|
-
</
|
|
278
|
+
</template>
|
|
182
279
|
<div>
|
|
183
280
|
<button class="pbx-sr-only">Focusable fallback</button>
|
|
184
281
|
</div>
|
|
@@ -69,75 +69,14 @@ watch(currentTranslations, async () => {
|
|
|
69
69
|
</script>
|
|
70
70
|
|
|
71
71
|
<template>
|
|
72
|
-
<div>
|
|
73
|
-
<div class="
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}}
|
|
81
|
-
</h2>
|
|
82
|
-
<p class="pbx-myPrimaryParagraph pbx-font-normal">
|
|
83
|
-
{{
|
|
84
|
-
translate(
|
|
85
|
-
'The web builder for stunning pages. Enable users to design and publish modern pages at any scale. Build responsive pages like listings, jobs or blog posts and manage content easily using the free click & drop Page Builder. Developed with TypeScript, Vue 3, Composition API, Pinia, CSS, Tailwind CSS and HTML.',
|
|
86
|
-
)
|
|
87
|
-
}}
|
|
88
|
-
<br />
|
|
89
|
-
</p>
|
|
90
|
-
<div class="pbx-mt-4">
|
|
91
|
-
<p class="pbx-myPrimaryParagraph pbx-font-normal">
|
|
92
|
-
{{
|
|
93
|
-
translate(
|
|
94
|
-
'Download or install our powerful, flexible, and easy-to-use free Vue 3 Page Builder via',
|
|
95
|
-
)
|
|
96
|
-
}}
|
|
97
|
-
<br />
|
|
98
|
-
<strong> npm:</strong>
|
|
99
|
-
<a
|
|
100
|
-
class="pbx-text-myPrimaryLinkColor"
|
|
101
|
-
href="https://www.npmjs.com/package/@myissue/vue-website-page-builder"
|
|
102
|
-
target="_blank"
|
|
103
|
-
>
|
|
104
|
-
@myissue/vue-website-page-builder
|
|
105
|
-
</a>
|
|
106
|
-
</p>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
<div class="lg:pbx-m-2 pbx-m-1">
|
|
110
|
-
<!-- :CustomBuilderComponents="DemoBuilderComponentsTest" -->
|
|
111
|
-
<PageBuilder
|
|
112
|
-
:CustomMediaLibraryComponent="DemoMediaLibraryComponentTest"
|
|
113
|
-
:showPublishButton="true"
|
|
114
|
-
@handlePublishPageBuilder="publishPageBuilder"
|
|
115
|
-
></PageBuilder>
|
|
116
|
-
</div>
|
|
72
|
+
<div class="pbx-bg-white">
|
|
73
|
+
<div class="lg:pbx-p-2">
|
|
74
|
+
<!-- :CustomBuilderComponents="DemoBuilderComponentsTest" -->
|
|
75
|
+
<PageBuilder
|
|
76
|
+
:CustomMediaLibraryComponent="DemoMediaLibraryComponentTest"
|
|
77
|
+
:showPublishButton="true"
|
|
78
|
+
@handlePublishPageBuilder="publishPageBuilder"
|
|
79
|
+
></PageBuilder>
|
|
117
80
|
</div>
|
|
118
|
-
|
|
119
|
-
<FullWidthElement :descriptionArea="true" class="pbx-bg-gray-50">
|
|
120
|
-
<template #title>
|
|
121
|
-
{{ translate('Everything you need. Break free from design limitations') }}
|
|
122
|
-
</template>
|
|
123
|
-
<template #description>
|
|
124
|
-
<p class="pbx-myPrimaryParagraph pbx-font-normal">
|
|
125
|
-
{{
|
|
126
|
-
translate(
|
|
127
|
-
'A Page Builder designed for growth. Build your website pages with ready-made components that are fully customizable and always responsive, designed to fit every need. A powerful Page Builder for growing merchants, brands, and agencies.',
|
|
128
|
-
)
|
|
129
|
-
}}
|
|
130
|
-
</p>
|
|
131
|
-
</template>
|
|
132
|
-
<template #content>
|
|
133
|
-
<p class="pbx-myPrimaryParagraph pbx-font-normal">
|
|
134
|
-
{{
|
|
135
|
-
translate(
|
|
136
|
-
"Try the powerful Click & Drop Page Builder—designed for developers and creators who want full control without the hassle. Customize layouts, fonts, and colors. Edit content visually in real time. Add media, embed YouTube videos, or export everything as clean HTML. With responsive editing, local auto-save, Tailwind support, and even Unsplash integration, it's everything you need—wrapped in one seamless builder. Build Stunning Pages in Minutes.",
|
|
137
|
-
)
|
|
138
|
-
}}
|
|
139
|
-
</p>
|
|
140
|
-
</template>
|
|
141
|
-
</FullWidthElement>
|
|
142
81
|
</div>
|
|
143
82
|
</template>
|