@myissue/vue-website-page-builder 3.3.97 → 3.3.98
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 +1 -1
- package/dist/style.css +1 -1
- package/dist/vue-website-page-builder.js +3582 -3543
- package/dist/vue-website-page-builder.umd.cjs +29 -29
- package/package.json +4 -4
- package/src/Components/Homepage/Footer.vue +1 -1
- package/src/css/style.css +2 -6
- package/src/services/PageBuilderService.ts +180 -73
- package/src/tests/PageBuilderTest.vue +1 -1
- package/src/tests/componentsArray.test.json +12 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myissue/vue-website-page-builder",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.98",
|
|
4
4
|
"description": "Vue 3 page builder component with drag & drop functionality.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/vue-website-page-builder.umd.cjs",
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
"license": "MIT",
|
|
53
53
|
"repository": {
|
|
54
54
|
"type": "git",
|
|
55
|
-
"url": "
|
|
55
|
+
"url": "git+ssh://git@github.com/myissue-org/vue-website-page-builder.git"
|
|
56
56
|
},
|
|
57
57
|
"bugs": {
|
|
58
|
-
"url": "https://github.com/
|
|
58
|
+
"url": "https://github.com/myissue-org/vue-website-page-builder/issues"
|
|
59
59
|
},
|
|
60
|
-
"homepage": "https://mybuilder.dev",
|
|
60
|
+
"homepage": "https://www.mybuilder.dev",
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=18.0.0",
|
|
63
63
|
"npm": ">=8.0.0"
|
|
@@ -18,7 +18,7 @@ const version = __APP_VERSION__
|
|
|
18
18
|
</p>
|
|
19
19
|
<p class="pbx-myPrimaryParagraph pbx-mt-3">
|
|
20
20
|
<a
|
|
21
|
-
href="https://github.com/
|
|
21
|
+
href="https://github.com/myissue-org/vue-website-page-builder"
|
|
22
22
|
target="_blank"
|
|
23
23
|
class="pbx-myPrimaryLink pbx-text-myPrimaryDarkGrayColor"
|
|
24
24
|
>
|
package/src/css/style.css
CHANGED
|
@@ -485,22 +485,18 @@
|
|
|
485
485
|
|
|
486
486
|
@keyframes pbx-reorder-flash {
|
|
487
487
|
0% {
|
|
488
|
-
box-shadow: 0 0 0 0px rgba(66, 153, 225, 0.7);
|
|
489
488
|
transform: scale(1);
|
|
490
489
|
opacity: 1;
|
|
491
490
|
}
|
|
492
491
|
50% {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
opacity: 0.8;
|
|
492
|
+
transform: scale(0.8);
|
|
493
|
+
opacity: 0.6;
|
|
496
494
|
}
|
|
497
495
|
100% {
|
|
498
|
-
box-shadow: 0 0 0 0px rgba(66, 153, 225, 0);
|
|
499
496
|
transform: scale(1);
|
|
500
497
|
opacity: 1;
|
|
501
498
|
}
|
|
502
499
|
}
|
|
503
500
|
|
|
504
501
|
.pbx-sibling-highlight {
|
|
505
|
-
border: 2px dashed #4299e1; /* Blue dashed border */
|
|
506
502
|
}
|
|
@@ -1043,9 +1043,11 @@ export class PageBuilderService {
|
|
|
1043
1043
|
/**
|
|
1044
1044
|
* Manually saves the current page builder content to local storage.
|
|
1045
1045
|
*/
|
|
1046
|
-
public handleManualSave = async () => {
|
|
1046
|
+
public handleManualSave = async (doNoClearHTML?: boolean) => {
|
|
1047
1047
|
this.pageBuilderStateStore.setIsSaving(true)
|
|
1048
|
-
|
|
1048
|
+
if (!doNoClearHTML) {
|
|
1049
|
+
this.clearHtmlSelection()
|
|
1050
|
+
}
|
|
1049
1051
|
this.startEditing()
|
|
1050
1052
|
this.saveDomComponentsToLocalStorage()
|
|
1051
1053
|
await delay(300)
|
|
@@ -1665,10 +1667,12 @@ export class PageBuilderService {
|
|
|
1665
1667
|
await nextTick()
|
|
1666
1668
|
|
|
1667
1669
|
// Scroll to the moved component
|
|
1668
|
-
const pageBuilderWrapper = document.querySelector(
|
|
1670
|
+
const pageBuilderWrapper = document.querySelector(
|
|
1671
|
+
'#page-builder-wrapper',
|
|
1672
|
+
) as HTMLElement | null
|
|
1669
1673
|
const movedComponentElement = pageBuilderWrapper?.querySelector(
|
|
1670
1674
|
`section[data-componentid="${componentToMove.id}"]`,
|
|
1671
|
-
)
|
|
1675
|
+
) as HTMLElement
|
|
1672
1676
|
|
|
1673
1677
|
if (movedComponentElement) {
|
|
1674
1678
|
// Apply highlight to the moved element
|
|
@@ -1685,19 +1689,22 @@ export class PageBuilderService {
|
|
|
1685
1689
|
nextSibling.classList.add('pbx-sibling-highlight')
|
|
1686
1690
|
}
|
|
1687
1691
|
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1692
|
+
if (pageBuilderWrapper) {
|
|
1693
|
+
// Scroll to the moved component
|
|
1694
|
+
const topPos = movedComponentElement.offsetTop - pageBuilderWrapper.offsetTop
|
|
1695
|
+
pageBuilderWrapper.scrollTop = topPos - pageBuilderWrapper.clientHeight / 2
|
|
1696
|
+
|
|
1697
|
+
// Remove highlights after a delay
|
|
1698
|
+
setTimeout(() => {
|
|
1699
|
+
movedComponentElement.classList.remove('pbx-reorder-highlight')
|
|
1700
|
+
if (prevSibling && prevSibling.tagName === 'SECTION') {
|
|
1701
|
+
prevSibling.classList.remove('pbx-sibling-highlight')
|
|
1702
|
+
}
|
|
1703
|
+
if (nextSibling && nextSibling.tagName === 'SECTION') {
|
|
1704
|
+
nextSibling.classList.remove('pbx-sibling-highlight')
|
|
1705
|
+
}
|
|
1706
|
+
}, 200)
|
|
1707
|
+
}
|
|
1701
1708
|
}
|
|
1702
1709
|
}
|
|
1703
1710
|
|
|
@@ -1920,6 +1927,9 @@ export class PageBuilderService {
|
|
|
1920
1927
|
pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
|
|
1921
1928
|
const sanitizedSection = this.cloneAndRemoveSelectionAttributes(section as HTMLElement)
|
|
1922
1929
|
|
|
1930
|
+
// Remove the data-componentid attribute
|
|
1931
|
+
sanitizedSection.removeAttribute('data-componentid')
|
|
1932
|
+
|
|
1923
1933
|
componentsToSave.push({
|
|
1924
1934
|
html_code: sanitizedSection.outerHTML,
|
|
1925
1935
|
title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
|
|
@@ -1938,7 +1948,29 @@ export class PageBuilderService {
|
|
|
1938
1948
|
}
|
|
1939
1949
|
|
|
1940
1950
|
const baseKey = this.getHistoryBaseKey()
|
|
1951
|
+
|
|
1941
1952
|
if (baseKey) {
|
|
1953
|
+
const currentDataRaw = localStorage.getItem(baseKey)
|
|
1954
|
+
if (currentDataRaw) {
|
|
1955
|
+
const currentData = JSON.parse(currentDataRaw)
|
|
1956
|
+
|
|
1957
|
+
// Compare components
|
|
1958
|
+
const currentComponents = currentData.components || []
|
|
1959
|
+
const newComponents = dataToSave.components || []
|
|
1960
|
+
|
|
1961
|
+
const hasChanges = newComponents.some((newComponent, index) => {
|
|
1962
|
+
const currentComponent = currentComponents[index]
|
|
1963
|
+
return (
|
|
1964
|
+
!currentComponent || // New component added
|
|
1965
|
+
currentComponent.html_code !== newComponent.html_code // Component HTML changed
|
|
1966
|
+
)
|
|
1967
|
+
})
|
|
1968
|
+
|
|
1969
|
+
if (!hasChanges) {
|
|
1970
|
+
return
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1942
1974
|
localStorage.setItem(baseKey, JSON.stringify(dataToSave))
|
|
1943
1975
|
let history = LocalStorageManager.getHistory(baseKey)
|
|
1944
1976
|
|
|
@@ -2588,6 +2620,134 @@ export class PageBuilderService {
|
|
|
2588
2620
|
}
|
|
2589
2621
|
}
|
|
2590
2622
|
|
|
2623
|
+
/**
|
|
2624
|
+
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2625
|
+
* @param htmlString - The HTML string to apply
|
|
2626
|
+
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2627
|
+
*/
|
|
2628
|
+
public async applyModifiedHTML(htmlString: string): Promise<string | null> {
|
|
2629
|
+
if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
|
|
2630
|
+
return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
// Check if the htmlString contains any <section> tags
|
|
2634
|
+
if (/<section[\s>]/i.test(htmlString)) {
|
|
2635
|
+
return 'Error: The <section> tag cannot be used as it is already included inside this component.'
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
const tempDiv = document.createElement('div')
|
|
2639
|
+
tempDiv.innerHTML = htmlString.trim()
|
|
2640
|
+
|
|
2641
|
+
const parsedElement = tempDiv.firstElementChild as HTMLElement | null
|
|
2642
|
+
|
|
2643
|
+
if (!parsedElement) {
|
|
2644
|
+
return 'Could not parse element from HTML string.'
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
// Replace the actual DOM element
|
|
2648
|
+
const oldElement = this.pageBuilderStateStore.getElement
|
|
2649
|
+
|
|
2650
|
+
if (oldElement && oldElement.parentElement) {
|
|
2651
|
+
oldElement.replaceWith(parsedElement)
|
|
2652
|
+
|
|
2653
|
+
// Update the element in the store (now referencing the new one)
|
|
2654
|
+
this.pageBuilderStateStore.setElement(parsedElement)
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
await this.addListenersToEditableElements()
|
|
2658
|
+
await nextTick()
|
|
2659
|
+
return null
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
private validateMountingHTML(
|
|
2663
|
+
htmlString: string,
|
|
2664
|
+
options?: { logError?: boolean },
|
|
2665
|
+
): string | null {
|
|
2666
|
+
// Trim HTML string
|
|
2667
|
+
const trimmedData = htmlString.trim()
|
|
2668
|
+
const openingSectionMatches = htmlString.match(/<section\b[^>]*>/gi) || []
|
|
2669
|
+
const closingSectionMatches = htmlString.match(/<\/section>/gi) || []
|
|
2670
|
+
|
|
2671
|
+
if (!htmlString || htmlString.trim().length === 0) {
|
|
2672
|
+
const error = 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2673
|
+
if (options && options.logError) {
|
|
2674
|
+
console.error(error)
|
|
2675
|
+
// Behavior
|
|
2676
|
+
return error
|
|
2677
|
+
}
|
|
2678
|
+
// default behavior
|
|
2679
|
+
return error
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
if (openingSectionMatches.length !== closingSectionMatches.length) {
|
|
2683
|
+
const error =
|
|
2684
|
+
'Uneven <section> tags detected in the provided HTML. Each component must be wrapped in its own properly paired <section>...</section>. ' +
|
|
2685
|
+
'Ensure that all <section> tags have a matching closing </section> tag.'
|
|
2686
|
+
|
|
2687
|
+
if (options && options.logError) {
|
|
2688
|
+
console.error(error)
|
|
2689
|
+
return error
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
return error
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
const tempDiv = document.createElement('div')
|
|
2696
|
+
tempDiv.innerHTML = trimmedData
|
|
2697
|
+
const nestedSection = tempDiv.querySelector('section section')
|
|
2698
|
+
if (nestedSection) {
|
|
2699
|
+
const error =
|
|
2700
|
+
'Nested <section> tags are not allowed. Please ensure that no <section> is placed inside another <section>.'
|
|
2701
|
+
if (options && options.logError) {
|
|
2702
|
+
console.error(error)
|
|
2703
|
+
return error
|
|
2704
|
+
}
|
|
2705
|
+
return error
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// Return error since JSON data has been passed to mount HTML to DOM
|
|
2709
|
+
if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
|
|
2710
|
+
const error =
|
|
2711
|
+
'Brackets [] or curly braces {} are not valid HTML. They are used for data formats like JSON.'
|
|
2712
|
+
if (options && options.logError) {
|
|
2713
|
+
console.error(error)
|
|
2714
|
+
return error
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
return error
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
return null
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
/**
|
|
2724
|
+
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2725
|
+
* @param htmlString - The HTML string to apply
|
|
2726
|
+
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2727
|
+
*/
|
|
2728
|
+
public async applyModifiedComponents(htmlString: string): Promise<string | null> {
|
|
2729
|
+
// Trim HTML string
|
|
2730
|
+
const trimmedData = htmlString.trim()
|
|
2731
|
+
|
|
2732
|
+
const openingSectionMatches = htmlString.match(/<section\b[^>]*>/gi) || []
|
|
2733
|
+
|
|
2734
|
+
if (openingSectionMatches.length === 0) {
|
|
2735
|
+
const error = 'No <section> tags found. Each component must be wrapped in a <section> tag.'
|
|
2736
|
+
if (error) {
|
|
2737
|
+
return error
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
const validationError = this.validateMountingHTML(trimmedData)
|
|
2742
|
+
if (validationError) return validationError
|
|
2743
|
+
|
|
2744
|
+
// also fixed to use `trimmedData`
|
|
2745
|
+
await this.mountComponentsToDOM(trimmedData)
|
|
2746
|
+
await this.addListenersToEditableElements()
|
|
2747
|
+
await nextTick()
|
|
2748
|
+
return null
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2591
2751
|
/**
|
|
2592
2752
|
* Mounts builder components to the DOM from an HTML string.
|
|
2593
2753
|
*
|
|
@@ -2606,13 +2766,11 @@ export class PageBuilderService {
|
|
|
2606
2766
|
htmlString: string,
|
|
2607
2767
|
usePassedPageSettings?: boolean,
|
|
2608
2768
|
): Promise<void> {
|
|
2769
|
+
// Trim HTML string
|
|
2609
2770
|
const trimmedData = htmlString.trim()
|
|
2610
2771
|
|
|
2611
|
-
|
|
2612
|
-
if (
|
|
2613
|
-
console.error('Error: JSON data passed to mountComponentsToDOM for the Page Builder Package.')
|
|
2614
|
-
return
|
|
2615
|
-
}
|
|
2772
|
+
const validationError = this.validateMountingHTML(trimmedData, { logError: true })
|
|
2773
|
+
if (validationError) return
|
|
2616
2774
|
|
|
2617
2775
|
// HTML string
|
|
2618
2776
|
try {
|
|
@@ -2851,57 +3009,6 @@ export class PageBuilderService {
|
|
|
2851
3009
|
}
|
|
2852
3010
|
}
|
|
2853
3011
|
|
|
2854
|
-
/**
|
|
2855
|
-
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2856
|
-
* @param htmlString - The HTML string to apply
|
|
2857
|
-
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2858
|
-
*/
|
|
2859
|
-
public async applyModifiedHTML(htmlString: string): Promise<string | null> {
|
|
2860
|
-
if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
|
|
2861
|
-
return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2862
|
-
}
|
|
2863
|
-
|
|
2864
|
-
const tempDiv = document.createElement('div')
|
|
2865
|
-
tempDiv.innerHTML = htmlString.trim()
|
|
2866
|
-
|
|
2867
|
-
const parsedElement = tempDiv.firstElementChild as HTMLElement | null
|
|
2868
|
-
|
|
2869
|
-
if (!parsedElement) {
|
|
2870
|
-
return 'Could not parse element from HTML string.'
|
|
2871
|
-
}
|
|
2872
|
-
|
|
2873
|
-
// Replace the actual DOM element
|
|
2874
|
-
const oldElement = this.pageBuilderStateStore.getElement
|
|
2875
|
-
|
|
2876
|
-
if (oldElement && oldElement.parentElement) {
|
|
2877
|
-
oldElement.replaceWith(parsedElement)
|
|
2878
|
-
|
|
2879
|
-
// Update the element in the store (now referencing the new one)
|
|
2880
|
-
this.pageBuilderStateStore.setElement(parsedElement)
|
|
2881
|
-
}
|
|
2882
|
-
|
|
2883
|
-
await this.addListenersToEditableElements()
|
|
2884
|
-
await nextTick()
|
|
2885
|
-
return null
|
|
2886
|
-
}
|
|
2887
|
-
|
|
2888
|
-
/**
|
|
2889
|
-
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2890
|
-
* @param htmlString - The HTML string to apply
|
|
2891
|
-
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2892
|
-
*/
|
|
2893
|
-
public async applyModifiedComponents(htmlString: string): Promise<string | null> {
|
|
2894
|
-
if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
|
|
2895
|
-
return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2896
|
-
}
|
|
2897
|
-
|
|
2898
|
-
await this.mountComponentsToDOM(htmlString)
|
|
2899
|
-
|
|
2900
|
-
await this.addListenersToEditableElements()
|
|
2901
|
-
await nextTick()
|
|
2902
|
-
return null
|
|
2903
|
-
}
|
|
2904
|
-
|
|
2905
3012
|
/**
|
|
2906
3013
|
* Initializes the styles for the currently selected element.
|
|
2907
3014
|
*/
|
|
@@ -3,7 +3,7 @@ import FullWidthElement from '../Components/Layouts/FullWidthElement.vue'
|
|
|
3
3
|
import PageBuilder from '../PageBuilder/PageBuilder.vue'
|
|
4
4
|
import DemoMediaLibraryComponentTest from '../tests/TestComponents/DemoMediaLibraryComponentTest.vue'
|
|
5
5
|
import DemoBuilderComponentsTest from '../tests/TestComponents/DemoBuilderComponentsTest.vue'
|
|
6
|
-
import {
|
|
6
|
+
import { computed, watch } from 'vue'
|
|
7
7
|
import componentsArray from '../tests/componentsArray.test.json'
|
|
8
8
|
import { getPageBuilder } from '../composables/builderInstance'
|
|
9
9
|
import { useTranslations } from '../composables/useTranslations'
|
|
@@ -1,61 +1,61 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
|
-
"html_code": "<section data-
|
|
3
|
+
"html_code": "<section data-component-title=\"Header H2\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-text-6xl lg:pbx-text-8xl pbx-font-medium\"><h2>{{ translate('Demo Content') }}</h2></div></div></div></section>",
|
|
4
4
|
"id": "ba0e9774-3779-467c-9c9f-5c95dd47fa6d",
|
|
5
5
|
"title": "Header H2"
|
|
6
6
|
},
|
|
7
7
|
{
|
|
8
|
-
"html_code": "<section data-
|
|
8
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div><p>{{ translate('Demo Description') }}</p></div>\n </div>\n </div>\n </section>",
|
|
9
9
|
"id": "d9fe6bdb-60df-45e4-bed5-1a6f8edf28e5",
|
|
10
10
|
"title": "Text"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
|
-
"html_code": "<section data-
|
|
13
|
+
"html_code": "<section data-component-title=\"Three Vertical Images\">\n<div class=\"pbx-w-full md:pbx-pt-12 md:pbx-pb-12 pbx-pt-4 pbx-pb-4 lg:pbx-px-4 pbx-px-2 pbx-bg-black\"><div class=\"pbx-mx-auto pbx-max-w-7xl pbx-m\"><div class=\"pbx-myPrimaryGap pbx-grid pbx-grid-cols-1 sm:pbx-grid-cols-3 lg:pbx-grid-cols-3\"> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] pbx-rounded-tl-full\" src=\"https://images.unsplash.com/photo-1632765866070-3fadf25d3d5b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjh8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDgzMXww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"b2fb2e61-c916-4195-9cd2-c1d25747b4f7\"> </div> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] pbx-rounded-full\" src=\"https://images.unsplash.com/photo-1542513217-0b0eedf7005d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMDR8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDc5MXww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"fdf36a14-f7ef-4025-942f-c87b20b18005\"> </div> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] pbx-rounded-br-full\" src=\"https://images.unsplash.com/photo-1574015974293-817f0ebebb74?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyNnx8bW9kZWx8ZW58MHx8fHwxNzQ5ODMwNzM1fDA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"618a74a7-5d41-4dce-937c-130dd7490569\"></div></div> </div></div>\n</section>",
|
|
14
14
|
"id": "0bb012a0-631a-497f-9b7f-832313b64a2b",
|
|
15
15
|
"title": "Three Vertical Images"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"html_code": "<section data-
|
|
18
|
+
"html_code": "<section data-component-title=\"Header H3\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-mt-6 pbx-font-medium pbx-text-2xl lg:pbx-text-4xl\"><h3>{{ translate('Demo Title') }}</h3></div></div></div></section>",
|
|
19
19
|
"id": "cd7e27ac-b152-4714-a5f7-5ad660f183bf",
|
|
20
20
|
"title": "Header H3"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"html_code": "<section data-
|
|
23
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div><p>{{ translate('Demo Description Two') }}</p></div>\n </div>\n </div>\n </section>",
|
|
24
24
|
"id": "b1e75d09-0e72-4c61-a207-a97277cbbfed",
|
|
25
25
|
"title": "Text"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"html_code": "<section data-
|
|
28
|
+
"html_code": "<section data-component-title=\"Two Vertical Images\">\n<div class=\"pbx-w-full md:pbx-pt-12 md:pbx-pb-12 pbx-pt-4 pbx-pb-4 lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-mx-auto pbx-max-w-7xl\"><div class=\"pbx-myPrimaryGap pbx-grid pbx-grid-cols-2 sm:pbx-grid-cols-2 lg:pbx-grid-cols-2\"> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] \" src=\"https://images.unsplash.com/photo-1592966719124-2ca2978ba325?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxraW5mb2xrfGVufDB8fHx8MTc0OTgzMTAzM3ww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"536340a5-c7e1-479d-a2ae-a85e6dacc2df\"> </div> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] \" src=\"https://images.unsplash.com/photo-1549298222-1c31e8915347?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxtYWdhemluZSUyMGZhc2hpb258ZW58MHx8fHwxNzQ5ODMxNTEwfDA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"41655496-4742-4cc6-bc3c-abe7c2b241fb\"> </div> </div> </div> </div>\n</section>",
|
|
29
29
|
"id": "d3b5a3e4-29a3-4b03-88b6-1f77d319af74",
|
|
30
30
|
"title": "Two Vertical Images"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
"html_code": "<section data-
|
|
33
|
+
"html_code": "<section data-component-title=\"Header H3\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-mt-6 pbx-font-medium pbx-text-2xl lg:pbx-text-4xl\"><h3>{{ translate('Demo Title Two') }}</h3></div></div></div></section>",
|
|
34
34
|
"id": "f164929b-4460-4b17-9933-119b47e8bbef",
|
|
35
35
|
"title": "Header H3"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
|
-
"html_code": "<section data-
|
|
38
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div class=\"\"><p>{{ translate('Demo Description Three') }}</p></div>\n </div>\n </div>\n </section>",
|
|
39
39
|
"id": "fa721207-2444-4892-9de3-5260d576a34b",
|
|
40
40
|
"title": "Text"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
|
-
"html_code": "<section data-
|
|
43
|
+
"html_code": "<section data-component-title=\"YouTube Video\">\n <div class=\"pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl pbx-w-full pbx-pt-6 pbx-pb-6\">\n <div id=\"youtube-video\" class=\"pbx-w-full pbx-aspect-video pbx-p-4\">\n\n <iframe frameborder=\"0\" allowfullscreen=\"\" class=\"pbx-w-full pbx-aspect-video\" src=\"https://www.youtube.com/embed/pJvwV1Fm0vU\" allow=\"accelerometer; autoplay; clipboard-write;\">\n </iframe>\n </div>\n </div>\n </div>\n </section>",
|
|
44
44
|
"id": "33a26684-eb95-43c9-adb4-d7bce0ca60f7",
|
|
45
45
|
"title": "YouTube Video"
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
|
-
"html_code": "<section data-
|
|
48
|
+
"html_code": "<section data-component-title=\"Header H3\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-text-2xl lg:pbx-text-4xl pbx-font-medium\"><h3>{{ translate('Demo Title Three') }}</h3></div></div></div></section>",
|
|
49
49
|
"id": "de2208e1-5b65-4302-8ffb-b9beb7d192d7",
|
|
50
50
|
"title": "Header H3"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
"html_code": "<section data-
|
|
53
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div><p>{{ translate('Demo Description Four') }}</p><p></p></div>\n </div>\n </div>\n </section>",
|
|
54
54
|
"id": "e9a5c794-5972-473d-8181-af4345cbaabe",
|
|
55
55
|
"title": "Text"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
"html_code": "<
|
|
58
|
+
"html_code": "<sectio data-component-title=\"Six Square Images Grid\">\n<div class=\"pbx-w-full md:pbx-pt-12 md:pbx-pb-12 pbx-pt-4 pbx-pb-4 lg:pbx-px-4 pbx-px-2 pbx-rounded-tr-full pbx-bg-yellow-100 pbx-rounded-bl-full\">\n<div class=\"pbx-mx-auto pbx-max-w-7xl\">\n<div class=\"pbx-grid pbx-grid-cols-2 md:pbx-grid-cols-3 pbx-myPrimaryGap\">\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-square \" src=\"https://images.unsplash.com/photo-1616837874254-8d5aaa63e273?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxOXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1MDR8MA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-square \" src=\"https://images.unsplash.com/photo-1608042314453-ae338d80c427?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyfHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-square \" src=\"https://images.unsplash.com/photo-1621939745912-aad97fd3a34d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1MXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1NDN8MA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-aspect-square pbx-object-bottom\" src=\"https://images.unsplash.com/photo-1617038220319-276d3cfab638?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1fHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-aspect-square pbx-object-bottom\" src=\"https://images.unsplash.com/photo-1594924571793-f6517415f594?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw0Nnx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1Mjd8MA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-aspect-square pbx-object-top\" src=\"https://images.unsplash.com/photo-1683099869102-bcf8791eb0e5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjV8fGpld2VybHl8ZW58MHx8fHwxNzUxMDIxNTc4fDA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n</div>\n</div>\n</div>\n</sectio>",
|
|
59
59
|
"id": "7bcda060-8ed5-482f-bcf4-aa6bd7fdb193",
|
|
60
60
|
"title": "Six Square Images Grid"
|
|
61
61
|
}
|