@mixd-id/web-scaffold 0.1.230406298 → 0.1.230406300

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.230406298",
4
+ "version": "0.1.230406300",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -47,9 +47,9 @@
47
47
  "crypto-js": "^4.2.0",
48
48
  "daisyui": "^2.19.0",
49
49
  "dayjs": "^1.11.2",
50
+ "eventemitter2": "^6.4.7",
50
51
  "exceljs": "^4.3.0",
51
52
  "express": "^4.18.1",
52
- "eventemitter2": "^6.4.7",
53
53
  "file-type": "^18.2.1",
54
54
  "glob": "^8.0.3",
55
55
  "lodash": "^4.17.21",
@@ -57,6 +57,7 @@
57
57
  "nprogress": "^0.2.0",
58
58
  "pinia": "^2.0.14",
59
59
  "prismjs": "^1.28.0",
60
+ "redis": "^4.6.13",
60
61
  "serve-static": "^1.15.0",
61
62
  "tailwindcss": "^3.2.4",
62
63
  "vue": "^3.2.25",
@@ -275,7 +275,7 @@ export default{
275
275
 
276
276
  '$route.hash': {
277
277
  handler(to){
278
- if(this.hash !== null){
278
+ if(typeof this.hash === 'string'){
279
279
  this._state = (to ?? '').indexOf(this.hash) >= 0
280
280
  }
281
281
  }
@@ -64,7 +64,7 @@ export default{
64
64
 
65
65
  emits: [ 'add', 'change', 'moveup', 'movedown', 'remove' ],
66
66
 
67
- inject: [ 'confirm', 'toast', 'store' ],
67
+ inject: [ 'confirm', 'toast', 'store', 'getConfig' ],
68
68
 
69
69
  props: {
70
70
  item: Object,
@@ -340,7 +340,9 @@ export default{
340
340
 
341
341
  item: {
342
342
  handler(){
343
- this.childCollapsed = this.componentStore[this.item.uid] ?? this.childCollapsed
343
+ if(this.componentStore){
344
+ this.childCollapsed = this.componentStore[this.item.uid] ?? this.childCollapsed
345
+ }
344
346
  },
345
347
  deep: true
346
348
  },
package/src/index.js CHANGED
@@ -554,6 +554,7 @@ export default{
554
554
  app.component('TestimonialSetting', defineAsyncComponent(() => import("./widgets/TestimonialSetting.vue")))
555
555
  app.component('TextBlockSetting', defineAsyncComponent(() => import("./widgets/TextBlockSetting.vue")))
556
556
  app.component('WebPageBuilder', defineAsyncComponent(() => import("./widgets/WebPageBuilder.vue")))
557
+ app.component('WebPageBuilder2', defineAsyncComponent(() => import("./widgets/WebPageBuilder2.vue")))
557
558
  app.component('WebComponentSelector', defineAsyncComponent(() => import("./widgets/WebComponentSelector.vue")))
558
559
  app.component('WebDatasourceSelector', defineAsyncComponent(() => import("./widgets/WebDatasourceSelector.vue")))
559
560
  app.component('WebPageSelector', defineAsyncComponent(() => import("./widgets/WebPageSelector.vue")))
@@ -287,21 +287,27 @@ const createFormData = (obj) => {
287
287
 
288
288
  const form = new FormData()
289
289
 
290
- const iterateObject = (parentKey, obj) => {
290
+ const iterateObject = (obj, parentKey = '') => {
291
291
 
292
- for(let key in obj){
293
- let currentKey = parentKey ? '[' + key + ']' : key
292
+ for (let key in obj) {
293
+ if (obj.hasOwnProperty(key)) {
294
+ const value = obj[key];
295
+ const propName = parentKey ? `${parentKey}[${key}]` : key;
294
296
 
295
- if(obj[key] !== '' && obj[key] !== null && obj[key] !== undefined){
296
- form.append(
297
- currentKey,
298
- obj[key] ?? ''
299
- )
297
+ if (value instanceof File || value instanceof Blob) {
298
+ form.append(propName, value);
299
+ }
300
+ else if (typeof value === 'object' && value !== null) {
301
+ iterateObject(value, propName);
302
+ }
303
+ else {
304
+ form.append(propName, value);
305
+ }
300
306
  }
301
307
  }
302
308
  }
303
309
 
304
- iterateObject('', obj)
310
+ iterateObject(obj)
305
311
 
306
312
  return form
307
313
  }
package/src/utils/wss.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const WebSocket = require('ws');
2
2
  const CryptoJS = require("crypto-js");
3
- const crypto = require("crypto-js");
4
3
  const EventEmitter2 = require("eventemitter2");
4
+ const redis = require("redis");
5
+
5
6
 
6
7
  const convertDataUrlObj = async(obj) => {
7
8
 
@@ -85,7 +86,7 @@ class WSS extends EventEmitter2{
85
86
  async toBinaryData(obj){
86
87
  const dataUrlObj = await convertDataUrlObj(obj)
87
88
  const encryptedData = this._opt.key ?
88
- crypto.AES.encrypt(JSON.stringify(dataUrlObj), this._opt.key).toString() :
89
+ CryptoJS.AES.encrypt(JSON.stringify(dataUrlObj), this._opt.key).toString() :
89
90
  JSON.stringify(dataUrlObj);
90
91
  return new TextEncoder().encode(encryptedData);
91
92
  }
@@ -96,24 +97,42 @@ class WSS extends EventEmitter2{
96
97
  this._opt = opt
97
98
  this._instance = new WebSocket.Server(opt);
98
99
 
100
+ this._client = redis.createClient()
101
+ this._client.connect().then()
102
+
99
103
  this._instance.on('connection', async (socket, req) => {
100
104
 
105
+ let subscriber
106
+
107
+ const listener = (message) => {
108
+ const { model, event, items } = JSON.parse(message)
109
+ this.toBinaryData({ data:{ model, event, items } })
110
+ .then(data => socket.send(data))
111
+ }
112
+
101
113
  socket.leave = (channel) => {
102
- if((socket.channels ?? {})[channel]){
114
+ /*if((socket.channels ?? {})[channel]){
103
115
  delete socket.channels[channel]
116
+ }*/
104
117
 
105
- if(process.verbose){
106
- process.verbose('wss.leave', channel)
107
- }
118
+ if(subscriber){
119
+ subscriber.unsubscribe(channel, listener)
120
+ }
121
+
122
+ if(process.verbose){
123
+ process.verbose('wss.leave', channel)
108
124
  }
109
125
  }
110
126
 
111
127
  socket.join = (channel) => {
112
- if(!socket.channels){
128
+ /*if(!socket.channels){
113
129
  socket.channels = {}
114
130
  }
131
+ socket.channels[channel] = 1*/
115
132
 
116
- socket.channels[channel] = 1
133
+ if(subscriber) {
134
+ subscriber.subscribe(channel, listener)
135
+ }
117
136
 
118
137
  if(process.verbose){
119
138
  process.verbose('wss.join', channel)
@@ -184,6 +203,9 @@ class WSS extends EventEmitter2{
184
203
  });
185
204
 
186
205
  socket.on('close', (e) => {
206
+ if(subscriber){
207
+ subscriber.disconnect()
208
+ }
187
209
  this.emit('close', e, socket)
188
210
  });
189
211
 
@@ -192,6 +214,9 @@ class WSS extends EventEmitter2{
192
214
  await this._opt.auth(token, socket)
193
215
  socket.isAuth = true
194
216
  socket.send(await this.toBinaryData({ auth:true }))
217
+
218
+ subscriber = this._client.duplicate()
219
+ await subscriber.connect()
195
220
  }
196
221
  catch(e){
197
222
  return socket.close(1002, e.message);
@@ -231,6 +256,14 @@ class WSS extends EventEmitter2{
231
256
 
232
257
  async broadcast(channel, { model, event, items }){
233
258
 
259
+ /*for(let socket of this._instance.clients){
260
+ if(socket.readyState === WebSocket.OPEN && (socket.channels ?? {})[channel]){
261
+ socket.send(await this.toBinaryData({ data:{ model, event, items } }))
262
+ }
263
+ }*/
264
+
265
+ await this._client.publish(channel, JSON.stringify({ model, event, items }))
266
+
234
267
  if(process.verbose){
235
268
  process.verbose('wss.broadcast', {
236
269
  channel,
@@ -239,12 +272,6 @@ class WSS extends EventEmitter2{
239
272
  items
240
273
  })
241
274
  }
242
-
243
- for(let socket of this._instance.clients){
244
- if(socket.readyState === WebSocket.OPEN && (socket.channels ?? {})[channel]){
245
- socket.send(await this.toBinaryData({ data:{ model, event, items } }))
246
- }
247
- }
248
275
  }
249
276
 
250
277
  }
@@ -0,0 +1,682 @@
1
+ <template>
2
+ <div v-if="page" :class="$style.comp">
3
+
4
+ <div class="flex-1 flex flex-col bg-base-400">
5
+
6
+ <div class="p-3 pr-5 sticky top-0 flex justify-center gap-4 bg-base-400 dark:bg-base-300 border-b-[1px] border-text-50">
7
+ <div class="flex-1 flex flex-row gap-4 items-center">
8
+
9
+ <button ref="close" class=" p-1"
10
+ @click="close">
11
+ <svg class="fill-text-300 hover:fill-red-500" width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
12
+ </button>
13
+
14
+ <h4 class="mr-5 w-[200px] text-ellipsis whitespace-nowrap overflow-hidden">
15
+ {{ page.title }}
16
+ </h4>
17
+
18
+ <div class="flex-1">
19
+ <Textbox :readonly="1" :value="computedIframeSrc" class="w-full rounded-full" item-class="p-1">
20
+ <template #start>
21
+ <div class="flex flex-row items-center mr-2">
22
+ <button @click="reloadIframe" class="p-3">
23
+ <svg width="14" height="14" viewBox="0 0 24 24" class="fill-text" xmlns="http://www.w3.org/2000/svg">
24
+ <path d="M3.75 12C3.75 7.44365 7.44365 3.75 12 3.75C14.7802 3.75 17.1982 5.12612 18.6816 7.24467L16.5022 7.23828C16.088 7.23707 15.7512 7.57187 15.75 7.98608C15.7488 8.4003 16.0836 8.73706 16.4978 8.73828L19.9491 8.74839C19.9817 8.75065 20.0147 8.75076 20.0477 8.74868L20.4978 8.75C20.6971 8.75058 20.8884 8.67182 21.0296 8.53111C21.1707 8.39039 21.25 8.19929 21.25 8L21.25 4C21.25 3.58579 20.9142 3.25 20.5 3.25C20.0858 3.25 19.75 3.58579 19.75 4L19.75 6.16237C17.9894 3.79113 15.2004 2.25 12 2.25C6.61522 2.25 2.25 6.61522 2.25 12C2.25 17.3848 6.61522 21.75 12 21.75C15.8354 21.75 19.0799 19.5367 20.6716 16.3338C20.856 15.9628 20.7047 15.5127 20.3338 15.3284C19.9628 15.144 19.5127 15.2953 19.3284 15.6662C17.9747 18.3902 15.2321 20.25 12 20.25C7.44365 20.25 3.75 16.5563 3.75 12Z"/>
25
+ </svg>
26
+ </button>
27
+ <select v-model="config.zoomLevel" :class="$style.zoomLevel" @change="resize()">
28
+ <optgroup label="Zoom Level">
29
+ <option value="fit">Fit</option>
30
+ <option value="125%">125%</option>
31
+ <option value="100%">100%</option>
32
+ <option value="75%">75%</option>
33
+ <option value="50%">50%</option>
34
+ </optgroup>
35
+ </select>
36
+ </div>
37
+ </template>
38
+ <template #end>
39
+ <div class="flex flex-row gap-4 ml-3">
40
+ <CopyToClipboard :value="computedIframeSrc" @copied="toast($t('Copied'))">
41
+ <svg width="14" height="14" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M433.941 65.941l-51.882-51.882A48 48 0 0 0 348.118 0H176c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48v-48h80c26.51 0 48-21.49 48-48V99.882a48 48 0 0 0-14.059-33.941zM352 32.491a15.88 15.88 0 0 1 7.431 4.195l51.882 51.883A15.885 15.885 0 0 1 415.508 96H352V32.491zM288 464c0 8.822-7.178 16-16 16H48c-8.822 0-16-7.178-16-16V144c0-8.822 7.178-16 16-16h80v240c0 26.51 21.49 48 48 48h112v48zm128-96c0 8.822-7.178 16-16 16H176c-8.822 0-16-7.178-16-16V48c0-8.822 7.178-16 16-16h144v72c0 13.2 10.8 24 24 24h72v240z"/></svg>
42
+ </CopyToClipboard>
43
+ <a type="button" class="w-[21px]" :href="computedIframeSrc" target="_blank">
44
+ <svg width="12" height="12" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M497.6,0,334.4.17A14.4,14.4,0,0,0,320,14.57V47.88a14.4,14.4,0,0,0,14.69,14.4l73.63-2.72,2.06,2.06L131.52,340.49a12,12,0,0,0,0,17l23,23a12,12,0,0,0,17,0L450.38,101.62l2.06,2.06-2.72,73.63A14.4,14.4,0,0,0,464.12,192h33.31a14.4,14.4,0,0,0,14.4-14.4L512,14.4A14.4,14.4,0,0,0,497.6,0ZM432,288H416a16,16,0,0,0-16,16V458a6,6,0,0,1-6,6H54a6,6,0,0,1-6-6V118a6,6,0,0,1,6-6H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V304A16,16,0,0,0,432,288Z"/></svg>
45
+ </a>
46
+ </div>
47
+ </template>
48
+ </Textbox>
49
+ </div>
50
+
51
+ <Tabs :items="previewModes" v-model="config.previewMode" variant="button" @change="updateIframe" />
52
+
53
+ <Button ref="saveBtn"
54
+ class="w-[70px] rounded-full p-1"
55
+ :state="canSave ? 1 : 1"
56
+ @click="save">{{ $t('Save') }}</Button>
57
+ </div>
58
+ </div>
59
+
60
+ <div class="flex-1 flex flex-row">
61
+
62
+ <div class="flex flex-row bg-base-400 dark:bg-base-300 border-r-[1px] border-text-50"
63
+ :style="section1Style">
64
+
65
+ <div class="flex-1 flex flex-col overflow-y-auto">
66
+
67
+ <div class="flex flex-col items-center border-b-[1px] border-text-100" @click="currentArea = 'header'">
68
+ <Tabs :items="tabItems"
69
+ class="pt-1"
70
+ v-model="leftBar.tabIndex" />
71
+ </div>
72
+
73
+ <div v-if="leftBar.tabIndex === 1">
74
+
75
+ </div>
76
+
77
+ <div v-else-if="leftBar.tabIndex === 2"
78
+ class="flex-1 overflow-y-auto p-6 flex flex-col gap-6">
79
+
80
+ <div>
81
+ <div class="flex flex-row gap-1 items-center cursor-pointer">
82
+ <svg v-if="!expanded['components']" width="12" height="12" @click="expanded['components'] = !expanded['components']" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"/></svg>
83
+ <svg v-else width="12" height="12" @click="expanded['components'] = !expanded['components']" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"/></svg>
84
+ <strong class="flex-1 text-text-400 line-clamp-1" @click="expanded['components'] = !expanded['components']">{{ $t('Components')}}</strong>
85
+ <button type="button" class="text-primary flex flex-row items-center gap-1"
86
+ @click="openComponentSelector({ items:page.components }); currentArea = ''">
87
+ <svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M376 232H216V72c0-4.42-3.58-8-8-8h-32c-4.42 0-8 3.58-8 8v160H8c-4.42 0-8 3.58-8 8v32c0 4.42 3.58 8 8 8h160v160c0 4.42 3.58 8 8 8h32c4.42 0 8-3.58 8-8V280h160c4.42 0 8-3.58 8-8v-32c0-4.42-3.58-8-8-8z"/></svg>
88
+ {{ $t('Add')}}
89
+ </button>
90
+ </div>
91
+
92
+ <div v-if="expanded['components']" class="flex flex-col gap-10">
93
+ <TreeView class="mt-2"
94
+ v-model="page.components"
95
+ :selected-item="currentItem"
96
+ @add="(items) => openComponentSelector({ items })"
97
+ @change="">
98
+ <template #default="{ item }">
99
+ <div class="flex-1 text-ellipsis whitespace-nowrap overflow-hidden"
100
+ :class="!item.props.enabled ? 'line-through' : ''"
101
+ @click="select(item.uid)">
102
+ {{ item.props.name ?? item.type }}
103
+ </div>
104
+ </template>
105
+ </TreeView>
106
+ </div>
107
+ </div>
108
+
109
+ </div>
110
+
111
+ </div>
112
+
113
+ <div :class="$style.resize1"
114
+ @mousedown="(e) => $util.dragResize(e, resize1)"></div>
115
+ </div>
116
+
117
+ <div class="flex-1 bg-base-300 dark:bg-base-400 relative" :class="previewClass" ref="preview">
118
+
119
+ <div class="flex flex-row p-2">
120
+ <select class="p-1 text-sm cursor-pointer bg-text-50 outline-none"
121
+ v-model="config.previewViewType"
122
+ @change="resize">
123
+ <option v-for="_type in previewViewTypes" :value="_type.value">{{ _type.text }}</option>
124
+ </select>
125
+ </div>
126
+
127
+ <iframe :src="iframeSrc" :width="iframeSize.width" :height="iframeSize.height"
128
+ class="mx-auto border-[2px] border-text-300" :style="iframeStyle" ref="iframe"></iframe>
129
+
130
+ </div>
131
+
132
+ <div v-if="currentItem"
133
+ class="flex flex-row bg-base-400 dark:bg-base-300 border-l-[1px] border-text-50"
134
+ @click=""
135
+ :style="section3Style">
136
+
137
+ <div :class="$style.resize3"
138
+ @mousedown="(e) => $util.dragResize(e, resize3)"></div>
139
+
140
+ <div class="flex-1 flex flex-col gap-6 overflow-y-auto p-6">
141
+
142
+ <component :is="`${currentItem.type}Setting`"
143
+ :item="currentItem"
144
+ :view-type="config.viewType"
145
+ :view-types="viewTypes"
146
+ ref="settingComponent"
147
+ @change="pageHistory.commit()"
148
+ @postMessageToIframe="onPostMessageToIframe"/>
149
+
150
+ </div>
151
+
152
+ </div>
153
+
154
+ </div>
155
+
156
+ </div>
157
+
158
+ <WebComponentSelector ref="webPageComponentSelector"
159
+ component-src="template.load"
160
+ :components="availableComponents"
161
+ @apply="addComponent"
162
+ dismissable="true"
163
+ @dismiss="$refs.webPageComponentSelector.close()" />
164
+
165
+ </div>
166
+ </template>
167
+
168
+ <script>
169
+
170
+ import md5 from "md5";
171
+
172
+ export default{
173
+
174
+ emits: [ 'save' ],
175
+
176
+ props: {
177
+
178
+ config: {
179
+ type: Object,
180
+ required: true
181
+ },
182
+
183
+ page: {
184
+ type: Object,
185
+ default: {}
186
+ }
187
+
188
+ },
189
+
190
+ data(){
191
+ return {
192
+ components: [
193
+
194
+ {"type":"Flex","name":"3 Column Layout","group":"Layouts","thumbnailUrl":"/images/templates/3-column-layout1.png", "items":[{"type":"Flex","name":"Flex","group":"Components","items":[{"type":"Article","name":"Article","group":"Components","props":{"htmlText":"Left","padding":["p-6",""],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"name":"Dummy Text"}}],"props":{"direction":["flex-col"],"enabled":true,"width":["","md:w-2/12"],"name":"Left"}},{"type":"Flex","name":"Flex","group":"Components","items":[{"type":"Article","name":"Article","group":"Components","props":{"htmlText":"Middle","padding":["p-6",""],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"name":"Dummy Text"}}],"props":{"direction":["flex-col"],"enabled":true,"width":[null,"md:flex-1"],"name":"Middle"}},{"type":"Flex","name":"Flex","group":"Components","items":[{"type":"Article","name":"Article","group":"Components","props":{"htmlText":"Right","padding":["p-6",""],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"name":"Dummy Text"}}],"props":{"direction":["flex-col"],"enabled":true,"width":[null,"md:w-3/12"],"name":"RIght"}}],"props":{"direction":["flex-col","md:flex-row"],"gap":[null,"md:gap-4"],"enabled":true,"name":"3 Column Layout"}},
195
+
196
+
197
+ {"type":"Flex","name":"Thumbnails","group":"Sections","thumbnailUrl":"/images/templates/thumbnails.gif","items":[{"type":"Flex","name":"Flex","group":"Components","items":[{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Thumbnails","tagName":"h5","flex":["flex-1"]}},{"type":"Link","name":"Link","group":"Components","props":{"enabled":true,"textColor":["text-primary-500"],"direction":["flex-column"],"gap":["gap-2"],"text":"More Thumbnails"},"items":[]}],"props":{"direction":["flex-row"],"enabled":true,"flexAlign":["items-center"]}},{"type":"Flex","name":"Flex","group":"Components","items":[{"type":"Thumbnail","name":"Thumbnail","group":"Components","props":{"enabled":true,"width":["w-5/12"],"direction":["flex-column"],"gap":["gap-2"],"flex":["flex-0"]},"items":[]},{"type":"Thumbnail","name":"Thumbnail","group":"Components","props":{"enabled":true,"width":["w-5/12"],"direction":["flex-column"],"gap":["gap-2"],"flex":["flex-0"]},"items":[]},{"type":"Thumbnail","name":"Thumbnail","group":"Components","props":{"enabled":true,"width":["w-5/12"],"direction":["flex-column"],"gap":["gap-2"],"flex":["flex-0"]},"items":[]}],"props":{"direction":["flex-row"],"gap":["gap-4"],"enabled":true,"overflow":["overflow-x-scroll"],"width":["w-full"],"minWidth":["min-w-0"]}}],"props":{"direction":["flex-col"],"gap":["gap-2"],"enabled":true,"padding":["p-5",""],"name":"Thumbnails"}},
198
+
199
+ {"type":"Carousel","name":"Image Carousel","group":"Sections","thumbnailUrl":"/images/templates/carousel1.png","items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["/assets/web/banner1.jpg"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"bdRadius":["rounded-xl"],"aspectRatio":["aspect-[2/1]"],"bgColors":["bg-amber-300"]}},{"type":"Image","name":"Image","group":"Components","props":{"src":["/assets/web/banner1.jpg"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"bdRadius":["rounded-xl"],"aspectRatio":["aspect-[2/1]"],"bgColors":["bg-lime-300"]}},{"type":"Image","name":"Image","group":"Components","props":{"src":["/assets/web/banner1.jpg"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"bdRadius":["rounded-xl"],"aspectRatio":["aspect-[2/1]"],"bgColors":["bg-blue-300"]}}],"props":{"enabled":true,"containerGap":["gap-2"],"padding":["p-4",""],"direction":["flex-column"],"gap":["gap-2"],"useLegend":true}},
200
+
201
+ {"type":"Link","name":"Icon Link","group":"Sections","thumbnailUrl":"/images/templates/icon-link.png","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["059bae0eadf1b650f3acff7dd1e7433a.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","fontWeight":["font-normal"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Icon Link 1"}}]},
202
+
203
+ {"type":"Carousel","name":"Icon Link Carousel","group":"Sections","thumbnailUrl":"/images/templates/icon-link-carousel.gif", "items":[{"type":"Grid","name":"Grid","group":"Components","thumbnailUrl":"/images/templates/grid1.png","items":[{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["059bae0eadf1b650f3acff7dd1e7433a.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 1","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["c7e8d12c0dcda3b9d3b2862559a8bc2e.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 2","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["47bcb782edfc426c8506664cc3b320e7.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 3","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["01e5a3e8f0e89562a7f6a5449be44614.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 4","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["7d7cc53e346aa5abf1f1ada463ed0e5c.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 5","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["4a1d1808e9f1be18f0ba18322647a11e.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 6","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["1b7f9673aeee9ebdf305658a54c63dc8.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 7","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["71828d52f682527cd500c1ba6c2a9ef0.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 8","fontSize":["text-sm"]}}]}],"gap":[],"props":{"columns":["grid-cols-4"],"gap":["gap-5"],"enabled":true,"direction":["flex-column"],"padding":["p-5",""]}},{"type":"Grid","name":"Grid","group":"Components","thumbnailUrl":"/images/templates/grid1.png","items":[{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["71828d52f682527cd500c1ba6c2a9ef0.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 9","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["059bae0eadf1b650f3acff7dd1e7433a.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 10","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["4a1d1808e9f1be18f0ba18322647a11e.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 11","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["7d7cc53e346aa5abf1f1ada463ed0e5c.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 12","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["47bcb782edfc426c8506664cc3b320e7.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 13","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["c7e8d12c0dcda3b9d3b2862559a8bc2e.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 14","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["4a1d1808e9f1be18f0ba18322647a11e.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 15","fontSize":["text-sm"]}}]},{"type":"Link","name":"Icon Link","group":"Sections","props":{"enabled":true,"display":["flex"],"direction":["flex-col"],"gap":["gap-2"],"flexAlign":["items-center"],"name":"Icon Link"},"items":[{"type":"Image","name":"Image","group":"Components","props":{"src":["059bae0eadf1b650f3acff7dd1e7433a.png"],"enabled":true,"direction":["flex-column"],"gap":["gap-2"]}},{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","enabled":true,"direction":["flex-column"],"gap":["gap-2"],"text":"Link 16","fontSize":["text-sm"]}}]}],"gap":[],"props":{"columns":["grid-cols-4"],"gap":["gap-5"],"enabled":true,"direction":["flex-column"],"padding":["p-5",""]}}],"props":{"enabled":true,"containerGap":["gap-2"],"padding":["p-4",""],"direction":["flex-column"],"gap":["gap-2"],"useLegend":true,"bgColors":["bg-gray-200"],"name":"Icon Link Carousel"}},
204
+
205
+ { type:'ContactForm', name:'Contact Form', group:'Widgets', thumbnailUrl:"/images/templates/contact-form1.png", props:{
206
+ fields:[
207
+ { type:'name', label:'Nama', required:true },
208
+ { type:'mobileNumber', label:'Nomor HP', required:true },
209
+ { type:'remark', label:'Pertanyaan' },
210
+ ],
211
+ title: 'Contact Us',
212
+ description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent gravida erat eget nisi',
213
+ submitMethod: 'post',
214
+ submitUrl: '/inquiry',
215
+ onSubmit:[],
216
+ }},
217
+
218
+ { type:'IconList', name:'Icon List', group:'Widgets', props:{
219
+ icons:[], columns:[ 'grid-cols-4' ],
220
+ }},
221
+
222
+ { type:'DataList', name:'Data List', group:'Widgets', props:{}, items:[] },
223
+
224
+ { type:'FAQ', name:'FAQ', group:'Widgets', thumbnailUrl:"/images/templates/faq.gif", props:{ items:[] }},
225
+ { type:'FAQ', name:'FAQ', group:'Widgets', thumbnailUrl:"/images/templates/faq.gif", props:{ items:[] }},
226
+
227
+ { type:'FeatureList', name:'Feature List', group:'Widgets', props:{ items:[], columns:[], variant:['variant1'] }},
228
+
229
+ { type:'Review', name:'Review', group:'Widgets', props:{} },
230
+
231
+ { type:'Share', name:'Share To', group:'Widgets', props:{ channels:[] }},
232
+
233
+ { type:'Testimonial', name:'Testimonial', group:'Widgets', props:{} },
234
+
235
+ { type:'Header', name:'Header', group:'Widgets', props:{}, items:[] },
236
+
237
+ { type:'ThumbnailList', name:'Thumbnail List', group:'Widgets', props:{ items:[] } },
238
+
239
+ { type:'ProductDetail', name:'Product Detail', props:{}, group:'Widgets' },
240
+
241
+
242
+ {"type":"Flex","name":"Section 1","group":"Components","items":[{"type":"TextBlock","name":"TextBlock","group":"Components","props":{"htmlText":"","fontSize":["text-4xl"],"enabled":true,"text":"Drive more revenue at lower costs\n","fontWeight":["font-semibold"]}},{"type":"Paragraph","name":"Paragraph","group":"Components","props":{"name":"Paragraph","enabled":true,"text":"Reach every customer on their own preferred channel with dynamic, omnichannel campaigns, using channel-responsive templates.","html":"Reach every customer on their own preferred channel with dynamic, omnichannel campaigns, using channel-responsive templates.","maxWidth":["max-w-lg"],"fontSize":["text-xl"]}},{"type":"Flex","name":"Flex","group":"Components","items":[{"type":"Button","name":"Button","group":"Components","props":{"name":"Button","text":"Start Now","enabled":true,"padding":["px-3 py-0"],"fontSize":["text-xl"]}},{"type":"Button","name":"Button","group":"Components","props":{"name":"Button","text":"Contact Sales","enabled":true,"variant":"outline","padding":["p-3"],"fontSize":["text-xl"]}}],"props":{"direction":["flex-row"],"gap":["gap-3"],"enabled":true}}],"props":{"direction":["flex-col"],"gap":["gap-4"],"enabled":true,"padding":["p-8"],"margin":["mx-auto"],"width":["w-full"],"maxWidth":["max-w-screen-xl"]}},
243
+
244
+ {"type":"Carousel","name":"Carousel","group":"Components","items":[],"props":{"enabled":true,"containerGap":["gap-2"],"padding":["p-4",""],"direction":["flex-column"],"gap":["gap-2"],"useLegend":true}},
245
+
246
+ { type:'Link', name:'Link', group:'Components', props:{}, items:[] },
247
+
248
+ { type:'Modal', name:'Modal', group:'Components', props:{}, items:[] },
249
+
250
+ { type:'Thumbnail', name:'Thumbnail', group:'Components', props:{}, items:[] },
251
+
252
+ { type:'Ahref', name:'Ahref', group:'Components', props:{ name:'Ahref', text:'Ahref' } },
253
+
254
+ { type:'Paragraph', name:'Paragraph', group:'Components', thumbnailUrl:"/images/templates/paragraph1.png", props:{ name:'Paragraph' } },
255
+
256
+ { type:'Button', name:'Button', group:'Components', props:{
257
+ name:'Button', text:'Button'
258
+ }},
259
+
260
+ { type:'Flex', name:'Flex', group:'Components', items:[], props:{ direction: [ 'flex-row' ] }},
261
+
262
+ { type:'Grid', name:'Grid', group:'Components', thumbnailUrl:"/images/templates/grid1.png", items:[], gap:[], props:{
263
+ columns: [], gap: [],
264
+ }},
265
+
266
+ { type:'Image', name:'Image', group:'Components', props:{
267
+ src:[],
268
+ }},
269
+
270
+ { type:'EmbeddedVideo', name:'Video', group:'Components', props:{
271
+ src:[],
272
+ }},
273
+
274
+ { type:'Article', name:'Article', group:'Components', props:{
275
+ htmlText:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed convallis odio at odio dapibus, " +
276
+ "eget molestie risus semper. Aenean magna tellus, aliquet nec tristique eget, lacinia nec urna.",
277
+ }},
278
+
279
+ { type:'Table', name:'Table', group:'Components', props:{
280
+ items: []
281
+ }},
282
+
283
+ { type:'TextBlock', name:'TextBlock', group:'Components', props:{
284
+ htmlText:'',
285
+ fontFamily:[], fontSize:[], fontWeight:[], textColor:[]
286
+ }},
287
+
288
+ { type:'Block', name:'Block', group:'Components', items:[], props:{}},
289
+
290
+ { type:'Countdown', name:'Countdown', group:'Components', props:{}},
291
+
292
+ { type:'YoutubeVideo', name:'Youtube Video', group:'Components', props:{ name:"Youtube Video", delay:"0" }},
293
+
294
+ { type:'Svg', name:'Svg', group:'Components', props:{}},
295
+
296
+ ],
297
+ iframeSrc: '',
298
+ iframeStyle: {},
299
+ previewModes: [
300
+ { text:"Design", value:1 },
301
+ { text:"Preview", value:2 },
302
+ ],
303
+ pageHistory: null,
304
+ prevData: null,
305
+ tabItems: [
306
+ { text:"Page Info", value:1 },
307
+ { text:"Components", value:2 },
308
+ { text:"Datasource", value:3 },
309
+ ],
310
+ viewTypes: [
311
+ { text:'Mobile', value:'' },
312
+ { text:'Tablet', value:'md:' },
313
+ ],
314
+ previewViewTypes: [
315
+ { text:'Mobile', value:'' },
316
+ { text:'Tablet', value:'md:' },
317
+ { text:'Desktop', value:'xl:' },
318
+ { text:'TV', value:'2xl:' },
319
+ ],
320
+ }
321
+ },
322
+
323
+ computed: {
324
+
325
+ availableComponents(){
326
+ return this.components
327
+ .sort((a, b) => a.type > b.type ? 1 : -1)
328
+ },
329
+
330
+ canSave(){
331
+ return this.prevData &&
332
+ (this.prevData.page !== JSON.stringify(this.page) ||
333
+ this.prevData.layout !== JSON.stringify(this.layout))
334
+ },
335
+
336
+ computedIframeSrc(){
337
+ return this.iframeSrc.substring(0, this.iframeSrc.indexOf('?'))
338
+ },
339
+
340
+ computedPreviewViewType(){
341
+ if(this.config.previewViewType === 'auto')
342
+ return this.config.viewType
343
+ return this.config.previewViewType
344
+ },
345
+
346
+ currentItem(){
347
+ if(Array.isArray(this.config.selectedComponent) && this.config.selectedComponent[0]){
348
+ return this.findCompByUid(this.config.selectedComponent[0], this.page.components)
349
+ }
350
+ },
351
+
352
+ expanded(){
353
+ if(!this.config.expanded)
354
+ this.config.expanded = {}
355
+ return this.config.expanded
356
+ },
357
+
358
+ iframeSize(){
359
+
360
+ let width, height
361
+ switch(this.computedPreviewViewType){
362
+ case '':
363
+ width = 390
364
+ height = 844
365
+ break
366
+
367
+ case 'md:':
368
+ width = 1024
369
+ height = 768
370
+ break
371
+
372
+ case 'xl:':
373
+ width = 1365
374
+ height = 768
375
+ break
376
+
377
+ case '2xl:':
378
+ width = 1920
379
+ height = 1080
380
+ break
381
+ }
382
+
383
+ return {
384
+ width,
385
+ height
386
+ }
387
+ },
388
+
389
+ leftBar(){
390
+ if(!this.config.leftBar){
391
+ this.config.leftBar = {
392
+ width: 360,
393
+ tabIndex: 2
394
+ }
395
+ }
396
+
397
+ return this.config.leftBar
398
+ },
399
+
400
+ previewClass(){
401
+ return {
402
+ 'overflow-auto': this.config.zoomLevel !== 'fit',
403
+ 'overflow-hidden': this.config.zoomLevel === 'fit',
404
+ }
405
+ },
406
+
407
+ rightBar(){
408
+ if(!this.config.rightBar){
409
+ this.config.rightBar = {
410
+ width: 360
411
+ }
412
+ }
413
+
414
+ return this.config.rightBar
415
+ },
416
+
417
+ section1Style(){
418
+ return {
419
+ width: this.leftBar.width + 'px'
420
+ }
421
+ },
422
+
423
+ section3Style(){
424
+ return {
425
+ width: this.rightBar.width + 'px'
426
+ }
427
+ },
428
+
429
+ },
430
+
431
+ methods: {
432
+
433
+ addComponent({ component, items, isLayout }){
434
+
435
+ Object.assign(component.props, {
436
+ enabled: true
437
+ })
438
+ this.setUid(component)
439
+
440
+ items.push(component)
441
+
442
+ this.config.selectedComponent = [ component.uid ]
443
+
444
+ this.$refs.webPageComponentSelector.close()
445
+ },
446
+
447
+ close(){
448
+ this.$emit('close')
449
+ },
450
+
451
+ findCompByUid(uid, components){
452
+
453
+ for(let i in components){
454
+ const comp = components[i]
455
+
456
+ if(comp.uid === uid){
457
+ return comp
458
+ }
459
+ else if(comp.items){
460
+ const c = this.findCompByUid(uid, comp.items)
461
+
462
+ if(c){
463
+ return c
464
+ }
465
+ }
466
+ }
467
+ },
468
+
469
+ onPostMessageToIframe(uid, data){
470
+ //this.$refs.iframe.contentWindow.postMessage({ uid, data }, '*')
471
+ },
472
+
473
+ updateIframe(){
474
+ if(!this.updating){
475
+ this.updating = true
476
+ return
477
+ }
478
+
479
+ if(this.$refs.iframe){
480
+
481
+ const headers = this.layout && Array.isArray(this.layout.headers) ?
482
+ this.layout.headers.map((_) => this.createComponentInstance(_)).filter(_=>_) :
483
+ null
484
+
485
+ const footers = this.layout && Array.isArray(this.layout.footers) ?
486
+ this.layout.footers.map((_) => this.createComponentInstance(_)).filter(_=>_) :
487
+ null
488
+
489
+ const components = (this.page.components ?? []).map((_) => this.createComponentInstance(_)).filter(_=>_)
490
+
491
+ const stylesheet = this.layout ? this.createStyleSheet(this.layout.styles) : ''
492
+
493
+ this.$refs.iframe.contentWindow.postMessage({
494
+ action:'update',
495
+ page: JSON.stringify({
496
+ headers,
497
+ footers,
498
+ components,
499
+ stylesheet,
500
+ data: this.page.data,
501
+ editMode: this.config.previewMode
502
+ })
503
+ }, '*')
504
+ }
505
+ },
506
+
507
+ openComponentSelector(params){
508
+ this.$refs.webPageComponentSelector.open(params)
509
+ },
510
+
511
+ reloadIframe(){
512
+
513
+ },
514
+
515
+ resize(){
516
+
517
+ const transformOrigin = this.computedPreviewViewType === '' ? 'center top' : '0 0'
518
+
519
+ switch(this.config.zoomLevel){
520
+
521
+ case 'fit':
522
+ if(this.$refs.preview){
523
+ const previewWidth = this.$refs.preview.clientWidth - 50
524
+ const previewHeight = this.$refs.preview.clientHeight - 70
525
+
526
+ let scale = 1
527
+ switch(this.computedPreviewViewType){
528
+
529
+ case 'md:':
530
+ scale = (previewWidth / 1024).toFixed(2)
531
+ break
532
+
533
+ case 'xl:':
534
+ scale = (previewWidth / 1365).toFixed(2)
535
+ break
536
+
537
+ case '2xl:':
538
+ scale = (previewWidth / 1920).toFixed(2)
539
+ break
540
+
541
+ default:
542
+ scale = (previewHeight / 844).toFixed(2)
543
+ break
544
+ }
545
+ console.log('scale', scale)
546
+
547
+ this.iframeStyle = {
548
+ 'transform': `scale(${scale})`,
549
+ '-webkit-transform': `scale(${scale})`,
550
+ '-moz-transform': `scale(${scale})`,
551
+ 'transform-origin': transformOrigin,
552
+ '-webkit-transform-origin': transformOrigin,
553
+ '-moz-transform-origin': transformOrigin
554
+ }
555
+ }
556
+ break
557
+
558
+ case '125%':
559
+ this.iframeStyle = {
560
+ 'transform': 'scale(1.25)',
561
+ '-webkit-transform': 'scale(1.25)',
562
+ '-moz-transform': 'scale(1.25)',
563
+ 'transform-origin': transformOrigin,
564
+ '-webkit-transform-origin': transformOrigin,
565
+ '-moz-transform-origin': transformOrigin
566
+ }
567
+ break
568
+
569
+ case '100%':
570
+ this.iframeStyle = {
571
+ 'transform': 'scale(1)',
572
+ '-webkit-transform': 'scale(1)',
573
+ '-moz-transform': 'scale(1)',
574
+ 'transform-origin': transformOrigin,
575
+ '-webkit-transform-origin': transformOrigin,
576
+ '-moz-transform-origin': transformOrigin
577
+ }
578
+ break
579
+
580
+ case '75%':
581
+ this.iframeStyle = {
582
+ 'transform': 'scale(.75)',
583
+ '-webkit-transform': 'scale(.75)',
584
+ '-moz-transform': 'scale(.75)',
585
+ 'transform-origin': transformOrigin,
586
+ '-webkit-transform-origin': transformOrigin,
587
+ '-moz-transform-origin': transformOrigin
588
+ }
589
+ break
590
+
591
+ case '50%':
592
+ this.iframeStyle = {
593
+ 'transform': 'scale(.5)',
594
+ '-webkit-transform': 'scale(.5)',
595
+ '-moz-transform': 'scale(.5)',
596
+ 'transform-origin': transformOrigin,
597
+ '-webkit-transform-origin': transformOrigin,
598
+ '-moz-transform-origin': transformOrigin
599
+ }
600
+ break
601
+
602
+ }
603
+ },
604
+
605
+ resize1(w){
606
+ if(this.leftBar.width + w >= 240){
607
+ this.leftBar.width += w
608
+ }
609
+ },
610
+
611
+ resize3(w){
612
+ if(this.rightBar.width - w >= 240){
613
+ this.rightBar.width -= w
614
+ }
615
+ },
616
+
617
+ save(){
618
+ this.$emit('save')
619
+ },
620
+
621
+ select(uid){
622
+ this.config.selectedComponent = [ uid ]
623
+ },
624
+
625
+ setUid(item){
626
+ item.uid = md5(Math.random())
627
+
628
+ if(Array.isArray(item.items)){
629
+ for(let subItem of item.items){
630
+ this.setUid(subItem)
631
+ }
632
+ }
633
+ },
634
+
635
+ },
636
+
637
+ mounted() {
638
+
639
+ Object.assign(this.config, Object.assign({
640
+ previewMode: 1,
641
+ version: '0.0.999',
642
+ layoutMode: false,
643
+ selectedComponent: null,
644
+ tabIndex: 2,
645
+ viewType: 'mobile',
646
+ previewViewType: '',
647
+ zoomLevel: 'fit',
648
+ width: [ 320, 320 ]
649
+ }, this.config))
650
+
651
+ this.$nextTick(() => {
652
+ this.resize()
653
+ })
654
+
655
+ }
656
+
657
+ }
658
+
659
+ </script>
660
+
661
+ <style module>
662
+
663
+ .comp{
664
+ @apply flex-1;
665
+ @apply hidden md:flex flex-row;
666
+ @apply divide-x divide-text-50;
667
+ }
668
+
669
+ .resize1{
670
+ @apply w-[3px] cursor-ew-resize;
671
+ }
672
+
673
+ .resize3{
674
+ @apply w-[3px] cursor-ew-resize;
675
+ }
676
+
677
+ .zoomLevel{
678
+ @apply appearance-none bg-base-400 text-center outline-none h-[24px] rounded-md;
679
+ @apply border-[1px] border-text-100;
680
+ }
681
+
682
+ </style>