@mixd-id/web-scaffold 0.1.230406147 → 0.1.230406149

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.230406147",
4
+ "version": "0.1.230406149",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -22,7 +22,8 @@
22
22
  },
23
23
  "./importer": "./src/utils/importer.js",
24
24
  "./listpage1": "./src/utils/listpage1.js",
25
- "./listview": "./src/utils/listview.js"
25
+ "./listview": "./src/utils/listview.js",
26
+ "./web": "./src/utils/web.js"
26
27
  },
27
28
  "dependencies": {
28
29
  "@faker-js/faker": "^7.3.0",
@@ -104,17 +104,21 @@ export default{
104
104
  },
105
105
 
106
106
  title(){
107
- if(this.alert.title){
108
- return this.alert.title
107
+ const err = this.alert.response && this.alert.response.data ?
108
+ this.alert.response.data :
109
+ this.alert
110
+
111
+ if(err.title){
112
+ return err.title
109
113
  }
110
- else if(this.alert.name){
111
- return unPascalCase(this.alert.name)
114
+ else if(err.name){
115
+ return unPascalCase(err.name)
112
116
  }
113
- else if(this.alert.type){
114
- return unPascalCase(this.alert.type)
117
+ else if(err.type){
118
+ return unPascalCase(err.type)
115
119
  }
116
- else if(this.alert.status){
117
- return `Error ${this.alert.status}`
120
+ else if(err.status){
121
+ return `Error ${err.status}`
118
122
  }
119
123
  else{
120
124
  return this.$t('Alert')
@@ -122,7 +126,19 @@ export default{
122
126
  },
123
127
 
124
128
  message(){
125
- return this.alert.message ?? ''
129
+ const err = this.alert.response && this.alert.response.data ?
130
+ this.alert.response.data :
131
+ this.alert
132
+
133
+ if(err.errors){
134
+ return Object.values(err.errors).join("\n")
135
+ }
136
+ else if(err.message){
137
+ return err.message
138
+ }
139
+ else{
140
+ return ''
141
+ }
126
142
  },
127
143
 
128
144
  details(){
@@ -1,10 +1,12 @@
1
1
  <template>
2
- <article :class="$style.comp"
3
- v-html="htmlText"
4
- :contenteditable="editable"
5
- @input="onInput"
6
- @click="onClick"
7
- @paste="onPaste"></article>
2
+ <div :class="$style.comp">
3
+ <article :class="$style.article"
4
+ v-html="htmlText"
5
+ :contenteditable="editMode"
6
+ @input="onInput"
7
+ @click="onClick"
8
+ @paste="onPaste"></article>
9
+ </div>
8
10
  </template>
9
11
 
10
12
  <script>
@@ -46,13 +48,13 @@ export default{
46
48
  },
47
49
 
48
50
  onInput(){
49
- if(this.editable){
51
+ if(this.editMode){
50
52
  this.triggerUpdate()
51
53
  }
52
54
  },
53
55
 
54
56
  onClick(){
55
- if(this.editable){
57
+ if(this.editMode){
56
58
  let { element } = getSelection(this.$el)
57
59
 
58
60
  const table = this.closest(element, 'table')
@@ -211,18 +213,14 @@ export default{
211
213
 
212
214
  },
213
215
 
214
- data(){
215
- return {
216
- editable: false
217
- }
218
- },
219
-
220
216
  mounted() {
221
217
  if('edit-mode' in this.$route.query){
222
218
  window.addEventListener('message', (e) => {
223
219
 
224
220
  const { data, source } = e
225
221
 
222
+ if(!data || !source) return
223
+
226
224
  if(data.uid === this.uid){
227
225
 
228
226
  const { action, type, value } = data.data ?? {}
@@ -325,7 +323,6 @@ export default{
325
323
  }
326
324
 
327
325
  })
328
- this.editable = true
329
326
  }
330
327
  }
331
328
 
@@ -336,38 +333,42 @@ export default{
336
333
  <style module>
337
334
 
338
335
  .comp{
339
- background-image: v-bind(bgImages[0]);
336
+ @apply relative;
337
+ background-image: v-bind(bgImages[0]);
338
+ }
339
+
340
+ .article{
340
341
  }
341
- .comp *{
342
+ .article *{
342
343
  }
343
- .comp[contenteditable]{
344
+ .article[contenteditable]{
344
345
  @apply outline-none;
345
346
  }
346
347
 
347
- .comp a{
348
+ .article a{
348
349
  @apply text-primary underline;
349
350
  }
350
351
 
351
- .comp ul li{
352
+ .article ul li{
352
353
  @apply list-disc list-inside;
353
354
  }
354
- .comp ol li{
355
+ .article ol li{
355
356
  @apply list-decimal list-inside;
356
357
  }
357
358
 
358
- font[size='1']{ @apply text-xs; }
359
- font[size='2']{ @apply text-sm; }
360
- font[size='3']{ @apply text-lg; }
361
- font[size='4']{ @apply text-xl; }
362
- font[size='5']{ @apply text-2xl; }
363
- font[size='6']{ @apply text-3xl; }
364
- font[size='7']{ @apply text-4xl; }
359
+ .article font[size='1']{ @apply text-xs; }
360
+ .article font[size='2']{ @apply text-sm; }
361
+ .article font[size='3']{ @apply text-lg; }
362
+ .article font[size='4']{ @apply text-xl; }
363
+ .article font[size='5']{ @apply text-2xl; }
364
+ .article font[size='6']{ @apply text-3xl; }
365
+ .article font[size='7']{ @apply text-4xl; }
365
366
 
366
- .comp table{
367
+ .article table{
367
368
  @apply border-[1px] border-text-200 border-collapse w-full;
368
369
  table-layout: fixed;
369
370
  }
370
- .comp table th, .comp table td{
371
+ .article table th, .article table td{
371
372
  @apply border-[1px] border-text-200 p-3 text-left;
372
373
  @apply break-words;
373
374
  }
@@ -125,7 +125,7 @@ export default{
125
125
  }
126
126
  },
127
127
 
128
- }
128
+ },
129
129
 
130
130
  }
131
131
 
@@ -4,8 +4,7 @@
4
4
  <div ref="inner" :class="computedContainerClass">
5
5
  <div v-for="item in items" :class="computedItemClass">
6
6
  <component :is="item.type"
7
- :="item"
8
- @click.stop="editModeClick(item.uid)" />
7
+ :="item" />
9
8
  </div>
10
9
  </div>
11
10
 
@@ -39,8 +38,6 @@ import {componentMixin} from "../mixin/component";
39
38
 
40
39
  export default{
41
40
 
42
- inject: [ 'editModeClick' ],
43
-
44
41
  mixins: [ componentMixin ],
45
42
 
46
43
  props:{
@@ -3,8 +3,7 @@
3
3
 
4
4
  <component v-for="(item, idx) in items"
5
5
  :is="item.type"
6
- :="item"
7
- @click.stop="editModeClick(item.uid)" />
6
+ :="item" />
8
7
 
9
8
  </div>
10
9
  </template>
@@ -15,8 +14,6 @@ import {componentMixin} from "../mixin/component";
15
14
 
16
15
  export default{
17
16
 
18
- inject: [ 'editModeClick' ],
19
-
20
17
  mixins: [ componentMixin ],
21
18
 
22
19
  props:{
@@ -3,8 +3,7 @@
3
3
 
4
4
  <component v-for="item in items"
5
5
  :is="item.type"
6
- :="item"
7
- @click.stop="editModeClick(item.uid)" />
6
+ :="item" />
8
7
 
9
8
  </div>
10
9
  </template>
@@ -15,8 +14,6 @@ import {componentMixin} from "../mixin/component";
15
14
 
16
15
  export default{
17
16
 
18
- inject: [ 'editModeClick' ],
19
-
20
17
  mixins: [ componentMixin ],
21
18
 
22
19
  props:{
@@ -372,7 +372,8 @@ export default{
372
372
  },
373
373
 
374
374
  async loadConfig(){
375
- if(!this.configStoreObj || 'reset' in ((this.$route ?? {}).query ?? {})){
375
+ if(!this.configStoreObj ||
376
+ Object.keys(((this.$route ?? {}).query ?? {})).map(_ => _.toLowerCase()).includes('reset')){
376
377
  this.configLoaded = true
377
378
  if('reset' in ((this.$route ?? {}).query ?? {}))
378
379
  await this.saveConfig()
@@ -239,7 +239,7 @@ export default{
239
239
  }
240
240
 
241
241
  .modalBody{
242
- @apply flex-1 min-h-0 overflow-y-auto flex bg-base-400 dark:bg-base-300;
242
+ @apply flex-1 min-h-0 overflow-y-auto flex bg-base-400;
243
243
  }
244
244
 
245
245
  .overlay{
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div :class="computedClass">
3
- <button v-for="(item, index) in items" :class="tabClass(item)"
3
+ <button v-for="(item, index) in filteredItems" :class="tabClass(item)"
4
4
  @click="onClick(item)" type="button" >
5
5
  <slot v-if="$slots.tab" name="tab" :="{ item, index }"></slot>
6
6
  <div v-else :class="$style.item">
@@ -35,7 +35,11 @@ export default{
35
35
 
36
36
  computedClass(){
37
37
  return this.$style[this.variant]
38
- }
38
+ },
39
+
40
+ filteredItems(){
41
+ return this.items.filter(_=>_)
42
+ }
39
43
 
40
44
  },
41
45
 
@@ -79,7 +83,7 @@ export default{
79
83
  }
80
84
 
81
85
  .item{
82
- @apply whitespace-nowrap overflow-hidden;
86
+ @apply whitespace-nowrap overflow-hidden p-0.5;
83
87
  }
84
88
 
85
89
  .button{
package/src/index.js CHANGED
@@ -332,6 +332,7 @@ export default{
332
332
  app.config.globalProperties.warn = consoleWarn
333
333
  app.config.globalProperties.info = consoleInfo
334
334
 
335
+ app.component('Ahref', defineAsyncComponent(() => import("./components/Ahref.vue")))
335
336
  app.component('Alert', defineAsyncComponent(() => import("./components/Alert.vue")))
336
337
  app.component('Article', defineAsyncComponent(() => import("./components/Article.vue")))
337
338
  app.component('Block', defineAsyncComponent(() => import("./components/Block.vue")))
@@ -352,7 +353,6 @@ export default{
352
353
  app.component('Feed', defineAsyncComponent(() => import("./components/Feed.vue")))
353
354
  app.component('Gmaps', defineAsyncComponent(() => import("./components/Gmaps.vue")))
354
355
  app.component('HTMLEditor', defineAsyncComponent(() => import("./components/HTMLEditor.vue")))
355
- app.component('Ahref', defineAsyncComponent(() => import("./components/Ahref.vue")))
356
356
  app.component('Switch', defineAsyncComponent(() => import("./components/Switch.vue")))
357
357
  app.component('IconMenu', defineAsyncComponent(() => import("./components/IconMenu.vue")))
358
358
  app.component('IconMenu2', defineAsyncComponent(() => import("./components/IconMenu2.vue")))
@@ -402,22 +402,19 @@ export default{
402
402
  app.component('TextBlock', defineAsyncComponent(() => import("./components/TextBlock.vue")))
403
403
  app.component('TextEditor', defineAsyncComponent(() => import("./components/TextEditor.vue")))
404
404
 
405
- app.component('WebPageBuilder', defineAsyncComponent(() => import("./widgets/WebPageBuilder.vue")))
406
- app.component('WebPageSelector', defineAsyncComponent(() => import("./widgets/WebPageSelector.vue")))
407
- app.component('WebLayoutSelector', defineAsyncComponent(() => import("./widgets/WebLayoutSelector.vue")))
408
- app.component('ComponentSetting', defineAsyncComponent(() => import("./widgets/ComponentSetting.vue")))
405
+ app.component('AhrefItem', defineAsyncComponent(() => import("./widgets/AhrefItem.vue")))
406
+ app.component('AhrefSetting', defineAsyncComponent(() => import("./widgets/AhrefSetting.vue")))
409
407
  app.component('ArticleItem', defineAsyncComponent(() => import("./widgets/ArticleItem.vue")))
410
408
  app.component('ArticleSetting', defineAsyncComponent(() => import("./widgets/ArticleSetting.vue")))
411
409
  app.component('BlockItem', defineAsyncComponent(() => import("./widgets/BlockItem.vue")))
412
410
  app.component('BlockSetting', defineAsyncComponent(() => import("./widgets/BlockSetting.vue")))
413
411
  app.component('BoxItem', defineAsyncComponent(() => import("./widgets/BoxItem.vue")))
414
412
  app.component('BoxSetting', defineAsyncComponent(() => import("./widgets/BoxSetting.vue")))
415
- app.component('AhrefItem', defineAsyncComponent(() => import("./widgets/AhrefItem.vue")))
416
- app.component('AhrefSetting', defineAsyncComponent(() => import("./widgets/AhrefSetting.vue")))
417
413
  app.component('ButtonItem', defineAsyncComponent(() => import("./widgets/ButtonItem.vue")))
418
414
  app.component('ButtonSetting', defineAsyncComponent(() => import("./widgets/ButtonSetting.vue")))
419
415
  app.component('CarouselItem', defineAsyncComponent(() => import("./widgets/CarouselItem.vue")))
420
416
  app.component('CarouselSetting', defineAsyncComponent(() => import("./widgets/CarouselSetting.vue")))
417
+ app.component('ComponentSetting', defineAsyncComponent(() => import("./widgets/ComponentSetting.vue")))
421
418
  app.component('ContactForm', defineAsyncComponent(() => import("./widgets/ContactForm.vue")))
422
419
  app.component('ContactFormItem', defineAsyncComponent(() => import("./widgets/ContactFormItem.vue")))
423
420
  app.component('ContactFormSetting', defineAsyncComponent(() => import("./widgets/ContactFormSetting.vue")))
@@ -457,5 +454,10 @@ export default{
457
454
  app.component('TestimonialSetting', defineAsyncComponent(() => import("./widgets/TestimonialSetting.vue")))
458
455
  app.component('TextBlockItem', defineAsyncComponent(() => import("./widgets/TextBlockItem.vue")))
459
456
  app.component('TextBlockSetting', defineAsyncComponent(() => import("./widgets/TextBlockSetting.vue")))
457
+ app.component('WebPageBuilder', defineAsyncComponent(() => import("./widgets/WebPageBuilder.vue")))
458
+ app.component('WebComponentSelector', defineAsyncComponent(() => import("./widgets/WebComponentSelector.vue")))
459
+ app.component('WebDatasourceSelector', defineAsyncComponent(() => import("./widgets/WebDatasourceSelector.vue")))
460
+ app.component('WebPageSelector', defineAsyncComponent(() => import("./widgets/WebPageSelector.vue")))
461
+ app.component('WebLayoutSelector', defineAsyncComponent(() => import("./widgets/WebLayoutSelector.vue")))
460
462
  }
461
463
  }
@@ -1,4 +1,6 @@
1
1
  // mixin/component.js
2
+ import { inject } from 'vue'
3
+ import {parseBoolean} from "../utils/helpers.mjs";
2
4
 
3
5
  export const componentMixin = {
4
6
 
@@ -46,7 +48,12 @@ export const componentMixin = {
46
48
  opacity: Array,
47
49
 
48
50
  containerClass: String,
49
- itemClass: String
51
+ itemClass: String,
52
+
53
+ editSelectable: {
54
+ type: undefined,
55
+ default: true
56
+ },
50
57
  },
51
58
 
52
59
  computed: {
@@ -63,7 +70,7 @@ export const componentMixin = {
63
70
  (this.bgImage && this.bgImage[0] && this.bgImage[0].imageUrl ?
64
71
  `url('${import.meta.env.VITE_IMAGE_HOST + '/' + this.bgImage[0].imageUrl}')` : '')
65
72
  ]
66
- }
73
+ },
67
74
 
68
75
  },
69
76
 
@@ -72,7 +79,53 @@ export const componentMixin = {
72
79
  imageSrc(src){
73
80
  return typeof src === 'string' ?
74
81
  import.meta.env.VITE_IMAGE_HOST + '/' + src : src
82
+ },
83
+
84
+ componentClick(e){
85
+ e.stopPropagation()
86
+ e.preventDefault()
87
+
88
+ this.editModeClick ? this.editModeClick(this.uid) : null
89
+ },
90
+
91
+ componentMouseOver(e){
92
+ //e.stopPropagation()
93
+ //e.preventDefault()
94
+
95
+ //this.lastStyle.position = this.$el.style.position
96
+ //this.$el.style.position = 'relative'
97
+
98
+ //this.$el.appendChild(this.getGuide())
99
+ },
100
+
101
+ componentMouseOut(e){
102
+ //this.$el.style.position = this.lastStyle.position
103
+ },
104
+
105
+ },
106
+
107
+ data(){
108
+ return {
109
+ editMode: false,
110
+ lastStyle: {}
75
111
  }
112
+ },
113
+
114
+ mounted(){
115
+ if('edit-mode' in this.$route.query){
116
+ this.editMode = true
117
+ this.editModeClick = inject('editModeClick', () => {})
118
+
119
+ if(parseBoolean(this.editSelectable)){
120
+ this.$el.addEventListener('click', this.componentClick)
121
+ this.$el.addEventListener('mouseover', this.componentMouseOver)
122
+ this.$el.addEventListener('mouseout', this.componentMouseOut)
123
+ }
124
+ }
125
+ },
126
+
127
+ unmounted() {
128
+ this.$el.removeEventListener('click', this.componentClick)
129
+ },
76
130
 
77
- }
78
131
  };
@@ -255,8 +255,8 @@ let ListView = {
255
255
  }
256
256
 
257
257
  let attributes = { id:1, updatedAt:1 }
258
+ let modelAttributes = this.model.getAttributes();
258
259
  if(preset.columns){
259
- let modelAttributes = this.model.getAttributes();
260
260
  preset.columns.forEach((column) => {
261
261
  if(column.visible && modelAttributes[column.key]){
262
262
  attributes[column.key] = 1
@@ -281,7 +281,15 @@ let ListView = {
281
281
  }
282
282
  attributes = Object.keys(attributes)
283
283
 
284
- if(preset.filters){
284
+ if(preset.search && modelAttributes['tag']){
285
+ const tableName = this.model.name
286
+ where = {
287
+ ...where,
288
+ [Op.and]: Sequelize.literal(`MATCH(\`${tableName}\`.tag) AGAINST (? IN BOOLEAN MODE)`)
289
+ }
290
+ replacements.push(preset.search)
291
+ }
292
+ else if(preset.filters){
285
293
  const { where:presetWhere } = this.getPresetFilterParams(preset, includes)
286
294
  where = {
287
295
  ...where,
@@ -303,15 +311,6 @@ let ListView = {
303
311
  }
304
312
  }
305
313
 
306
- if(preset.search){
307
- const tableName = this.model.name
308
- where = {
309
- ...where,
310
- [Op.and]: Sequelize.literal(`MATCH(\`${tableName}\`.tag) AGAINST (? IN BOOLEAN MODE)`)
311
- }
312
- replacements.push(preset.search)
313
- }
314
-
315
314
  if(afterItem){
316
315
  const sortWhere = getPresetSortWhereParams(order, afterItem)
317
316
  where = {
@@ -0,0 +1,48 @@
1
+ const { accessNestedObject } = require("./helpers");
2
+
3
+ const applyDatasourceReplacer = (value, datasource) => {
4
+ let matches = value.match(/\{([^}]+)\}/g);
5
+ (matches ?? []).forEach(matchKey => {
6
+ matchKey = matchKey.slice(1, -1)
7
+ const matchValue = accessNestedObject(datasource, matchKey) ?? ''
8
+ value = value.replace(`{${matchKey}}`, matchValue, 'gi')
9
+ });
10
+
11
+ return value
12
+ }
13
+
14
+ const applyDatasource = async (items, datasource, keys = [ 'htmlText', 'text' ]) => {
15
+
16
+ for(let idx in items){
17
+ const item = items[idx]
18
+
19
+ for(let key of keys){
20
+
21
+ // Replace array type value
22
+ if(Array.isArray(item[key])){
23
+ for(let itemIdx in item[key]){
24
+ item[key][itemIdx] = applyDatasourceReplacer(item[key][itemIdx], datasource)
25
+ }
26
+ }
27
+
28
+ // Replace primitive type value
29
+ else if(item[key]){
30
+ item[key] = applyDatasourceReplacer(item[key], datasource)
31
+ }
32
+ }
33
+
34
+ // Iterate child items
35
+ if(Array.isArray(item.items)){
36
+ item.items = await applyDatasource(item.items, datasource, keys)
37
+ }
38
+
39
+ items[idx] = item
40
+ }
41
+
42
+ return items
43
+ }
44
+
45
+ module.exports = {
46
+ applyDatasource,
47
+ applyDatasourceReplacer
48
+ }