@myissue/vue-website-page-builder 3.3.65 → 3.3.67

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.
Files changed (36) hide show
  1. package/README.md +70 -4
  2. package/dist/vue-website-page-builder.js +14959 -12086
  3. package/dist/vue-website-page-builder.umd.cjs +78 -57
  4. package/package.json +2 -1
  5. package/src/Components/PageBuilder/EditorMenu/Editables/BackgroundColorEditor.vue +2 -2
  6. package/src/Components/PageBuilder/EditorMenu/Editables/BorderRadius.vue +19 -13
  7. package/src/Components/PageBuilder/EditorMenu/Editables/Borders.vue +9 -7
  8. package/src/Components/PageBuilder/EditorMenu/Editables/ClassEditor.vue +8 -7
  9. package/src/Components/PageBuilder/EditorMenu/Editables/ManageBackgroundOpacity.vue +7 -3
  10. package/src/Components/PageBuilder/EditorMenu/Editables/ManageOpacity.vue +5 -3
  11. package/src/Components/PageBuilder/EditorMenu/Editables/Margin.vue +9 -5
  12. package/src/Components/PageBuilder/EditorMenu/Editables/OpacityEditor.vue +1 -1
  13. package/src/Components/PageBuilder/EditorMenu/Editables/Padding.vue +9 -5
  14. package/src/Components/PageBuilder/EditorMenu/Editables/StyleEditor.vue +8 -7
  15. package/src/Components/PageBuilder/EditorMenu/Editables/Typography.vue +25 -9
  16. package/src/Components/PageBuilder/EditorMenu/RightSidebarEditor.vue +9 -12
  17. package/src/Components/PageBuilder/Settings/PageBuilderSettings.vue +3 -3
  18. package/src/Components/PageBuilder/ToolbarOption/ToolbarOption.vue +4 -4
  19. package/src/PageBuilder/PageBuilder.vue +83 -5
  20. package/src/composables/builderInstance.ts +3 -2
  21. package/src/i18n.ts +28 -0
  22. package/src/locales/ar.json +136 -0
  23. package/src/locales/de.json +136 -0
  24. package/src/locales/en.json +136 -0
  25. package/src/locales/es.json +136 -0
  26. package/src/locales/fr.json +136 -0
  27. package/src/locales/hi.json +136 -0
  28. package/src/locales/ja.json +136 -0
  29. package/src/locales/pt.json +136 -0
  30. package/src/locales/ru.json +136 -0
  31. package/src/locales/zh-Hans.json +136 -0
  32. package/src/main.ts +10 -5
  33. package/src/services/PageBuilderService.ts +150 -29
  34. package/src/tests/PageBuilderTest.vue +24 -54
  35. package/src/tests/pageBuilderService.test.ts +7 -1
  36. package/src/types/index.ts +7 -1
@@ -7,6 +7,7 @@ import type {
7
7
  StartBuilderResult,
8
8
  } from '../types'
9
9
  import type { usePageBuilderStateStore } from '../stores/page-builder-state'
10
+ // import { i18n } from '../i18n' // i18n is now async and must be passed in, not imported
10
11
 
11
12
  import tailwindFontSizes from '../utils/builder/tailwind-font-sizes'
12
13
  import tailwindColors from '../utils/builder/tailwaind-colors'
@@ -22,7 +23,36 @@ import { delay } from '../composables/delay'
22
23
  import { isEmptyObject } from '../helpers/isEmptyObject'
23
24
  import { extractCleanHTMLFromPageBuilder } from '../composables/extractCleanHTMLFromPageBuilder'
24
25
 
