@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myissue/vue-website-page-builder",
3
- "version": "3.4.10",
3
+ "version": "3.4.12",
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",
package/src/App.vue CHANGED
@@ -22,7 +22,6 @@ onMounted(async () => {
22
22
 
23
23
  <template>
24
24
  <div>
25
- <Navbar></Navbar>
26
25
  <PageBuilderTest></PageBuilderTest>
27
26
  <Footer></Footer>
28
27
  </div>
@@ -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-bg-red-100 pbx-py-10 lg:pbx-px-12 pbx-px-4"
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
- <div>
10
- <p class="pbx-myPrimaryParagraph">
11
- <a
12
- href="https://www.npmjs.com/package/@myissue/vue-website-page-builder"
13
- target="_blank"
14
- class="pbx-myPrimaryLink pbx-text-myPrimaryDarkGrayColor"
15
- >
16
- Install via npm
17
- </a>
18
- </p>
19
- <p class="pbx-myPrimaryParagraph pbx-mt-3">
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
- </div>
29
- <p class="pbx-myPrimaryParagraph pbx-mt-3">
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
- if (props.globalPage) {
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 handleHTMLSettings = function () {
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="handleHTMLSettings"
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 1rem;
519
+ padding: 1rem 0 0 1.4rem;
524
520
  margin-left: 1em;
525
- line-height: 1.2;
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
- private syncDomToStoreOnly() {
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
- <!-- Helper Components Section -->
108
- <div class="pbx-mb-8">
109
- <h3 class="pbx-myQuaternaryHeader pbx-mb-4">{{ translate('Helper Components') }}</h3>
110
- <div
111
- 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"
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
- v-for="helper in componentHelpers"
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
- class="pbx-max-h-72 pbx-cursor-pointer pbx-object-contain pbx-bg-white pbx-mx-auto"
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 v-if="false" class="pbx-mr-2" v-html="helper.icon"></div>
123
- <h4 class="pbx-myPrimaryParagraph pbx-text-base pbx-font-medium">
124
- {{ translate(helper.title) }}
125
- </h4>
126
- </div>
127
- <div class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-normal pbx-pt-2">
128
- {{ translate('Click to add') }} {{ helper.title.toLowerCase() }}
129
- {{ translate('component') }}
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
- </div>
199
+ </template>
200
+ <!-- theme is selected end -->
134
201
 
135
- <!-- Regular Components Section -->
136
- <div class="pbx-px-2" v-if="customMediaComponent">
137
- <h3 class="pbx-myQuaternaryHeader pbx-mb-4">{{ translate('Layout Components') }}</h3>
138
- <div class="pbx-mb-4 pbx-flex pbx-jusitify-left pbx-items-center pbx-gap-2">
139
- <button
140
- v-for="category in categories"
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
- {{ translate(category) }}
151
- </button>
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
- <div
154
- class="pbx-grid pbx-grid-cols-1 sm:pbx-grid-cols-2 md:pbx-grid-cols-3 pbx-gap-4 pbx-pb-4"
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
- v-for="comp in filteredComponents"
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
- 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"
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-max-h-72 pbx-cursor-pointer pbx-bg-white pbx-mx-auto pbx-flex pbx-items-center pbx-justify-center"
168
- v-html="comp.cover_image"
169
- ></div>
170
- </div>
171
- <div class="pbx-p-3">
172
- <h4 class="pbx-myPrimaryParagraph pbx-text-sm pbx-font-normal">
173
- {{ translate(comp.title) }}
174
- </h4>
175
- <div class="pbx-myPrimaryParagraph pbx-text-xs pbx-font-normal pbx-pt-2">
176
- {{ translate('Click to add component') }}
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
- </div>
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="pbx-myPrimaryWidthScreenModule pbx-bg-red-50 lg:pbx-block">
74
- <div class="pbx-myPrimaryContentSection">
75
- <h2 class="pbx-mySecondaryHeader">
76
- {{
77
- translate(
78
- 'Bring your vision to life and create impressive pages using a click & drop Page Builder',
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>