@myissue/vue-website-page-builder 3.3.96 → 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.
@@ -984,7 +984,6 @@ export class PageBuilderService {
984
984
  await this.handleAutoSave()
985
985
  }
986
986
 
987
- private historyIndex: number = -1
988
987
  private getHistoryBaseKey(): string | null {
989
988
  return this.getLocalStorageItemName.value
990
989
  }
@@ -993,7 +992,8 @@ export class PageBuilderService {
993
992
  const baseKey = this.getHistoryBaseKey()
994
993
  if (baseKey) {
995
994
  const history = LocalStorageManager.getHistory(baseKey)
996
- this.historyIndex = history.length - 1
995
+ this.pageBuilderStateStore.setHistoryIndex(history.length - 1)
996
+ this.pageBuilderStateStore.setHistoryLength(history.length)
997
997
  }
998
998
  }
999
999
 
@@ -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
- this.clearHtmlSelection()
1048
+ if (!doNoClearHTML) {
1049
+ this.clearHtmlSelection()
1050
+ }
1049
1051
  this.startEditing()
1050
1052
  this.saveDomComponentsToLocalStorage()
1051
1053
  await delay(300)
@@ -1458,9 +1460,9 @@ export class PageBuilderService {
1458
1460
  if (!baseKey) return
1459
1461
 
1460
1462
  const history = LocalStorageManager.getHistory(baseKey)
1461
- if (history.length > 1 && this.historyIndex > 0) {
1462
- this.historyIndex--
1463
- const data = history[this.historyIndex]
1463
+ if (history.length > 1 && this.pageBuilderStateStore.getHistoryIndex > 0) {
1464
+ this.pageBuilderStateStore.setHistoryIndex(this.pageBuilderStateStore.getHistoryIndex - 1)
1465
+ const data = history[this.pageBuilderStateStore.getHistoryIndex]
1464
1466
  const htmlString = this.renderComponentsToHtml(data.components)
1465
1467
  await this.mountComponentsToDOM(htmlString)
1466
1468
  }
@@ -1474,9 +1476,9 @@ export class PageBuilderService {
1474
1476
  if (!baseKey) return
1475
1477
 
1476
1478
  const history = LocalStorageManager.getHistory(baseKey)
1477
- if (history.length > 0 && this.historyIndex < history.length - 1) {
1478
- this.historyIndex++
1479
- const data = history[this.historyIndex]
1479
+ if (history.length > 0 && this.pageBuilderStateStore.getHistoryIndex < history.length - 1) {
1480
+ this.pageBuilderStateStore.setHistoryIndex(this.pageBuilderStateStore.getHistoryIndex + 1)
1481
+ const data = history[this.pageBuilderStateStore.getHistoryIndex]
1480
1482
  const htmlString = this.renderComponentsToHtml(data.components)
1481
1483
  await this.mountComponentsToDOM(htmlString)
1482
1484
  }
@@ -1632,7 +1634,7 @@ export class PageBuilderService {
1632
1634
  * Reorders the currently selected component up or down in the component list.
1633
1635
  * @param {number} direction - The direction to move the component (-1 for up, 1 for down).
1634
1636
  */
1635
- public reorderComponent(direction: number): void {
1637
+ public async reorderComponent(direction: number): Promise<void> {
1636
1638
  if (!this.getComponents.value || !this.getComponent.value) return
1637
1639
 
1638
1640
  if (this.getComponents.value.length <= 1) return
@@ -1660,6 +1662,74 @@ export class PageBuilderService {
1660
1662
  // Move the component to the new position in the array.
1661
1663
  this.getComponents.value.splice(currentIndex, 1)
1662
1664
  this.getComponents.value.splice(newIndex, 0, componentToMove)
1665
+
1666
+ // Wait for the DOM to update after reordering
1667
+ await nextTick()
1668
+
1669
+ // Scroll to the moved component
1670
+ const pageBuilderWrapper = document.querySelector(
1671
+ '#page-builder-wrapper',
1672
+ ) as HTMLElement | null
1673
+ const movedComponentElement = pageBuilderWrapper?.querySelector(
1674
+ `section[data-componentid="${componentToMove.id}"]`,
1675
+ ) as HTMLElement
1676
+
1677
+ if (movedComponentElement) {
1678
+ // Apply highlight to the moved element
1679
+ movedComponentElement.classList.add('pbx-reorder-highlight')
1680
+
1681
+ // Highlight its new neighbors (if they exist)
1682
+ const prevSibling = movedComponentElement.previousElementSibling as HTMLElement
1683
+ const nextSibling = movedComponentElement.nextElementSibling as HTMLElement
1684
+
1685
+ if (prevSibling && prevSibling.tagName === 'SECTION') {
1686
+ prevSibling.classList.add('pbx-sibling-highlight')
1687
+ }
1688
+ if (nextSibling && nextSibling.tagName === 'SECTION') {
1689
+ nextSibling.classList.add('pbx-sibling-highlight')
1690
+ }
1691
+
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
+ }
1708
+ }
1709
+ }
1710
+
1711
+ /**
1712
+ * Checks if the currently selected component can be moved up.
1713
+ * @returns {boolean} True if the component can be moved up, false otherwise.
1714
+ */
1715
+ public canMoveUp(): boolean {
1716
+ if (!this.getComponents.value || !this.getComponent.value) return false
1717
+ const currentIndex = this.getComponents.value.findIndex(
1718
+ (component) => component.id === this.getComponent.value?.id,
1719
+ )
1720
+ return currentIndex > 0
1721
+ }
1722
+
1723
+ /**
1724
+ * Checks if the currently selected component can be moved down.
1725
+ * @returns {boolean} True if the component can be moved down, false otherwise.
1726
+ */
1727
+ public canMoveDown(): boolean {
1728
+ if (!this.getComponents.value || !this.getComponent.value) return false
1729
+ const currentIndex = this.getComponents.value.findIndex(
1730
+ (component) => component.id === this.getComponent.value?.id,
1731
+ )
1732
+ return currentIndex < this.getComponents.value.length - 1
1663
1733
  }
1664
1734
 
1665
1735
  /**
@@ -1857,6 +1927,9 @@ export class PageBuilderService {
1857
1927
  pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
1858
1928
  const sanitizedSection = this.cloneAndRemoveSelectionAttributes(section as HTMLElement)
1859
1929
 
1930
+ // Remove the data-componentid attribute
1931
+ sanitizedSection.removeAttribute('data-componentid')
1932
+
1860
1933
  componentsToSave.push({
1861
1934
  html_code: sanitizedSection.outerHTML,
1862
1935
  title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
@@ -1875,7 +1948,29 @@ export class PageBuilderService {
1875
1948
  }
1876
1949
 
1877
1950
  const baseKey = this.getHistoryBaseKey()
1951
+
1878
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
+
1879
1974
  localStorage.setItem(baseKey, JSON.stringify(dataToSave))
1880
1975
  let history = LocalStorageManager.getHistory(baseKey)
1881
1976
 
@@ -1890,15 +1985,16 @@ export class PageBuilderService {
1890
1985
  }
1891
1986
  }
1892
1987
 
1893
- if (this.historyIndex < history.length - 1) {
1894
- history = history.slice(0, this.historyIndex + 1)
1988
+ if (this.pageBuilderStateStore.getHistoryIndex < history.length - 1) {
1989
+ history = history.slice(0, this.pageBuilderStateStore.getHistoryIndex + 1)
1895
1990
  }
1896
1991
  history.push(dataToSave)
1897
1992
  if (history.length > 10) {
1898
1993
  history = history.slice(history.length - 10)
1899
1994
  }
1900
1995
  localStorage.setItem(baseKey + '-history', JSON.stringify(history))
1901
- this.historyIndex = history.length - 1
1996
+ this.pageBuilderStateStore.setHistoryIndex(history.length - 1)
1997
+ this.pageBuilderStateStore.setHistoryLength(history.length)
1902
1998
  }
1903
1999
  }
1904
2000
  /**
@@ -2524,6 +2620,134 @@ export class PageBuilderService {
2524
2620
  }
2525
2621
  }
2526
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
+
2527
2751
  /**
2528
2752
  * Mounts builder components to the DOM from an HTML string.
2529
2753
  *
@@ -2542,13 +2766,11 @@ export class PageBuilderService {
2542
2766
  htmlString: string,
2543
2767
  usePassedPageSettings?: boolean,
2544
2768
  ): Promise<void> {
2769
+ // Trim HTML string
2545
2770
  const trimmedData = htmlString.trim()
2546
2771
 
2547
- // Return error since JSON data has been passed to mount HTML to DOM
2548
- if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
2549
- console.error('Error: JSON data passed to mountComponentsToDOM for the Page Builder Package.')
2550
- return
2551
- }
2772
+ const validationError = this.validateMountingHTML(trimmedData, { logError: true })
2773
+ if (validationError) return
2552
2774
 
2553
2775
  // HTML string
2554
2776
  try {
@@ -2787,57 +3009,6 @@ export class PageBuilderService {
2787
3009
  }
2788
3010
  }
2789
3011
 
2790
- /**
2791
- * Applies modified components by mounting them to the DOM and attaching listeners.
2792
- * @param htmlString - The HTML string to apply
2793
- * @returns {Promise<string | null>} - Returns error message if failed, otherwise null
2794
- */
2795
- public async applyModifiedHTML(htmlString: string): Promise<string | null> {
2796
- if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
2797
- return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
2798
- }
2799
-
2800
- const tempDiv = document.createElement('div')
2801
- tempDiv.innerHTML = htmlString.trim()
2802
-
2803
- const parsedElement = tempDiv.firstElementChild as HTMLElement | null
2804
-
2805
- if (!parsedElement) {
2806
- return 'Could not parse element from HTML string.'
2807
- }
2808
-
2809
- // Replace the actual DOM element
2810
- const oldElement = this.pageBuilderStateStore.getElement
2811
-
2812
- if (oldElement && oldElement.parentElement) {
2813
- oldElement.replaceWith(parsedElement)
2814
-
2815
- // Update the element in the store (now referencing the new one)
2816
- this.pageBuilderStateStore.setElement(parsedElement)
2817
- }
2818
-
2819
- await this.addListenersToEditableElements()
2820
- await nextTick()
2821
- return null
2822
- }
2823
-
2824
- /**
2825
- * Applies modified components by mounting them to the DOM and attaching listeners.
2826
- * @param htmlString - The HTML string to apply
2827
- * @returns {Promise<string | null>} - Returns error message if failed, otherwise null
2828
- */
2829
- public async applyModifiedComponents(htmlString: string): Promise<string | null> {
2830
- if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
2831
- return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
2832
- }
2833
-
2834
- await this.mountComponentsToDOM(htmlString)
2835
-
2836
- await this.addListenersToEditableElements()
2837
- await nextTick()
2838
- return null
2839
- }
2840
-
2841
3012
  /**
2842
3013
  * Initializes the styles for the currently selected element.
2843
3014
  */
@@ -65,6 +65,8 @@ interface PageBuilderState {
65
65
  isResumeEditing: boolean
66
66
  isRestoring: boolean
67
67
  currentLanguage: string | null
68
+ historyIndex: number
69
+ historyLength: number
68
70
  }
69
71
 
70
72
  export const usePageBuilderStateStore = defineStore('pageBuilderState', {
@@ -125,6 +127,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
125
127
  isResumeEditing: false,
126
128
  isRestoring: false,
127
129
  currentLanguage: null,
130
+ historyIndex: -1,
131
+ historyLength: 0,
128
132
  }),
129
133
  getters: {
130
134
  // Core Page Builder Getters
@@ -273,6 +277,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
273
277
  getIsLoadingResumeEditing: (state: PageBuilderState): boolean => state.isResumeEditing,
274
278
  getIsRestoring: (state: PageBuilderState): boolean => state.isRestoring,
275
279
  getCurrentLanguage: (state: PageBuilderState): string | null => state.currentLanguage,
280
+ getHistoryIndex: (state: PageBuilderState): number => state.historyIndex,
281
+ getHistoryLength: (state: PageBuilderState): number => state.historyLength,
276
282
  },
277
283
  actions: {
278
284
  setComponentArrayAddMethod(payload: string | null): void {
@@ -473,5 +479,11 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
473
479
  setCurrentLanguage(payload: string): void {
474
480
  this.currentLanguage = payload
475
481
  },
482
+ setHistoryIndex(payload: number): void {
483
+ this.historyIndex = payload
484
+ },
485
+ setHistoryLength(payload: number): void {
486
+ this.historyLength = payload
487
+ },
476
488
  },
477
489
  })
@@ -147,7 +147,7 @@ const getSvgPreview = (title: string) => {
147
147
  v-for="category in categories"
148
148
  :key="category"
149
149
  @click="selectedCategory = category"
150
- class="pbx-mySecondaryButton pbx-px-2 pbx-text-xs"
150
+ class="pbx-mySecondaryButton pbx-text-xs pbx-px-4"
151
151
  :class="{ active: selectedCategory === category }"
152
152
  >
153
153
  {{ translate(category) }}
@@ -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 { onMounted, computed, watch } from 'vue'
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-componentid=\"ba0e9774-3779-467c-9c9f-5c95dd47fa6d\" 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>",
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-componentid=\"d9fe6bdb-60df-45e4-bed5-1a6f8edf28e5\" 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>",
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-componentid=\"0bb012a0-631a-497f-9b7f-832313b64a2b\" 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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjh8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDgzMXww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMDR8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDc5MXww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyNnx8bW9kZWx8ZW58MHx8fHwxNzQ5ODMwNzM1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080\" alt=\"provider\" data-image=\"618a74a7-5d41-4dce-937c-130dd7490569\"></div></div> </div></div>\n</section>",
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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjh8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDgzMXww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMDR8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDc5MXww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyNnx8bW9kZWx8ZW58MHx8fHwxNzQ5ODMwNzM1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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-componentid=\"cd7e27ac-b152-4714-a5f7-5ad660f183bf\" 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>",
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-componentid=\"b1e75d09-0e72-4c61-a207-a97277cbbfed\" 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>",
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-componentid=\"d3b5a3e4-29a3-4b03-88b6-1f77d319af74\" 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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxraW5mb2xrfGVufDB8fHx8MTc0OTgzMTAzM3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxtYWdhemluZSUyMGZhc2hpb258ZW58MHx8fHwxNzQ5ODMxNTEwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080\" alt=\"provider\" data-image=\"41655496-4742-4cc6-bc3c-abe7c2b241fb\"> </div> </div> </div> </div>\n</section>",
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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxraW5mb2xrfGVufDB8fHx8MTc0OTgzMTAzM3ww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxtYWdhemluZSUyMGZhc2hpb258ZW58MHx8fHwxNzQ5ODMxNTEwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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-componentid=\"f164929b-4460-4b17-9933-119b47e8bbef\" 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>",
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-componentid=\"fa721207-2444-4892-9de3-5260d576a34b\" 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>",
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-componentid=\"33a26684-eb95-43c9-adb4-d7bce0ca60f7\" 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>",
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-componentid=\"de2208e1-5b65-4302-8ffb-b9beb7d192d7\" title=\"Header H3\" 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>",
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-componentid=\"e9a5c794-5972-473d-8181-af4345cbaabe\" title=\"Text\" 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>",
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": "<section data-componentid=\"7bcda060-8ed5-482f-bcf4-aa6bd7fdb193\" title=\"Six Square Images Grid\" 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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxOXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1MDR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyfHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1MXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1NDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1fHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw0Nnx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1Mjd8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjV8fGpld2VybHl8ZW58MHx8fHwxNzUxMDIxNTc4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080\" alt=\"image\">\n</div>\n\n</div>\n</div>\n</div>\n</section>",
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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxOXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1MDR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyfHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1MXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1NDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1fHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw0Nnx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1Mjd8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjV8fGpld2VybHl8ZW58MHx8fHwxNzUxMDIxNTc4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;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
  }