@mixd-id/web-scaffold 0.1.230406091 → 0.1.230406093

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 (50) hide show
  1. package/package.json +2 -1
  2. package/src/components/Ahref.vue +1 -1
  3. package/src/components/Article.vue +239 -9
  4. package/src/components/Block.vue +3 -25
  5. package/src/components/Box.vue +1 -14
  6. package/src/components/Button.vue +8 -5
  7. package/src/components/Carousel.vue +7 -17
  8. package/src/components/Flex.vue +6 -26
  9. package/src/components/Grid.vue +6 -28
  10. package/src/components/HTMLEditor.vue +86 -8
  11. package/src/components/Image.vue +4 -9
  12. package/src/components/Modal.vue +1 -1
  13. package/src/components/Table.vue +56 -0
  14. package/src/components/TextBlock.vue +1 -14
  15. package/src/components/TreeView.vue +4 -1
  16. package/src/components/TreeViewItem.vue +28 -6
  17. package/src/index.js +34 -9
  18. package/src/mixin/component.js +4 -7
  19. package/src/utils/selection.js +9 -6
  20. package/src/widgets/ArticleSetting.vue +176 -4
  21. package/src/widgets/CarouselItem.vue +4 -10
  22. package/src/widgets/CarouselSetting.vue +11 -11
  23. package/src/widgets/ComponentSetting.vue +81 -36
  24. package/src/widgets/ContactForm.vue +9 -24
  25. package/src/widgets/EmbeddedVideo.vue +10 -43
  26. package/src/widgets/EmbeddedVideoSetting.vue +0 -42
  27. package/src/widgets/FAQ.vue +1 -14
  28. package/src/widgets/FeatureList.vue +39 -25
  29. package/src/widgets/FeatureListSetting.vue +20 -4
  30. package/src/widgets/FlexItem.vue +3 -1
  31. package/src/widgets/FlexSetting.vue +1 -1
  32. package/src/widgets/GridItem.vue +2 -2
  33. package/src/widgets/GridSetting.vue +29 -4
  34. package/src/widgets/Header.vue +2 -14
  35. package/src/widgets/IconList.vue +1 -14
  36. package/src/widgets/IconListSetting.vue +11 -6
  37. package/src/widgets/ImageItem.vue +4 -10
  38. package/src/widgets/ImageSetting.vue +38 -9
  39. package/src/widgets/Share.vue +1 -9
  40. package/src/widgets/StyleSetting.vue +1 -1
  41. package/src/widgets/{ParagraphItem.vue → TableItem.vue} +1 -1
  42. package/src/widgets/TableSetting.vue +174 -0
  43. package/src/widgets/TextBlockSetting.vue +15 -9
  44. package/src/widgets/WebLayoutSelector.vue +376 -0
  45. package/src/widgets/WebPageBuilder.vue +491 -342
  46. package/src/widgets/WebPageSelector.vue +150 -0
  47. package/tailwind.config.js +2 -2
  48. package/src/components/CitySelector.vue +0 -59
  49. package/src/components/Paragraph.vue +0 -54
  50. package/src/widgets/ParagraphSetting.vue +0 -175
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.230406091",
4
+ "version": "0.1.230406093",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -12,6 +12,7 @@
12
12
  ".": "./src/index.js",
13
13
  "./themes/default": "./src/themes/default/index.js",
14
14
  "./mixin/component": "./src/mixin/component.js",
