@mixd-id/web-scaffold 0.1.230406113 → 0.1.230406114

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.230406113",
4
+ "version": "0.1.230406114",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -68,7 +68,10 @@ export default{
68
68
 
69
69
  if(this.state && this.state.title){
70
70
  if(typeof this.state.title === 'object'){
71
- if(this.state.title.type === 'ValidationError'){
71
+ if(this.state.title.response){
72
+ title = this.state.title.response.data.message
73
+ }
74
+ else if(this.state.title.type === 'ValidationError'){
72
75
  title = 'Validation error'
73
76
  }
74
77
  else if(this.state.title.status){
@@ -90,14 +93,20 @@ export default{
90
93
  let description
91
94
 
92
95
  if(this.state){
93
-
94
96
  if(typeof this.state.title === 'object'){
95
- if(this.state.title.type === 'ValidationError'){
97
+ if(this.state.title.response || this.state.title.type === 'ValidationError'){
98
+ const errors = this.state.title.response.data.errors ?? this.state.title.errors
99
+
96
100
  description = {}
97
- for(let key in this.state.title.errors){
98
- this.state.title.errors[key].forEach((text) => {
99
- description[text] = 1
100
- })
101
+ for(let key in errors){
102
+ if(Array.isArray(errors[key])){
103
+ errors[key].forEach((text) => {
104
+ description[text] = 1
105
+ })
106
+ }
107
+ else{
108
+ errors[errors[key]] = 1
109
+ }
101
110
  }
102
111
  description = Object.keys(description).join("\n")
103
112
  }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <button :class="compClass" :disabled="isDisabled" @click="onClick">
3
- <div>
3
+ <div :class="itemClass">
4
4
  <slot>{{ text }}</slot>
5
5
  </div>
6
6
  <div v-if="isLoading" :class="$style.loadingPane">
@@ -36,6 +36,8 @@ export default{
36
36
 
37
37
  target: String,
38
38
 
39
+ targetType: String,
40
+
39
41
  width: Array,
40
42
 
41
43
  },
@@ -98,9 +100,28 @@ export default{
98
100
 
99
101
  onClick(){
100
102
  if(this.target){
101
- this.$router.push(this.target)
103
+ switch(this.targetType){
104
+
105
+ case 'section':
106
+ this.scrollTo(this.target)
107
+ break
108
+
109
+ default:
110
+ this.$router.push(this.target)
111
+ break
112
+ }
102
113
  }
103
- }
114
+ },
115
+
116
+ scrollTo(exp){
117
+ const el = document.querySelector('._' + exp.substring(0, 4))
118
+ if(el){
119
+ window.scrollTo({
120
+ top: el.offsetTop - 100,
121
+ behavior: 'smooth'
122
+ });
123
+ }
124
+ },
104
125
 
105
126
  }
106
127
 
@@ -4,7 +4,12 @@
4
4
  <div v-if="typeof error.response.data.errors === 'string'">{{ error.response.data.errors }}</div>
5
5
  <div v-else v-for="(text, key) in error.response.data.errors">
6
6
  <div v-if="!errorKey || key === errorKey">
7
- <div v-for="txt in text">{{ txt }}</div>
7
+ <div v-if="Array.isArray(text)">
8
+ <div v-for="txt in text">{{ txt }}</div>
9
+ </div>
10
+ <div v-else>
11
+ {{ text }}
12
+ </div>
8
13
  </div>
9
14
  </div>
10
15
  </div>
@@ -49,4 +54,4 @@ export default{
49
54
  @apply text-red-500;
50
55
  }
51
56
 
52
- </style>
57
+ </style>
@@ -214,9 +214,7 @@ export default{
214
214
  reader.readAsDataURL(this.src)
215
215
  this.status = 1
216
216
  }
217
- else{
218
- this.actualSrc = this.defaultSrc
219
- }
217
+
220
218
  },
221
219
 
222
220
  onClick(){
@@ -14,7 +14,7 @@
14
14
  </div>
15
15
  <div class="h-[1px] bg-gray-200"></div>
16
16
  <div class="flex flex-row items-center gap-2">
17
- <Image class="w-[36px] aspect-square"
17
+ <Image class="w-[36px] aspect-square rounded-full"
18
18
  :src="imageSrc(item.imageUrl)" />
19
19
  <div class="flex-1 flex flex-col leading-tight">
20
20
  <div class="text-sm text-ellipsis overflow-hidden whitespace-nowrap">
@@ -62,11 +62,11 @@ export default{
62
62
  <style module>
63
63
 
64
64
  .comp{
65
- @apply flex-1 flex flex-col gap-4 bg-gray-100 overflow-hidden;
65
+ @apply flex-1 bg-gray-100 overflow-hidden;
66
66
  }
67
67
 
68
68
  .head{
69
- @apply text-center md:text-left;
69
+ @apply text-center md:text-left mb-6;
70
70
  }
71
71
 
72
72
  .container{
@@ -10,7 +10,7 @@
10
10
  <svg v-if="!childCollapsed" width="16" height="16" class="fill-text-300" 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>
11
11
  <svg v-else width="16" height="16" class="fill-text-300" 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>
12
12
  </button>
13
- <div v-else class="pl-1"></div>
13
+ <div v-else class="px-1"></div>
14
14
  <slot :item="item"></slot>
15
15
  <button type="button" class="py-2" @click="$emit('remove')">
16
16
  <svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z"/></svg>
@@ -113,12 +113,11 @@ export default{
113
113
 
114
114
  const rect = this.$el.getBoundingClientRect()
115
115
  const startX = e.clientX
116
- const startY = e.clientY
117
116
 
118
117
  const cloned = this.$el.cloneNode(true)
119
118
  cloned.style.position = 'absolute'
120
119
  cloned.style.left = rect.x + "px"
121
- cloned.style.top = rect.y + "px"
120
+ cloned.style.top = (e.clientY - 10) + "px"
122
121
  cloned.style.width = this.$el.clientWidth + "px"
123
122
  cloned.style.pointerEvents = 'none'
124
123
  document.body.appendChild(cloned)
@@ -130,9 +129,8 @@ export default{
130
129
 
131
130
  const mouseMove = (e) => {
132
131
  const distanceX = e.clientX - startX
133
- const distanceY = e.clientY - startY
134
132
  cloned.style.left = (rect.x + distanceX) + "px"
135
- cloned.style.top = (rect.y + distanceY) + "px"
133
+ cloned.style.top = (e.clientY - 10) + "px"
136
134
  }
137
135
 
138
136
  const mouseUp = (e) => {
@@ -0,0 +1,282 @@
1
+ <template>
2
+ <div @mouseover="hoverMouseOver"
3
+ @mouseout="hoverMouseOut"
4
+ @mouseup="hoverMouseUp">
5
+ <div ref="item" :class="itemClass"
6
+ @copy.stop.prevent="copy"
7
+ @mousedown="mouseDown">
8
+ <button type="button" class="py-2" v-if="Array.isArray((item ?? {}).items) && item.items.length > 0"
9
+ @click="childCollapsed = !childCollapsed">
10
+ <svg v-if="!childCollapsed" width="16" height="16" class="fill-text-300" 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>
11
+ <svg v-else width="16" height="16" class="fill-text-300" 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>
12
+ </button>
13
+ <div v-else class="pl-1"></div>
14
+ <slot :item="item"></slot>
15
+ <button type="button" class="py-2" @click="$emit('remove')">
16
+ <svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z"/></svg>
17
+ </button>
18
+ </div>
19
+ <div ref="container" v-if="item && Array.isArray(item.items) && !childCollapsed" class="ml-4">
20
+ <TreeViewItem v-for="(subItem, index) in item.items"
21
+ :item="subItem"
22
+ :parent="item.items"
23
+ :selected-item="selectedItem"
24
+ @moveup="moveUp(subItem)"
25
+ @movedown="moveDown(subItem)"
26
+ @remove="confirm($t('Remove this item?'), { onConfirm: () => { item.items.splice(index, 1);$emit('change') }})"
27
+ @add="(items) => $emit('add', items)"
28
+ @change="$emit('change')"
29
+ @paste.stop.prevent="(e) => paste(e, subItem)"
30
+ @item-paste="(p1, p2, p3) => $emit('item-paste', p1, p2, p3)">
31
+ <template #default="{ item }">
32
+ <slot :item="item"></slot>
33
+ </template>
34
+ </TreeViewItem>
35
+
36
+ <div class="flex flex-row items-center justify-center mb-2">
37
+ <button type="button" class="p-1 text-primary flex flex-row gap-1 items-center" @click="add">
38
+ <svg width="14" height="14" 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>
39
+ Add
40
+ </button>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
+ <script>
47
+
48
+ import {copyToClipboard} from "../utils/helpers.mjs";
49
+
50
+ const createGuide = () => {
51
+ const div = document.createElement('div')
52
+ div.classList.add('treeview-guide')
53
+ return div
54
+ }
55
+
56
+ let dragged = null
57
+ let guide1 = createGuide()
58
+ let guide2 = createGuide()
59
+
60
+ export default{
61
+
62
+ emits: [ 'add', 'change', 'moveup', 'movedown', 'remove', 'item-paste' ],
63
+
64
+ inject: [ 'confirm', 'toast' ],
65
+
66
+ props: {
67
+ item: Object,
68
+
69
+ parent: Array,
70
+
71
+ selectedItem: Object,
72
+
73
+ state: {
74
+ type: [ Number, String ],
75
+ default: 1
76
+ },
77
+ },
78
+
79
+ methods: {
80
+
81
+ copy(){
82
+ alert('cop')
83
+ copyToClipboard(JSON.stringify(this.item))
84
+ this.toast(this.item.type + ' copied')
85
+ },
86
+
87
+ paste(event, subItem){
88
+ const clipboardData = event.clipboardData || window.clipboardData;
89
+ const pastedText = clipboardData.getData('text');
90
+
91
+ try{
92
+ const newItem = JSON.parse(pastedText)
93
+ this.$emit('item-paste', this.item.items, subItem, newItem)
94
+ }
95
+ catch(e){
96
+
97
+ }
98
+ },
99
+
100
+ moveDown(item){
101
+ const idx = this.item.items.indexOf(item)
102
+ if(idx < this.item.items.length - 1){
103
+ this.item.items.splice(idx + 1, 0, this.item.items.splice(idx, 1)[0])
104
+ this.$emit('change')
105
+ }
106
+ },
107
+
108
+ moveUp(item){
109
+ const idx = this.item.items.indexOf(item)
110
+ if(idx - 1 >= 0){
111
+ this.item.items.splice(idx - 1, 0, this.item.items.splice(idx, 1)[0])
112
+ this.$emit('change')
113
+ }
114
+ },
115
+
116
+ add(){
117
+ this.$emit('add', this.item.items)
118
+ },
119
+
120
+ mouseDown(e){
121
+ e.preventDefault()
122
+
123
+ const rect = this.$el.getBoundingClientRect()
124
+ const startX = e.clientX
125
+ const startY = e.clientY
126
+
127
+ const cloned = this.$el.cloneNode(true)
128
+ cloned.style.position = 'absolute'
129
+ cloned.style.left = rect.x + "px"
130
+ cloned.style.top = rect.y + "px"
131
+ cloned.style.width = this.$el.clientWidth + "px"
132
+ cloned.style.pointerEvents = 'none'
133
+ cloned.style.opacity = '0.7'
134
+ document.body.appendChild(cloned)
135
+
136
+ dragged = {
137
+ item: this.item,
138
+ parent: this.parent
139
+ }
140
+
141
+ const mouseMove = (e) => {
142
+ const distanceX = e.clientX - startX
143
+ const distanceY = e.clientY - startY
144
+ cloned.style.left = (rect.x + distanceX) + "px"
145
+ cloned.style.top = (rect.y + distanceY) + "px"
146
+ }
147
+
148
+ const mouseUp = (e) => {
149
+ document.body.removeChild(cloned)
150
+ window.removeEventListener('mousemove', mouseMove)
151
+ window.removeEventListener('mouseup', mouseUp)
152
+ }
153
+
154
+ window.addEventListener('mousemove', mouseMove)
155
+ window.addEventListener('mouseup', mouseUp)
156
+ },
157
+
158
+ hoverMouseUp(e){
159
+
160
+ /*if(dragged && dragged.targetParent){
161
+ const targetIdx = dragged.targetParent.indexOf(dragged.target)
162
+ const startIdx = dragged.parent.indexOf(dragged.item)
163
+
164
+ if(targetIdx >= -1 && (targetIdx !== startIdx || dragged.parent !== dragged.targetParent)){
165
+
166
+ if(dragged.parent === dragged.targetParent){
167
+ dragged.parent.splice(targetIdx, 0, dragged.parent.splice(startIdx, 1)[0])
168
+ }
169
+ else{
170
+ dragged.targetParent.splice(targetIdx, 0, dragged.parent.splice(startIdx, 1)[0])
171
+ }
172
+
173
+ this.$emit('change')
174
+ }
175
+ }*/
176
+
177
+ if(this.$refs.item){
178
+ this.$refs.item.classList.remove(this.$style.itemMouseOver)
179
+ }
180
+ window.removeEventListener('mouseup', this.hoverMouseUp)
181
+ dragged = null
182
+
183
+ if(guide1.parentNode){
184
+ guide1.parentNode.removeChild(guide1)
185
+ }
186
+ if(guide2.parentNode){
187
+ guide2.parentNode.removeChild(guide2)
188
+ }
189
+ guide1.removeEventListener('mouseover', this.hoverMouseOver)
190
+ guide2.removeEventListener('mouseover', this.hoverMouseOver)
191
+ },
192
+
193
+ hoverMouseOver(e){
194
+
195
+ if(dragged && dragged.item !== this.item){
196
+ //this.$refs.item.classList.add(this.$style.itemMouseOver)
197
+
198
+ const parent = this.$refs.item.parentNode
199
+ parent.insertBefore(guide1, this.$el.firstElementChild)
200
+ parent.insertBefore(guide2, null)
201
+
202
+ guide1.addEventListener('mouseover', this.guideMouseOver)
203
+ guide2.addEventListener('mouseover', this.guideMouseOver)
204
+
205
+ /*dragged.target = this.item
206
+ dragged.targetParent = this.parent
207
+ window.addEventListener('mouseup', this.hoverMouseUp)*/
208
+ }
209
+
210
+ },
211
+
212
+ guideMouseOver(e){
213
+ console.log('guideMouseOver', e.target)
214
+ },
215
+
216
+ hoverMouseOut(e){
217
+
218
+ /*if(dragged){
219
+ this.$refs.item.classList.remove(this.$style.itemMouseOver)
220
+ delete dragged.target
221
+ delete dragged.targetParent
222
+ }*/
223
+
224
+ if(guide1.parentNode){
225
+ guide1.parentNode.removeChild(guide1)
226
+ }
227
+ if(guide2.parentNode){
228
+ guide2.parentNode.removeChild(guide2)
229
+ }
230
+ guide1.removeEventListener('mouseover', this.hoverMouseOver)
231
+ guide2.removeEventListener('mouseover', this.hoverMouseOver)
232
+ }
233
+
234
+ },
235
+
236
+ computed: {
237
+
238
+ itemClass(){
239
+ return [
240
+ this.$style.item,
241
+ this.selectedItem === this.item ? this.$style.active : '',
242
+ this.state === 3 ? this.$style.active : '',
243
+ ]
244
+ .filter(_=>_)
245
+ .join(' ')
246
+ }
247
+
248
+ },
249
+
250
+ data(){
251
+ return {
252
+ childCollapsed: false
253
+ }
254
+ }
255
+
256
+ }
257
+
258
+ </script>
259
+
260
+ <style>
261
+
262
+ .treeview-guide{
263
+ @apply w-full h-[5px] bg-primary my-1;
264
+ }
265
+
266
+ </style>
267
+
268
+ <style module>
269
+
270
+ .item{
271
+ @apply bg-base-300 dark:bg-base-400 flex flex-row gap-2 px-2 items-center rounded-lg mb-1;
272
+ @apply border-[1px] border-transparent cursor-pointer;
273
+ }
274
+ .item.active{
275
+ @apply border-primary;
276
+ }
277
+
278
+ .itemMouseOver{
279
+ @apply !bg-primary;
280
+ }
281
+
282
+ </style>
@@ -213,6 +213,26 @@ const copyToClipboard = function(obj){
213
213
  })
214
214
  }
215
215
 
216
+ const getComponentUids = function(components, excepts = []){
217
+
218
+ const arr = []
219
+
220
+ for(let comp of components){
221
+ if(!excepts.includes(comp.uid)){
222
+ arr.push({
223
+ uid: comp.uid,
224
+ name: comp.props.name ?? comp.type
225
+ })
226
+
227
+ if(Array.isArray(comp.items)){
228
+ arr.push(...getComponentUids(comp.items))
229
+ }
230
+ }
231
+ }
232
+
233
+ return arr
234
+ }
235
+
216
236
  export {
217
237
  downsizeImage,
218
238
  uid,
@@ -224,7 +244,8 @@ export {
224
244
  accessNestedObject,
225
245
  mediaPrefixes,
226
246
  _applyClass,
227
- copyToClipboard
247
+ copyToClipboard,
248
+ getComponentUids
228
249
  }
229
250
 
230
251
  function observeInit(){
@@ -8,7 +8,24 @@
8
8
 
9
9
  <div>
10
10
  <label class="flex-1 text-text-400">Target</label>
11
- <Textbox v-model="item.props.target" @keyup.enter="$emit('change')"/>
11
+ <div class="flex flex-row items-center gap-2">
12
+ <Dropdown class="w-[70px]"
13
+ v-model="item.props.targetType"
14
+ @change="item.props.target= ''; $emit('change')">
15
+ <option value="">URL</option>
16
+ <option value="section">Section</option>
17
+ </Dropdown>
18
+ <Dropdown v-if="item.props.targetType === 'section'"
19
+ v-model="item.props.target"
20
+ @change="$emit('change')"
21
+ class="flex-1">
22
+ <option value="" disabled>-Select-</option>
23
+ <option v-for="comp in compUids" :value="comp.uid">{{ comp.name }}</option>
24
+ </Dropdown>
25
+ <Textbox class="flex-1" v-else v-model="item.props.target"
26
+ @keyup.enter="$emit('change')"
27
+ @blur="$emit('change')"/>
28
+ </div>
12
29
  </div>
13
30
 
14
31
  <div>
@@ -35,6 +52,8 @@
35
52
 
36
53
  <script>
37
54
 
55
+ import {getComponentUids} from "../utils/helpers.mjs";
56
+
38
57
  export default{
39
58
 
40
59
  emits: [ 'change' ],
@@ -57,10 +76,21 @@ export default{
57
76
  }
58
77
  },
59
78
 
60
- inject: [ 'confirm', 'imageSrc' ],
79
+ inject: [ 'confirm', 'imageSrc', 'getPage' ],
61
80
 
62
- methods: {
81
+ computed: {
82
+
83
+ compUids(){
84
+ if(this.item.props.targetType === 'section'){
85
+ const page = this.getPage()
86
+ const components = page.components
87
+ return getComponentUids(components, [ this.item.uid ])
88
+ }
89
+ }
63
90
 
91
+ },
92
+
93
+ methods: {
64
94
 
65
95
  }
66
96
 
@@ -22,7 +22,7 @@
22
22
  <div class="flex flex-row gap-4" v-if="!page.isSystem">
23
23
  <div class="flex flex-col gap-1">
24
24
  <label class="text-text-400 w-[40px]">{{ $t('Active')}}</label>
25
- <Switch v-model="page.isActive" />
25
+ <Switch v-model="page.isActive" @change="save"/>
26
26
  </div>
27
27
 
28
28
  <div class="flex-1">