26
+ // Define available languages as a type and an array for easy iteration and type safety
27
+ export type AvailableLanguage =
28
+ | 'en'
29
+ | 'zh-Hans'
30
+ | 'fr'
31
+ | 'ja'
32
+ | 'ru'
33
+ | 'es'
34
+ | 'pt'
35
+ | 'de'
36
+ | 'ar'
37
+ | 'hi'
38
+
39
+ export const AVAILABLE_LANGUAGES: AvailableLanguage[] = [
40
+ 'en',
41
+ 'zh-Hans',
42
+ 'fr',
43
+ 'ja',
44
+ 'ru',
45
+ 'es',
46
+ 'pt',
47
+ 'de',
48
+ 'ar',
49
+ 'hi',
50
+ ]
51
+
52
+ import type { I18n } from 'vue-i18n'
53
+
25
54
  export class PageBuilderService {
55
+ private i18n: I18n
26
56
  // Class properties with types
27
57
  private fontSizeRegex =
28
58
  /^(sm:|md:|lg:|xl:|2xl:)?pbx-text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/
@@ -47,7 +77,8 @@ export class PageBuilderService {
47
77
  private pendingMountComponents: BuilderResourceData | null = null
48
78
  private isPageBuilderMissingOnStart: boolean = false
49
79
 
50
- constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>) {
80
+ constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>, i18n: I18n) {
81
+ this.i18n = i18n
51
82
  this.hasStartedEditing = false
52
83
  this.pageBuilderStateStore = pageBuilderStateStore
53
84
  this.getApplyImageToSelection = computed(
@@ -100,6 +131,9 @@ export class PageBuilderService {
100
131
  ]
101
132
  }
102
133
 
134
+ public availableLanguage(): AvailableLanguage[] {
135
+ return AVAILABLE_LANGUAGES
136
+ }
103
137
  // Deselect any selected or hovered elements in the builder UI
104
138
  async clearHtmlSelection(): Promise<void> {
105
139
  this.pageBuilderStateStore.setComponent(null)
@@ -235,6 +269,55 @@ export class PageBuilderService {
235
269
  return
236
270
  }
237
271
 
272
+ private ensureLanguage(config: PageBuilderConfig): void {
273
+ // Set default language config if missing, empty, or language missing/empty
274
+ const defaultLang = 'en'
275
+ const defaultEnable = ['en', 'zh-Hans', 'fr', 'ja', 'ru', 'es', 'pt', 'de', 'ar', 'hi'] as const
276
+
277
+ let needsDefault = false
278
+ const userSettings = config.userSettings
279
+ const language = userSettings && userSettings.language
280
+
281
+ if (!userSettings || isEmptyObject(userSettings)) {
282
+ needsDefault = true
283
+ } else if (!language || isEmptyObject(language)) {
284
+ needsDefault = true
285
+ }
286
+
287
+ if (needsDefault) {
288
+ const updatedLanguage = {
289
+ ...config,
290
+ userSettings: {
291
+ ...userSettings,
292
+ language: {
293
+ default: defaultLang,
294
+ enable: defaultEnable as typeof defaultEnable,
295
+ },
296
+ },
297
+ } as const
298
+ this.pageBuilderStateStore.setPageBuilderConfig(updatedLanguage)
299
+ return
300
+ }
301
+
302
+ // Ensure default is in enable array
303
+ if (language && Array.isArray(language.enable) && language.default) {
304
+ if (!language.enable.includes(language.default)) {
305
+ const updatedEnable = [...language.enable, language.default]
306
+ const updatedLanguage = {
307
+ ...config,
308
+ userSettings: {
309
+ ...userSettings,
310
+ language: {
311
+ ...language,
312
+ enable: updatedEnable,
313
+ },
314
+ },
315
+ } as const
316
+ this.pageBuilderStateStore.setPageBuilderConfig(updatedLanguage)
317
+ }
318
+ }
319
+ }
320
+
238
321
  private validateConfig(config: PageBuilderConfig): void {
239
322
  const defaultConfigValues = {
240
323
  updateOrCreate: {
@@ -251,6 +334,52 @@ export class PageBuilderService {
251
334
  if (config && Object.keys(config).length !== 0 && config.constructor === Object) {
252
335
  this.ensureUpdateOrCreateConfig(config)
253
336
  }
337
+
338
+ this.ensureLanguage(config)
339
+ }
340
+
341
+ public saveBuilderConfigToLocalStorage(specificConfig: PageBuilderConfig) {
342
+ // Only save userSettings to localStorage
343
+ if (specificConfig && specificConfig.userSettings) {
344
+ localStorage.setItem(
345
+ 'pageBuilderConfig',
346
+ JSON.stringify({ userSettings: specificConfig.userSettings }),
347
+ )
348
+ }
349
+ }
350
+
351
+ private checkBuilderConfigToLocalStorage(currentConfig: PageBuilderConfig) {
352
+ const savedConfigRaw = localStorage.getItem('pageBuilderConfig')
353
+
354
+ if (savedConfigRaw) {
355
+ try {
356
+ const savedConfig = JSON.parse(savedConfigRaw)
357
+ // Deep merge: prefer all keys from savedConfig, fallback to currentConfig
358
+ const mergedConfig = {
359
+ ...currentConfig,
360
+ ...savedConfig,
361
+ userSettings: {
362
+ ...currentConfig.userSettings,
363
+ ...savedConfig.userSettings,
364
+ },
365
+ }
366
+
367
+ this.pageBuilderStateStore.setPageBuilderConfig(mergedConfig)
368
+
369
+ const saveLang =
370
+ this.pageBuilderStateStore.getPageBuilderConfig &&
371
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings &&
372
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings.language &&
373
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings.language.default
374
+
375
+ if (saveLang) {
376
+ this.i18n.global.locale = saveLang
377
+ }
378
+ return
379
+ } catch (e) {
380
+ console.warn('Failed to parse saved pageBuilderConfig from localStorage:', e)
381
+ }
382
+ }
254
383
  }
255
384
 
256
385
  /**
@@ -271,6 +400,7 @@ export class PageBuilderService {
271
400
  // Prevents builder actions to prevent errors caused by missing DOM .
272
401
  this.pageBuilderStateStore.setBuilderStarted(true)
273
402
  const pagebuilder = document.querySelector('#pagebuilder')
403
+
274
404
  let validation
275
405
  try {
276
406
  this.originalComponents = passedComponentsArray
@@ -278,6 +408,20 @@ export class PageBuilderService {
278
408
  // Validate and normalize the config (ensure required fields are present)
279
409
  this.validateConfig(config)
280
410
 
411
+ if (
412
+ this.pageBuilderStateStore.getPageBuilderConfig &&
413
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings &&
414
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings.language &&
415
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings.language.default
416
+ ) {
417
+ this.i18n.global.locale =
418
+ this.pageBuilderStateStore.getPageBuilderConfig.userSettings.language.default
419
+ }
420
+
421
+ if (this.pageBuilderStateStore.getPageBuilderConfig) {
422
+ this.checkBuilderConfigToLocalStorage(this.pageBuilderStateStore.getPageBuilderConfig)
423
+ }
424
+
281
425
  validation = this.validateUserProvidedComponents(passedComponentsArray)
282
426
 
283
427
  // Update the localStorage key name based on the config/resource
@@ -405,7 +549,7 @@ export class PageBuilderService {
405
549
  }
406
550
 
407
551
  if (!passedComponentsArray && !localStorageData && this.isPageBuilderMissingOnStart) {
408
- console.log('10000:', internalPageBuilderCall)
552
+ console.log('XXXX:', internalPageBuilderCall)
409
553
  await this.completeMountProcess(JSON.stringify(this.pendingMountComponents), true)
410
554
  this.saveDomComponentsToLocalStorage()
411
555
  return
@@ -769,33 +913,11 @@ export class PageBuilderService {
769
913
 
770
914
  public handleManualSave = async () => {
771
915
  this.startEditing()
772
- const passedConfig = this.pageBuilderStateStore.getPageBuilderConfig
773
-
774
- // Check if config is set
775
- if (passedConfig && passedConfig.userSettings) {
776
- //
777
- //
778
- // Enabled auto save
779
- if (
780
- (typeof passedConfig.userSettings.autoSave === 'boolean' &&
781
- !passedConfig.userSettings.autoSave) ||
782
- (typeof passedConfig.userSettings.autoSave === 'boolean' &&
783
- passedConfig.userSettings.autoSave)
784
- ) {
785
- this.pageBuilderStateStore.setIsSaving(true)
786
- this.saveDomComponentsToLocalStorage()
787
- await delay(400)
788
916
 
789
- this.pageBuilderStateStore.setIsSaving(false)
790
- }
791
- }
792
- if (passedConfig && !passedConfig.userSettings) {
793
- this.pageBuilderStateStore.setIsSaving(true)
794
- this.saveDomComponentsToLocalStorage()
795
- await delay(400)
796
-
797
- this.pageBuilderStateStore.setIsSaving(false)
798
- }
917
+ this.pageBuilderStateStore.setIsSaving(true)
918
+ this.saveDomComponentsToLocalStorage()
919
+ await delay(400)
920
+ this.pageBuilderStateStore.setIsSaving(false)
799
921
  }
800
922
 
801
923
  public cloneCompObjForDOMInsertion(componentObject: ComponentObject): ComponentObject {
@@ -921,7 +1043,6 @@ export class PageBuilderService {
921
1043
  }
922
1044
 
923
1045
  public handleRemoveStyle(property: string): void {
924
- console.log('come her:', property)
925
1046
  const element = this.getElement.value
926
1047
  if (!element || !property) return
927
1048
 
@@ -6,61 +6,31 @@ import DemoBuilderComponentsTest from '../tests/TestComponents/DemoBuilderCompon
6
6
  import { onMounted } from 'vue'
7
7
  import componentsArray from '../tests/componentsArray.test.json'
8
8
  import { getPageBuilder } from '../composables/builderInstance'
9
+ import { useI18n } from 'vue-i18n'
9
10
  const pageBuilderService = getPageBuilder()
11
+ const { t } = useI18n()
10
12
 
11
13
  const features = [
12
- {
13
- name: 'Live Drag & Drop Builder',
14
- description:
15
- 'Click & Drop content on a page and watch your pages come to life. Bring your vision to life and create impressive pages using a click & drop Page Builder',
16
- },
17
- {
18
- name: 'True Visual Editing',
19
- description:
20
- 'See your changes in real-time as you make them. Elevate your creative vision and create pages using an intuitive click & drop page builder. Break free from design limitations and turn your visions into reality.',
21
- },
22
- {
23
- name: 'Features',
24
- description:
25
- 'Click & Drop, Reordering, True Visual Editing, Responsive Editing, Font Customization, Undo & Redo, Text Editing, Media Library, Unsplash Integration, YouTube Videos.',
26
- },
27
- {
28
- name: 'Technologies',
29
- description:
30
- 'Developed with TypeScript, Vue 3, Composition API, Pinia, CSS, Tailwind CSS and HTML.',
31
- },
32
- {
33
- name: 'Set Brand and Link Colors one place',
34
- description:
35
- 'Global Styles for fonts, designs, & colors. Set Brand and Link Colors once and apply them across the entire Platform with ease.',
36
- },
37
- {
38
- name: 'Mobile-First Approach',
39
- description:
40
- 'Developed with Mobile-First approach. The Page Builder even works on mobile phones.',
41
- },
42
- {
43
- name: 'Media Library',
44
- description:
45
- 'A beautiful and user-friendly media library that allows you to change and update images. Unsplash Integration is included.',
46
- },
47
- {
48
- name: 'Minimal and Intuitive Design',
49
- description:
50
- 'Beautiful, elegant and intuitive design. Enhance user engagement with amazing visual experience.',
51
- },
14
+ { key: 'liveDragDropBuilder' },
15
+ { key: 'trueVisualEditing' },
16
+ { key: 'features' },
17
+ { key: 'technologies' },
18
+ { key: 'setBrandAndLinkColors' },
19
+ { key: 'mobileFirstApproach' },
20
+ { key: 'mediaLibrary' },
21
+ { key: 'minimalIntuitiveDesign' },
52
22
  ]
53
23
 
54
24
  const publishPageBuilder = function () {}
55
25
 
56
26
  // Convert componentsArray to HTML string
57
27
  const htmlString =
58
- '<div id="pagebuilder" class="bg-yellow-200 border-radius-full pb-6" style="">' +
28
+ '<div id="pagebuilder" class="" style="">' +
59
29
  componentsArray.map((c) => c.html_code).join('\n') +
60
30
  '</div>'
61
31
 
62
32
  // Parse as HTML (not JSON)
63
- const { components, pageSettings } = pageBuilderService.parsePageBuilderHTML(htmlString)
33
+ const { /* components, */ pageSettings } = pageBuilderService.parsePageBuilderHTML(htmlString)
64
34
 
65
35
  const configPageBuilder = {
66
36
  userForPageBuilder: {
@@ -80,7 +50,11 @@ const configPageBuilder = {
80
50
  },
81
51
  userSettings: {
82
52
  theme: 'light',
83
- language: 'en',
53
+ language: {
54
+ default: 'en',
55
+ enable: ['en', 'zh-Hans', 'fr', 'ja', 'ru', 'es', 'pt', 'de', 'ar', 'hi'],
56
+ disableLanguageDropDown: false,
57
+ },
84
58
  autoSave: true,
85
59
  },
86
60
  settings: {
@@ -90,7 +64,7 @@ const configPageBuilder = {
90
64
  } as const
91
65
 
92
66
  onMounted(async () => {
93
- const result = await pageBuilderService.startBuilder(configPageBuilder, components)
67
+ const result = await pageBuilderService.startBuilder(configPageBuilder)
94
68
  console.log('Page Builder inspect the result for message, status, or error::', result)
95
69
  })
96
70
  </script>
@@ -100,19 +74,15 @@ onMounted(async () => {
100
74
  <div class="pbx-myPrimaryWidthScreenModule pbx-bg-red-50 lg:pbx-block">
101
75
  <div class="pbx-myPrimaryContentSection">
102
76
  <h2 class="pbx-mySecondaryHeader">
103
- Bring your vision to life and create impressive pages using a click & drop Page Builder
77
+ {{ $t('branding.mainHeader') }}
104
78
  </h2>
105
79
  <p class="pbx-myPrimaryParagraph pbx-font-normal">
106
- The web builder for stunning pages. Enable users to design and publish modern pages at any
107
- scale. Build responsive pages like listings, jobs or blog posts and manage content easily
108
- using the free click & drop Page Builder. Developed with TypeScript, Vue 3, Composition
109
- API, Pinia, CSS, Tailwind CSS and HTML.
110
-
80
+ {{ $t('branding.description') }}
111
81
  <br />
112
82
  </p>
113
83
  <div class="pbx-mt-4">
114
84
  <p class="pbx-myPrimaryParagraph pbx-font-normal">
115
- Download or install our powerful, flexible, and easy-to-use free Vue 3 Page Builder via
85
+ {{ $t('branding.downloadDescription') }}
116
86
  <br />
117
87
  <strong> npm:</strong>
118
88
  <a
@@ -150,16 +120,16 @@ onMounted(async () => {
150
120
  >
151
121
  <div
152
122
  v-for="feature in features"
153
- :key="feature.name"
123
+ :key="feature.key"
154
124
  class="pbx-bg-red-200 pbx-bg-opacity-20 hover:pbx-bg-opacity-10 pbx-w-full lg:pbx-min-h-[20rem] pbx-min-h-[12rem] pbx-relative pbx-col-span-1 pbx-flex pbx-flex-col pbx-text-center pbx-rounded-lg pbx-shadow-sm pbx-outline pbx-outline-2 pbx-outline-offset-8 pbx-outline-yellow-400"
155
125
  >
156
126
  <div
157
127
  class="pbx-bg-black/0 pbx-absolute pbx-top-0 pbx-left-0 pbx-w-full pbx-h-full pbx-rounded-lg"
158
128
  ></div>
159
129
  <div class="pbx-px-2 pbx-pt-8 pbx-absolute pbx-top-0 pbx-w-full">
160
- <p class="pbx-myTertiaryHeader">{{ feature.name }}</p>
130
+ <p class="pbx-myTertiaryHeader">{{ t(`features.${feature.key}.name`) }}</p>
161
131
  <p class="pbx-myPrimaryParagraph pbx-font-medium pbx-drop-shadow-sm">
162
- {{ feature.description }}
132
+ {{ t(`features.${feature.key}.description`) }}
163
133
  </p>
164
134
  </div>
165
135
  </div>
@@ -47,7 +47,13 @@ describe('PageBuilderService', () => {
47
47
  typeof (fn as { mockClear?: () => void }).mockClear === 'function' &&
48
48
  (fn as { mockClear: () => void }).mockClear(),
49
49
  )
50
- service = new PageBuilderService(mockStore)
50
+ // Provide a minimal i18n mock for tests
51
+ const mockI18n = {
52
+ global: {
53
+ locale: 'en',
54
+ },
55
+ } as any
56
+ service = new PageBuilderService(mockStore, mockI18n)
51
57
  })
52
58
 
53
59
  it('should start builder and return a success message', async () => {
@@ -227,7 +227,13 @@ export interface PageBuilderConfig {
227
227
  [key: string]: unknown
228
228
  userSettings?: {
229
229
  theme?: 'light' | 'dark' | 'auto'
230
- language?: string
230
+ language?: {
231
+ default: 'en' | 'zh-Hans' | 'fr' | 'ja' | 'ru' | 'es' | 'pt' | 'de' | 'ar' | 'hi'
232
+ enable?: ReadonlyArray<
233
+ 'en' | 'zh-Hans' | 'fr' | 'ja' | 'ru' | 'es' | 'pt' | 'de' | 'ar' | 'hi'
234
+ >
235
+ }
236
+
231
237
  autoSave?: boolean
232
238
  [key: string]: unknown
233
239
  } | null