15
+ "./mixin/edit-mode": "./src/mixin/edit-mode.js",
15
16
  "./helpers": {
16
17
  "require": "./src/utils/helpers.js",
17
18
  "import": "./src/utils/helpers.mjs"
@@ -19,7 +19,7 @@ export default {
19
19
  computed: {
20
20
 
21
21
  isExternalLink() {
22
- return typeof this.href === 'string' && (this.href.startsWith('http') || this.href.startsWith('tel:'))
22
+ return typeof this.href === 'string' && this.href.indexOf('://') > 0
23
23
  }
24
24
  },
25
25
  }
@@ -1,10 +1,16 @@
1
1
  <template>
2
- <article :class="compClass" v-html="htmlText"></article>
2
+ <article :class="$style.comp"
3
+ v-html="htmlText"
4
+ :contenteditable="editable"
5
+ @input="onInput"
6
+ @click="onClick"
7
+ @paste="onPaste"></article>
3
8
  </template>
4
9
 
5
10
  <script>
6
11
 
7
12
  import { componentMixin } from '../mixin/component';
13
+ import { getSelection } from "../utils/selection";
8
14
 
9
15
  export default{
10
16
 
@@ -16,18 +22,230 @@ export default{
16
22
 
17
23
  },
18
24
 
19
- computed: {
25
+ methods: {
20
26
 
21
- compClass(){
22
- return [
23
- this.$style.comp,
24
- this.extClass
25
- ]
26
- .join(' ')
27
+ onInput(){
28
+ if(this.editable){
29
+ this.triggerUpdate()
30
+ }
27
31
  },
28
32
 
29
- }
33
+ onClick(){
34
+ if(this.editable){
35
+ let { element } = getSelection(this.$el)
36
+
37
+ const table = this.closest(element, 'table')
38
+
39
+ window.parent.postMessage({
40
+ uid: this.uid,
41
+ type: 'setSubAction',
42
+ value: table ? 'table' : ''
43
+ }, '*')
44
+ }
45
+ },
46
+
47
+ onPaste(e) {
48
+ e.preventDefault()
49
+ let text = (e.clipboardData || window.clipboardData).getData("text");
50
+ const el = document.createElement('div')
51
+ el.innerHTML = text
52
+ text = el.innerText
53
+ document.execCommand("insertText", false, text);
54
+ },
55
+
56
+ triggerUpdate(){
57
+ window.parent.postMessage({
58
+ uid: this.uid,
59
+ type: 'setProp',
60
+ value: {
61
+ htmlText: this.$el.innerHTML
62
+ }
63
+ }, '*')
64
+ },
65
+
66
+ closest(el, selector){
67
+ let parent = el.parentNode
68
+ while(parent){
69
+ if(parent === document) break
70
+
71
+ if(parent.matches(selector)){
72
+ return parent
73
+ }
74
+ parent = parent.parentNode
75
+ }
76
+ },
77
+
78
+ addTableColumn(){
79
+
80
+ let { element } = getSelection(this.$el)
81
+ if(element.nodeType !== 1)
82
+ element = element.parentNode
83
+ const table = this.closest(element, 'table')
84
+
85
+ if(table){
86
+ const thead = table.querySelector('thead')
87
+ const tbody = table.querySelector('tbody')
88
+ const tr = this.closest(element, 'tr')
89
+ const index = Array.from(tr.children).indexOf(element)
90
+
91
+ thead.querySelectorAll('tr').forEach(tr => {
92
+ const th = document.createElement('th')
93
+ th.innerHTML = "<i>insert header...</i>"
94
+ tr.insertBefore(th, tr.children[index + 1])
95
+ })
96
+
97
+ tbody.querySelectorAll('tr').forEach(tr => {
98
+ const td = document.createElement('td')
99
+ td.innerHTML = 'Content'
100
+ tr.insertBefore(td, tr.children[index + 1])
101
+ })
102
+
103
+ this.triggerUpdate()
104
+ }
105
+ },
106
+
107
+ addTableRow(){
108
+
109
+ let { element } = getSelection(this.$el)
110
+ if(element.nodeType !== 1)
111
+ element = element.parentNode
112
+ const table = this.closest(element, 'table')
113
+
114
+ if(table){
115
+ const tbody = table.querySelector('tbody')
116
+ const tr = this.closest(element, 'tr')
117
+ const index = Array.from(tbody.children).indexOf(tr)
118
+ if(index >= 0){
119
+ const nTr = document.createElement('tr')
120
+ for(let i = 0 ; i < tr.children.length ; i++){
121
+ const nTd = document.createElement('td')
122
+ nTd.innerHTML = 'Content'
123
+ nTr.appendChild(nTd)
124
+ }
125
+ tbody.insertBefore(nTr, tbody.children[index + 1])
126
+ this.triggerUpdate()
127
+ }
128
+ }
129
+ },
130
+
131
+ removeTableRow(){
132
+
133
+ let { element } = getSelection(this.$el)
134
+ if(element.nodeType !== 1)
135
+ element = element.parentNode
136
+ const table = this.closest(element, 'table')
137
+
138
+ if(table){
139
+ const tbody = table.querySelector('tbody')
140
+ const tr = this.closest(element, 'tr')
141
+ if(tr){
142
+ tbody.removeChild(tr)
143
+ this.triggerUpdate()
144
+ }
145
+ }
146
+ },
147
+
148
+ removeTableColumn(){
30
149
 
150
+ let { element } = getSelection(this.$el)
151
+ if(element.nodeType !== 1)
152
+ element = element.parentNode
153
+ const table = this.closest(element, 'table')
154
+
155
+ if(table) {
156
+ const thead = table.querySelector('thead')
157
+ const tbody = table.querySelector('tbody')
158
+ const tr = this.closest(element, 'tr')
159
+ const index = Array.from(tr.children).indexOf(element)
160
+
161
+ thead.querySelectorAll('tr').forEach(tr => {
162
+ tr.removeChild(tr.children[index])
163
+ })
164
+
165
+ tbody.querySelectorAll('tr').forEach(tr => {
166
+ tr.removeChild(tr.children[index])
167
+ })
168
+
169
+ this.triggerUpdate()
170
+ }
171
+ },
172
+
173
+ insertTable(){
174
+ document.execCommand('insertHTML', false,
175
+ `<table>
176
+ <thead>
177
+ <tr>
178
+ <th>Header</th>
179
+ <th>Header</th>
180
+ </tr>
181
+ </thead>
182
+ <tbody>
183
+ <tr>
184
+ <td>Content</td>
185
+ <td>Content</td>
186
+ </tr>
187
+ </tbody>
188
+ </table>`)
189
+ }
190
+
191
+ },
192
+
193
+ data(){
194
+ return {
195
+ editable: false
196
+ }
197
+ },
198
+
199
+ mounted() {
200
+ if('edit-mode' in this.$route.query){
201
+ window.addEventListener('message', ({ data }) => {
202
+ if(data.uid === this.uid){
203
+
204
+ const { action, type, value } = data.data
205
+
206
+ switch(action){
207
+
208
+ case 'insertTable':
209
+ this.insertTable()
210
+ break
211
+
212
+ case 'removeFormat':
213
+ document.execCommand('removeFormat', false);
214
+ break
215
+
216
+ case 'addTableColumn':
217
+ this.addTableColumn()
218
+ break
219
+
220
+ case 'addTableRow':
221
+ this.addTableRow()
222
+ break
223
+
224
+ case 'removeTableColumn':
225
+ this.removeTableColumn()
226
+ break
227
+
228
+ case 'removeTableRow':
229
+ this.removeTableRow()
230
+ break
231
+
232
+ case 'format':
233
+ switch(type){
234
+ case 'bold':
235
+ case 'italic':
236
+ default:
237
+ document.execCommand(type, false, value);
238
+ break
239
+ }
240
+ break
241
+
242
+ }
243
+
244
+ }
245
+ })
246
+ this.editable = true
247
+ }
248
+ }
31
249
 
32
250
  }
33
251
 
@@ -40,6 +258,9 @@ export default{
40
258
  }
41
259
  .comp *{
42
260
  }
261
+ .comp[contenteditable]{
262
+ @apply outline-none;
263
+ }
43
264
 
44
265
  .comp a{
45
266
  @apply text-primary underline;
@@ -60,6 +281,15 @@ font[size='5']{ @apply text-2xl; }
60
281
  font[size='6']{ @apply text-3xl; }
61
282
  font[size='7']{ @apply text-4xl; }
62
283
 
284
+ .comp table{
285
+ @apply border-[1px] border-text-200 border-collapse w-full;
286
+ table-layout: fixed;
287
+ }
288
+ .comp table th, .comp table td{
289
+ @apply border-[1px] border-text-200 p-3 text-left;
290
+ @apply break-words;
291
+ }
292
+
63
293
  @media screen(md){
64
294
  .comp{
65
295
  background-image: v-bind(bgImages[1]);
@@ -1,12 +1,8 @@
1
1
  <template>
2
- <div :class="compClass">
3
-
4
- <component v-for="item in computedItems"
2
+ <div :class="$style.comp">
3
+ <component v-for="item in items"
5
4
  :is="item.type"
6
- :uid="item.uid"
7
- :items="item.items"
8
- :="item.props" />
9
-
5
+ :="item" />
10
6
  </div>
11
7
  </template>
12
8
 
@@ -22,24 +18,6 @@ export default{
22
18
  class: String,
23
19
  items: Array,
24
20
  type: String,
25
- },
26
-
27
- computed: {
28
-
29
- computedItems() {
30
- return this.items.filter((_) => _.props.enabled)
31
- },
32
-
33
- compClass(){
34
- return [
35
- this.$style.comp,
36
- this.extClass,
37
- this.class ?? ''
38
- ]
39
- .filter(_ => _)
40
- .join(' ')
41
- }
42
-
43
21
  }
44
22
 
45
23
  }
@@ -1,6 +1,5 @@
1
1
  <template>
2
- <div :class="compClass">
3
- <br />
2
+ <div :class="$style.comp">
4
3
  <br />
5
4
  </div>
6
5
  </template>
@@ -20,18 +19,6 @@ export default{
20
19
  default: 'Box'
21
20
  }
22
21
 
23
- },
24
-
25
- computed: {
26
-
27
- compClass(){
28
- return [
29
- this.$style.comp,
30
- this.extClass
31
- ]
32
- .join(' ')
33
- },
34
-
35
22
  }
36
23
 
37
24
  }
@@ -22,8 +22,6 @@ export default{
22
22
 
23
23
  props: {
24
24
 
25
- class: String,
26
-
27
25
  variant: {
28
26
  type: [ String, Number ],
29
27
  default: "primary" // primary|secondary|outline, default:primary
@@ -49,9 +47,7 @@ export default{
49
47
  return [
50
48
  this.$style.button,
51
49
  this.$style['button-' + this.variant],
52
- parseInt(this.computedState) === 2 ? this.$style.loading : '',
53
- this.extClass,
54
- this.class ?? '',
50
+ parseInt(this.computedState) === 2 ? this.$style.loading : ''
55
51
  ]
56
52
  .filter(_ => _)
57
53
  .join(' ')
@@ -119,6 +115,7 @@ export default{
119
115
  @apply relative flex items-center justify-center;
120
116
  @apply whitespace-nowrap text-ellipsis overflow-hidden;
121
117
  @apply rounded-lg;
118
+ background-image: v-bind(bgImages[0]);
122
119
  }
123
120
  .button>*:first-child{
124
121
  @apply flex items-center justify-center
@@ -286,4 +283,10 @@ export default{
286
283
  @apply animate-spin h-5 w-5;
287
284
  }
288
285
 
286
+ @media screen(md){
287
+ .button{
288
+ background-image: v-bind(bgImages[1]);
289
+ }
290
+ }
291
+
289
292
  </style>
@@ -1,13 +1,11 @@
1
1
  <template>
2
- <div :class="compClass" @mousedown.prevent="mouseDown" @touchstart.passive="mouseDown">
2
+ <div :class="$style.comp" @mousedown.prevent="mouseDown" @touchstart.passive="mouseDown">
3
3
 
4
4
  <div ref="inner" :class="innerClass">
5
5
  <div v-for="item in items" :class="itemClass">
6
6
  <component :is="item.type"
7
- :uid="item.uid"
8
- :="item.props"
9
- :ratio="ratio"
10
- :ext-class="item.extClass" />
7
+ :="item"
8
+ @click.stop="editModeClick(item.uid)" />
11
9
  </div>
12
10
  </div>
13
11
 
@@ -41,6 +39,8 @@ import {componentMixin} from "../mixin/component";
41
39
 
42
40
  export default{
43
41
 
42
+ inject: [ 'editModeClick' ],
43
+
44
44
  mixins: [ componentMixin ],
45
45
 
46
46
  props:{
@@ -69,20 +69,9 @@ export default{
69
69
 
70
70
  computed: {
71
71
 
72
- compClass(){
73
- return [
74
- this.$style.comp,
75
- this.extClass
76
- ]
77
- .filter(_ => _)
78
- .join(' ')
79
- },
80
-
81
72
  innerClass(){
82
73
  return [
83
74
  this.$style.inner,
84
- 'aspect-[' + this.ratio[0] + ']',
85
- this.ratio[1] ? 'md:aspect-[' + this.ratio[1] + ']' : ''
86
75
  ]
87
76
  .filter(_ => _)
88
77
  .join(' ')
@@ -315,11 +304,12 @@ export default{
315
304
  white-space: nowrap;
316
305
  will-change: transform;
317
306
  touch-action: none;
318
- padding: v-bind(gaps[0]);
307
+ @apply flex flex-row items-stretch;
319
308
  }
320
309
  .inner>*{
321
310
  display: inline-block;
322
311
  width: 100%;
312
+ min-width: 100%;
323
313
  touch-action: none;
324
314
  vertical-align: top;
325
315
  }
@@ -1,13 +1,10 @@
1
1
  <template>
2
- <div :class="compClass" :style="computedStyle">
2
+ <div :class="$style.comp">
3
3
 
4
- <component v-for="(item, idx) in computedItems"
4
+ <component v-for="(item, idx) in items"
5
5
  :is="item.type"
6
- :uid="item.uid"
7
- :items="item.items"
8
- :="item.props"
9
- :ext-class="item.extClass"
10
- :class="itemClass(idx)" />
6
+ :="item"
7
+ @click.stop="editModeClick(item.uid)" />
11
8
 
12
9
  </div>
13
10
  </template>
@@ -18,6 +15,8 @@ import {componentMixin} from "../mixin/component";
18
15
 
19
16
  export default{
20
17
 
18
+ inject: [ 'editModeClick' ],
19
+
21
20
  mixins: [ componentMixin ],
22
21
 
23
22
  props:{
@@ -28,25 +27,6 @@ export default{
28
27
 
29
28
  methods: {
30
29
 
31
- itemClass(idx){
32
- return ((this.flexColumns ?? [])[idx] ?? []).join(' ')
33
- },
34
- },
35
-
36
- computed: {
37
-
38
- computedItems(){
39
- return this.items.filter((_) => _.props.enabled)
40
- },
41
-
42
- compClass(){
43
- return [
44
- this.$style.comp,
45
- this.extClass
46
- ]
47
- .join(' ')
48
- }
49
-
50
30
  }
51
31
 
52
32
  }
@@ -1,12 +1,10 @@
1
1
  <template>
2
- <div :class="compClass">
2
+ <div :class="$style.comp">
3
3
 
4
- <component v-for="item in computedItems"
4
+ <component v-for="item in items"
5
5
  :is="item.type"
6
- :uid="item.uid"
7
- :items="item.items"
8
- :="item.props"
9
- :ext-class="item.extClass" />
6
+ :="item"
7
+ @click.stop="editModeClick(item.uid)" />
10
8
 
11
9
  </div>
12
10
  </template>
@@ -17,32 +15,12 @@ import {componentMixin} from "../mixin/component";
17
15
 
18
16
  export default{
19
17
 
18
+ inject: [ 'editModeClick' ],
19
+
20
20
  mixins: [ componentMixin ],
21
21
 
22
22
  props:{
23
23
  items: Array
24
- },
25
-
26
- computed:{
27
-
28
- computedItems(){
29
- return this.items.filter((_) => _.props.enabled)
30
- },
31
-
32
- compClass(){
33
- return [
34
- this.$style.comp,
35
- this.extClass
36
- ]
37
- .filter(_=>_)
38
- .join(' ')
39
- }
40
-
41
- },
42
-
43
- methods: {
44
-
45
-
46
24
  }
47
25
 
48
26
  }