@mixd-id/web-scaffold 0.1.230406042 → 0.1.230406043
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
|
@@ -133,10 +133,7 @@ export default{
|
|
|
133
133
|
default: ''
|
|
134
134
|
},
|
|
135
135
|
|
|
136
|
-
modelValue:
|
|
137
|
-
type: String,
|
|
138
|
-
default: currentDate
|
|
139
|
-
}
|
|
136
|
+
modelValue:String
|
|
140
137
|
|
|
141
138
|
},
|
|
142
139
|
|
|
@@ -309,4 +306,4 @@ export default{
|
|
|
309
306
|
@apply bg-primary;
|
|
310
307
|
}
|
|
311
308
|
|
|
312
|
-
</style>
|
|
309
|
+
</style>
|
|
@@ -1,23 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="$style.comp" v-if="true || configLoaded">
|
|
3
3
|
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<button type="button">
|
|
8
|
-
<
|
|
9
|
-
|
|
4
|
+
<slot v-if="$slots.head" name="head"></slot>
|
|
5
|
+
<div v-else class="flex flex-row items-center gap-4">
|
|
6
|
+
<div class="flex flex-row gap-1">
|
|
7
|
+
<button type="button" class="flex flex-row gap-1 items-center">
|
|
8
|
+
<h3>{{ title }}</h3>
|
|
9
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-primary" 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>
|
|
10
|
+
</button>
|
|
11
|
+
<button type="button" @click="$refs.setting.open()">
|
|
12
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M452.515 237l31.843-18.382c9.426-5.441 13.996-16.542 11.177-27.054-11.404-42.531-33.842-80.547-64.058-110.797-7.68-7.688-19.575-9.246-28.985-3.811l-31.785 18.358a196.276 196.276 0 0 0-32.899-19.02V39.541a24.016 24.016 0 0 0-17.842-23.206c-41.761-11.107-86.117-11.121-127.93-.001-10.519 2.798-17.844 12.321-17.844 23.206v36.753a196.276 196.276 0 0 0-32.899 19.02l-31.785-18.358c-9.41-5.435-21.305-3.877-28.985 3.811-30.216 30.25-52.654 68.265-64.058 110.797-2.819 10.512 1.751 21.613 11.177 27.054L59.485 237a197.715 197.715 0 0 0 0 37.999l-31.843 18.382c-9.426 5.441-13.996 16.542-11.177 27.054 11.404 42.531 33.842 80.547 64.058 110.797 7.68 7.688 19.575 9.246 28.985 3.811l31.785-18.358a196.202 196.202 0 0 0 32.899 19.019v36.753a24.016 24.016 0 0 0 17.842 23.206c41.761 11.107 86.117 11.122 127.93.001 10.519-2.798 17.844-12.321 17.844-23.206v-36.753a196.34 196.34 0 0 0 32.899-19.019l31.785 18.358c9.41 5.435 21.305 3.877 28.985-3.811 30.216-30.25 52.654-68.266 64.058-110.797 2.819-10.512-1.751-21.613-11.177-27.054L452.515 275c1.22-12.65 1.22-25.35 0-38zm-52.679 63.019l43.819 25.289a200.138 200.138 0 0 1-33.849 58.528l-43.829-25.309c-31.984 27.397-36.659 30.077-76.168 44.029v50.599a200.917 200.917 0 0 1-67.618 0v-50.599c-39.504-13.95-44.196-16.642-76.168-44.029l-43.829 25.309a200.15 200.15 0 0 1-33.849-58.528l43.819-25.289c-7.63-41.299-7.634-46.719 0-88.038l-43.819-25.289c7.85-21.229 19.31-41.049 33.849-58.529l43.829 25.309c31.984-27.397 36.66-30.078 76.168-44.029V58.845a200.917 200.917 0 0 1 67.618 0v50.599c39.504 13.95 44.196 16.642 76.168 44.029l43.829-25.309a200.143 200.143 0 0 1 33.849 58.529l-43.819 25.289c7.631 41.3 7.634 46.718 0 88.037zM256 160c-52.935 0-96 43.065-96 96s43.065 96 96 96 96-43.065 96-96-43.065-96-96-96zm0 144c-26.468 0-48-21.532-48-48 0-26.467 21.532-48 48-48s48 21.533 48 48c0 26.468-21.532 48-48 48z"/></svg>
|
|
13
|
+
</button>
|
|
14
|
+
|
|
15
|
+
<Modal ref="setting" width="680" height="560">
|
|
16
|
+
<template #head>
|
|
17
|
+
<div class="relative">
|
|
18
|
+
<div class="absolute top-0 right-0 p-2">
|
|
19
|
+
<button type="button" class="p-2" @click="$refs.setting.close()">
|
|
20
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
21
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
22
|
+
</svg>
|
|
23
|
+
</button>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
<ListViewSettings class="flex-1"
|
|
28
|
+
:config="config"
|
|
29
|
+
@change="load" />
|
|
30
|
+
</Modal>
|
|
10
31
|
</div>
|
|
11
|
-
<Textbox placeholder="Cari..." :clearable="true" @clear="clearSearch" v-model="preset.search"
|
|
12
|
-
@keyup.enter="load">
|
|
13
32
|
|
|
33
|
+
<div class="flex-1">
|
|
34
|
+
<slot name="headerOpt"></slot>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<Textbox :placeholder="$t('Search...')" :clearable="true" @clear="clearSearch" v-model="preset.search"
|
|
38
|
+
@keyup.enter="load" :class="$style.searchBox">
|
|
39
|
+
<template #start>
|
|
40
|
+
<div class="pl-2">
|
|
41
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 481.6l-129-129c-2.3-2.3-5.3-3.5-8.5-3.5h-10.3C395 312 416 262.5 416 208 416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c54.5 0 104-21 141.1-55.2V371c0 3.2 1.3 6.2 3.5 8.5l129 129c4.7 4.7 12.3 4.7 17 0l9.9-9.9c4.7-4.7 4.7-12.3 0-17zM208 384c-97.3 0-176-78.7-176-176S110.7 32 208 32s176 78.7 176 176-78.7 176-176 176z"/></svg>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
14
44
|
</Textbox>
|
|
15
45
|
</div>
|
|
16
46
|
|
|
17
47
|
<VirtualTable ref="table1" :columns="presetColumns" :items="items" class="flex-1"
|
|
18
48
|
@scroll-end="loadNext">
|
|
19
49
|
<template v-for="column in presetColumns" #[colOf(column.key)]="{}">
|
|
20
|
-
<div :class="getHeader(column)">
|
|
50
|
+
<div :class="getHeader(column)" @click="openColumnOptions(column.key, $event.target.closest('.' + $style.header))">
|
|
21
51
|
<div>
|
|
22
52
|
{{ column.label ?? column.key }}
|
|
23
53
|
</div>
|
|
@@ -49,24 +79,38 @@
|
|
|
49
79
|
</template>
|
|
50
80
|
</VirtualTable>
|
|
51
81
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
82
|
+
<ContextMenu ref="columnMenu" :dismiss="false">
|
|
83
|
+
<div class="flex-1 flex flex-col w-[270px] p-3">
|
|
84
|
+
<div class="flex flex-col">
|
|
85
|
+
<div class="flex flex-row gap-2 items-center">
|
|
86
|
+
<div class="p-2 text-text-300 flex-1">Sort By</div>
|
|
87
|
+
<div class="text-primary cursor-pointer text-sm" @click="openPreset('sort');$refs.columnMenu.close()">Sort Options</div>
|
|
88
|
+
</div>
|
|
89
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="setSortCurrent(1)">Sort Ascending</div>
|
|
90
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="setSortCurrent(2)">Sort Descending</div>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="h-[1px] bg-text-50 my-2"></div>
|
|
93
|
+
<div class="flex flex-col">
|
|
94
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="hide">Hide</div>
|
|
95
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="openPreset();$refs.columnMenu.close()">Column Options</div>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="h-[1px] bg-text-50 my-2"></div>
|
|
98
|
+
<div class="flex flex-col">
|
|
99
|
+
<div class="flex flex-row gap-2 items-center">
|
|
100
|
+
<div class="p-2 text-text-300 flex-1">Filters</div>
|
|
101
|
+
<div class="text-primary cursor-pointer text-sm" @click="openPreset('filter');$refs.columnMenu.close()">Filter Options</div>
|
|
102
|
+
</div>
|
|
103
|
+
<div v-if="presetCurrentFilters.length > 0">
|
|
104
|
+
<ListPage1Filter v-if="preset.filters" v-for="filter in presetCurrentFilters"
|
|
105
|
+
:filter="filter" :column="config.columns[filter.key]"
|
|
106
|
+
@remove="removeFilter(filter)" @change="load" />
|
|
107
|
+
</div>
|
|
108
|
+
<div v-else>
|
|
109
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click.stop="addCurrentFilter">Add Filter</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</ContextMenu>
|
|
70
114
|
|
|
71
115
|
</div>
|
|
72
116
|
</template>
|
|
@@ -74,8 +118,11 @@
|
|
|
74
118
|
<script>
|
|
75
119
|
|
|
76
120
|
import throttle from "lodash/throttle";
|
|
121
|
+
import VirtualTable from "./VirtualTable.vue";
|
|
122
|
+
|
|
77
123
|
|
|
78
124
|
export default{
|
|
125
|
+
components: {VirtualTable},
|
|
79
126
|
|
|
80
127
|
emits: [ ],
|
|
81
128
|
|
|
@@ -92,6 +139,7 @@ export default{
|
|
|
92
139
|
defaultValue: {}
|
|
93
140
|
},
|
|
94
141
|
configStore: String,
|
|
142
|
+
subscription: String,
|
|
95
143
|
|
|
96
144
|
title: String
|
|
97
145
|
|
|
@@ -99,6 +147,38 @@ export default{
|
|
|
99
147
|
|
|
100
148
|
methods: {
|
|
101
149
|
|
|
150
|
+
addCurrentFilter(){
|
|
151
|
+
this.addFilter(this.selectedColumn)
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
addFilter(key){
|
|
155
|
+
|
|
156
|
+
const column = this.config.columns[key]
|
|
157
|
+
|
|
158
|
+
if(!this.preset.filters){
|
|
159
|
+
this.preset.filters = []
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let filters = [{}]
|
|
163
|
+
switch(column.type){
|
|
164
|
+
case 'date':
|
|
165
|
+
case 'enum':
|
|
166
|
+
filters = [{ value:[] }]
|
|
167
|
+
break
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.preset.filters.push({
|
|
171
|
+
enabled: true,
|
|
172
|
+
key: column.key,
|
|
173
|
+
label: column.label,
|
|
174
|
+
type: column.type,
|
|
175
|
+
typeParams: column.typeParams,
|
|
176
|
+
filters
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
this.presetFilterSelector = null
|
|
180
|
+
},
|
|
181
|
+
|
|
102
182
|
clearSearch(){
|
|
103
183
|
this.preset.search = ''
|
|
104
184
|
this.load()
|
|
@@ -118,6 +198,12 @@ export default{
|
|
|
118
198
|
.join(' ')
|
|
119
199
|
},
|
|
120
200
|
|
|
201
|
+
hide(){
|
|
202
|
+
const idx = this.preset.columns.findIndex((_) => _.key === this.selectedColumn)
|
|
203
|
+
this.preset.columns[idx].visible = false
|
|
204
|
+
this.$refs.columnMenu.close()
|
|
205
|
+
},
|
|
206
|
+
|
|
121
207
|
load(){
|
|
122
208
|
if(!this.src) return
|
|
123
209
|
|
|
@@ -146,9 +232,12 @@ export default{
|
|
|
146
232
|
},
|
|
147
233
|
|
|
148
234
|
async loadConfig(){
|
|
235
|
+
if(!this.configStoreObj) return
|
|
236
|
+
|
|
149
237
|
switch(this.configStoreObj.type){
|
|
150
238
|
case 'socket':
|
|
151
|
-
return this.socketEmit2(this.configStoreObj.src,
|
|
239
|
+
return this.socketEmit2(this.configStoreObj.src,
|
|
240
|
+
{ key:this.configStoreObj.name ?? 'ListView' })
|
|
152
241
|
.then((config) => {
|
|
153
242
|
Object.assign(this.config, config ?? {})
|
|
154
243
|
this.configLoaded = true
|
|
@@ -156,30 +245,108 @@ export default{
|
|
|
156
245
|
}
|
|
157
246
|
},
|
|
158
247
|
|
|
248
|
+
onHooks(model, event, items){
|
|
249
|
+
console.log('onHooks', model, event, items)
|
|
250
|
+
if(model === this.subscriptionObj.model){
|
|
251
|
+
switch(event){
|
|
252
|
+
|
|
253
|
+
case 'create':
|
|
254
|
+
case 'update':
|
|
255
|
+
items.forEach((item) => {
|
|
256
|
+
this.$util.unshift(this.items, item)
|
|
257
|
+
})
|
|
258
|
+
break
|
|
259
|
+
|
|
260
|
+
case 'remove':
|
|
261
|
+
case 'destroy':
|
|
262
|
+
items.forEach((item) => {
|
|
263
|
+
const idx = this.items.findIndex((_) => _.id === item.id)
|
|
264
|
+
if(idx >= 0){
|
|
265
|
+
this.items.splice(idx, 1)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
openColumnOptions(key, target){
|
|
274
|
+
this.selectedColumn = key
|
|
275
|
+
this.$refs.columnMenu.open(target)
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
openPreset(tab){
|
|
279
|
+
this.$refs.setting.open()
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
removeFilter(filter){
|
|
283
|
+
this.preset.filters.splice(this.preset.filters.indexOf(filter), 1)
|
|
284
|
+
this.load()
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
setSortCurrent(sortType){
|
|
288
|
+
this.preset.sorts = [
|
|
289
|
+
{
|
|
290
|
+
key: this.selectedColumn,
|
|
291
|
+
label: this.config.columns[this.selectedColumn].label,
|
|
292
|
+
type: sortType === 2 ? 'desc' : 'asc'
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
this.load()
|
|
296
|
+
this.$refs.columnMenu.close()
|
|
297
|
+
},
|
|
298
|
+
|
|
159
299
|
saveConfig: throttle(function() {
|
|
160
|
-
if(!this.configLoaded) return
|
|
300
|
+
if(!this.configLoaded || !this.configStoreObj) return
|
|
161
301
|
switch(this.configStoreObj.type){
|
|
162
302
|
case 'socket':
|
|
163
|
-
this.socketEmit2(this.configStoreObj.src,
|
|
303
|
+
this.socketEmit2(this.configStoreObj.src,
|
|
304
|
+
{ key:this.configStoreObj.name ?? 'ListView', config:this.config })
|
|
164
305
|
break
|
|
165
306
|
}
|
|
166
307
|
}, 1000, { leading:true }),
|
|
167
308
|
|
|
309
|
+
subscribe(){
|
|
310
|
+
if(!this.subscriptionObj) return
|
|
311
|
+
|
|
312
|
+
const { type, method, model } = this.subscriptionObj
|
|
313
|
+
|
|
314
|
+
switch(type){
|
|
315
|
+
|
|
316
|
+
case 'socket':
|
|
317
|
+
this.socketEmit2(method, { name:model }).then()
|
|
318
|
+
break
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
168
322
|
},
|
|
169
323
|
|
|
170
324
|
|
|
171
|
-
inject: [ 'socketEmit2', 'toast', 'alert' ],
|
|
325
|
+
inject: [ 'socket', 'socketEmit2', 'toast', 'alert' ],
|
|
172
326
|
|
|
173
327
|
computed: {
|
|
174
328
|
|
|
329
|
+
subscriptionObj(){
|
|
330
|
+
const splitted = ((this.subscription ?? '').toString()).split(':')
|
|
331
|
+
const splitted2 = (splitted[1] ?? '').split(',')
|
|
332
|
+
const obj = {
|
|
333
|
+
type: splitted[0],
|
|
334
|
+
method: splitted2[0],
|
|
335
|
+
model: splitted2[1],
|
|
336
|
+
}
|
|
337
|
+
return obj.type && obj.method && obj.model ? obj : null
|
|
338
|
+
},
|
|
339
|
+
|
|
175
340
|
configStoreObj(){
|
|
176
341
|
const splitted = ((this.configStore ?? '').toString()).split(':')
|
|
177
|
-
|
|
178
|
-
|
|
342
|
+
const splitted2 = (splitted[1] ?? '').split(',')
|
|
343
|
+
const obj = {
|
|
179
344
|
type: splitted[0],
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
345
|
+
src: splitted2[0],
|
|
346
|
+
name: splitted2[1]
|
|
347
|
+
}
|
|
348
|
+
return obj.type && obj.src ? obj : null
|
|
349
|
+
},
|
|
183
350
|
|
|
184
351
|
contentSlots(){
|
|
185
352
|
const slots = {}
|
|
@@ -219,6 +386,11 @@ export default{
|
|
|
219
386
|
return this.preset.columns
|
|
220
387
|
},
|
|
221
388
|
|
|
389
|
+
presetCurrentFilters(){
|
|
390
|
+
if(!this.preset.filters) return []
|
|
391
|
+
return this.preset.filters.filter((_) => _.key === this.selectedColumn)
|
|
392
|
+
},
|
|
393
|
+
|
|
222
394
|
},
|
|
223
395
|
|
|
224
396
|
data(){
|
|
@@ -226,18 +398,29 @@ export default{
|
|
|
226
398
|
items: [],
|
|
227
399
|
hasNext: false,
|
|
228
400
|
count: null,
|
|
229
|
-
configLoaded: false
|
|
401
|
+
configLoaded: false,
|
|
402
|
+
selectedColumn: null
|
|
230
403
|
}
|
|
231
404
|
},
|
|
232
405
|
|
|
233
406
|
|
|
234
407
|
mounted() {
|
|
235
|
-
this.
|
|
236
|
-
|
|
237
|
-
|
|
408
|
+
this.socket.onAny(this.onHooks)
|
|
409
|
+
|
|
410
|
+
window.setTimeout(() => {
|
|
411
|
+
this.loadConfig().then(() => {
|
|
412
|
+
this.load()
|
|
413
|
+
})
|
|
414
|
+
}, 201)
|
|
415
|
+
|
|
416
|
+
this.subscribe()
|
|
238
417
|
},
|
|
239
418
|
|
|
240
|
-
|
|
419
|
+
unmounted() {
|
|
420
|
+
this.socket.offAny(this.onHooks)
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
watch: {
|
|
241
424
|
|
|
242
425
|
config: {
|
|
243
426
|
deep: true,
|
|
@@ -265,4 +448,12 @@ export default{
|
|
|
265
448
|
@apply text-ellipsis whitespace-nowrap overflow-x-hidden;
|
|
266
449
|
}
|
|
267
450
|
|
|
451
|
+
.searchBox{
|
|
452
|
+
@apply w-[300px] max-w-[30%];
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.hoverable{
|
|
456
|
+
@apply hover:bg-primary hover:text-white;
|
|
457
|
+
}
|
|
458
|
+
|
|
268
459
|
</style>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="styleComp">
|
|
3
|
-
<div>
|
|
3
|
+
<div class="border-r-[1px] border-text-50 bg-base-400">
|
|
4
4
|
|
|
5
5
|
<div class="p-6">
|
|
6
6
|
<h3>Presets</h3>
|
|
7
7
|
<br />
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
-
<div class="flex-1 overflow-y-auto
|
|
10
|
+
<div class="flex-1 overflow-y-auto">
|
|
11
11
|
<div v-for="(preset, idx) in config.presets"
|
|
12
|
-
class="px-6 py-3 flex flex-row gap-2 items-center
|
|
12
|
+
class="px-6 py-3 flex flex-row gap-2 items-center hover:bg-text-50 cursor-pointer">
|
|
13
13
|
<div class="px-2">
|
|
14
14
|
<Checkbox :checked="idx === config.presetIdx" @change="selectPreset(preset)" />
|
|
15
15
|
</div>
|
|
@@ -1,51 +1,214 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
|
|
2
3
|
<div :class="$style.comp">
|
|
3
4
|
|
|
4
|
-
<div
|
|
5
|
-
<div
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<div :class="$style.resizeRight" @mousedown="(e) => onMouseDown(e, widget, 'right')"></div>
|
|
11
|
-
<div :class="$style.resizeBottom" @mousedown="(e) => onMouseDown(e, widget, 'bottom')"></div>
|
|
12
|
-
<div :class="$style.resizeBottomRight" @mousedown="(e) => onMouseDown(e, widget, 'bottom-right')"></div>
|
|
13
|
-
<div v-if="widget.title">
|
|
14
|
-
<h5>{{ widget.title }}</h5>
|
|
15
|
-
</div>
|
|
16
|
-
<component :is="widget.type" :="widget.props"></component>
|
|
5
|
+
<div v-if="useHeader" class="flex flex-row justify-end gap-8">
|
|
6
|
+
<div class="flex flex-row">
|
|
7
|
+
<Button @click="$refs.widgetSelector.open()" class="px-3">
|
|
8
|
+
<svg width="16" height="16" class="fill-white mr-1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"/></svg>
|
|
9
|
+
Widgets
|
|
10
|
+
</Button>
|
|
17
11
|
</div>
|
|
12
|
+
|
|
13
|
+
<Switch v-model="editMode" />
|
|
18
14
|
</div>
|
|
19
15
|
|
|
20
|
-
<div class="
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
<div :class="`${$style.pageGrid} ${gridClass}`" :style="pageGrid" ref="pageGrid">
|
|
17
|
+
<div v-for="(widget, index) in config.widgets"
|
|
18
|
+
:class="$style.column"
|
|
19
|
+
:style="columnStyle(widget)"
|
|
20
|
+
@mouseover="onMoverMouseOver">
|
|
21
|
+
<div v-if="editMode" :class="$style.mover" @mousedown="(e) => onMoverStart(e, widget, index)"></div>
|
|
22
|
+
<div v-if="editMode" :class="$style.resizeLeft" @mousedown="(e) => onMouseDown(e, widget, 'right')"></div>
|
|
23
|
+
<div v-if="editMode" :class="$style.resizeRight" @mousedown="(e) => onMouseDown(e, widget, 'right')"></div>
|
|
24
|
+
<div v-if="editMode" :class="$style.resizeBottom" @mousedown="(e) => onMouseDown(e, widget, 'bottom')"></div>
|
|
25
|
+
<div v-if="editMode" :class="$style.resizeTop" @mousedown="(e) => onMouseDown(e, widget, 'bottom')"></div>
|
|
26
|
+
<component v-if="widget.type" :is="widget.type" :="widget.props">
|
|
27
|
+
<template v-for="(_, slot) in $slots" #[slot]="{ item }">
|
|
28
|
+
<slot :name="slot" :item="item"></slot>
|
|
29
|
+
</template>
|
|
30
|
+
</component>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
31
33
|
|
|
32
|
-
<div class="
|
|
34
|
+
<div class="hidden">
|
|
35
|
+
<div class="col-span-1"></div>
|
|
36
|
+
<div class="col-span-2"></div>
|
|
37
|
+
<div class="col-span-3"></div>
|
|
38
|
+
<div class="col-span-4"></div>
|
|
39
|
+
<div class="col-span-5"></div>
|
|
40
|
+
<div class="col-span-6"></div>
|
|
41
|
+
<div class="col-span-7"></div>
|
|
42
|
+
<div class="col-span-8"></div>
|
|
43
|
+
<div class="col-span-9"></div>
|
|
44
|
+
<div class="col-span-10"></div>
|
|
45
|
+
<div class="col-span-11"></div>
|
|
46
|
+
<div class="col-span-12"></div>
|
|
47
|
+
</div>
|
|
33
48
|
|
|
49
|
+
<div class="absolute">
|
|
50
|
+
<Modal ref="widgetSelector" width="420" height="560">
|
|
51
|
+
<template #head>
|
|
52
|
+
<div class="p-6 flex flex-col">
|
|
53
|
+
<div class="flex flex-row">
|
|
54
|
+
<h3 class="flex-1">Widgets</h3>
|
|
55
|
+
<button type="button" @click="$refs.widgetSelector.close()">
|
|
56
|
+
<svg width="19" height="19" class="fill-text-300 hover:fill-red-500" 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>
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="flex justify-center mb-4">
|
|
60
|
+
<Tabs :items="tabItems" v-model="tabIndex" />
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</template>
|
|
64
|
+
<div v-if="tabIndex === 1" class="flex-1 flex flex-col divide-y divide-text-50">
|
|
65
|
+
<div v-for="widget in widgets" class="flex flex-row gap-4 p-4 px-6 hover:bg-primary-50">
|
|
66
|
+
<div class="w-[96px] h-[48px] border-[1px] border-text-50 bg-base-300"></div>
|
|
67
|
+
<div class="flex-1">
|
|
68
|
+
<strong>{{ widget.type ?? widget.title }}</strong>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="grid grid-cols-2 gap-1">
|
|
71
|
+
<div @click="addWidget(widget, { col:3 })">3</div>
|
|
72
|
+
<div @click="addWidget(widget, { col:4 })">4</div>
|
|
73
|
+
<div @click="addWidget(widget, { col:6 })">6</div>
|
|
74
|
+
<div @click="addWidget(widget, { col:12 })">12</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div v-else class="flex-1 flex">
|
|
79
|
+
<ListItem :items="config.widgets" @reorder="reorderWidget" class="flex-1" bodyClass="divide-y divide-text-50">
|
|
80
|
+
<template v-slot="{ item }">
|
|
81
|
+
<div class="flex flex-row items-center gap-2 px-3" :key="item">
|
|
82
|
+
<div class="p-2 cursor-move" data-reorder>
|
|
83
|
+
<svg width="19" height="19" class="fill-text-300" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
84
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.25 16C4.25 15.5858 4.58579 15.25 5 15.25H19C19.4142 15.25 19.75 15.5858 19.75 16C19.75 16.4142 19.4142 16.75 19 16.75H5C4.58579 16.75 4.25 16.4142 4.25 16Z"/>
|
|
85
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.25 8C4.25 7.58579 4.58579 7.25 5 7.25H19C19.4142 7.25 19.75 7.58579 19.75 8C19.75 8.41421 19.4142 8.75 19 8.75H5C4.58579 8.75 4.25 8.41421 4.25 8Z"/>
|
|
86
|
+
</svg>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="flex-1">
|
|
89
|
+
<strong>{{ item.title ?? item.type }}</strong>
|
|
90
|
+
</div>
|
|
91
|
+
<div>
|
|
92
|
+
<button type="button" @click="removeWidget(item)">
|
|
93
|
+
<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>
|
|
94
|
+
</button>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</template>
|
|
98
|
+
</ListItem>
|
|
99
|
+
</div>
|
|
100
|
+
</Modal>
|
|
101
|
+
</div>
|
|
34
102
|
</div>
|
|
103
|
+
|
|
35
104
|
</template>
|
|
36
105
|
|
|
37
106
|
<script>
|
|
38
107
|
|
|
108
|
+
import throttle from "lodash/throttle";
|
|
109
|
+
import {parseBoolean} from "../utils/helpers.mjs";
|
|
110
|
+
|
|
39
111
|
export default{
|
|
40
112
|
|
|
41
113
|
props: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
114
|
+
config: Object,
|
|
115
|
+
configStore: String,
|
|
116
|
+
widgets: Array,
|
|
117
|
+
header: undefined,
|
|
118
|
+
gap: {
|
|
119
|
+
type: String,
|
|
120
|
+
default: '1rem'
|
|
121
|
+
},
|
|
122
|
+
grid: {
|
|
123
|
+
type: [ String, Number ],
|
|
124
|
+
default: 12
|
|
125
|
+
},
|
|
126
|
+
mode: {
|
|
127
|
+
type: String,
|
|
128
|
+
remark: 'page|screen, default:page'
|
|
129
|
+
},
|
|
130
|
+
gridClass: String
|
|
45
131
|
},
|
|
46
132
|
|
|
47
133
|
methods: {
|
|
48
134
|
|
|
135
|
+
columnStyle(widget){
|
|
136
|
+
let style = {
|
|
137
|
+
gridColumn: `span ${widget.col} / span ${widget.col}`,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
switch(this.mode){
|
|
141
|
+
|
|
142
|
+
case 'screen':
|
|
143
|
+
Object.assign(style, {
|
|
144
|
+
gridRow: `span ${widget.row} / span ${widget.row}`,
|
|
145
|
+
})
|
|
146
|
+
break
|
|
147
|
+
|
|
148
|
+
case 'page':
|
|
149
|
+
default:
|
|
150
|
+
Object.assign(style, {
|
|
151
|
+
height:(widget.row * this.rowHeight) + 'px'
|
|
152
|
+
})
|
|
153
|
+
break
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return style
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
addWidget(widget, props){
|
|
161
|
+
this.config.widgets.push({
|
|
162
|
+
...widget,
|
|
163
|
+
...(props ?? {})
|
|
164
|
+
})
|
|
165
|
+
this.$refs.widgetSelector.close()
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
reorderWidget(from, to){
|
|
169
|
+
this.config.widgets.splice(to, 0, this.config.widgets.splice(from, 1)[0])
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
removeWidget(widget){
|
|
173
|
+
const index = this.config.widgets.indexOf(widget)
|
|
174
|
+
if(index >= 0){
|
|
175
|
+
this.config.widgets.splice(index, 1)
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
toggleEditMode(state){
|
|
181
|
+
if(typeof state !== 'boolean')
|
|
182
|
+
this.editMode = state
|
|
183
|
+
else
|
|
184
|
+
this.editMode = !this.editMode
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
async loadConfig(){
|
|
189
|
+
if(!this.configStoreObj) return
|
|
190
|
+
|
|
191
|
+
switch(this.configStoreObj.type){
|
|
192
|
+
case 'socket':
|
|
193
|
+
return this.socketEmit2(this.configStoreObj.src,
|
|
194
|
+
{ key:this.configStoreObj.name ?? 'pageBuilder' })
|
|
195
|
+
.then((config) => {
|
|
196
|
+
Object.assign(this.config, config ?? {})
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
saveConfig: throttle(function() {
|
|
202
|
+
if(!this.configStoreObj) return
|
|
203
|
+
switch(this.configStoreObj.type){
|
|
204
|
+
case 'socket':
|
|
205
|
+
this.socketEmit2(this.configStoreObj.src,
|
|
206
|
+
{ key:this.configStoreObj.name ?? 'pageBuilder', config:this.config })
|
|
207
|
+
break
|
|
208
|
+
}
|
|
209
|
+
}, 1000, { leading:true }),
|
|
210
|
+
|
|
211
|
+
|
|
49
212
|
onMouseDown(e, widget){
|
|
50
213
|
this.curResize = {
|
|
51
214
|
target: e.target.parentNode,
|
|
@@ -79,8 +242,8 @@ export default{
|
|
|
79
242
|
if(span < 1) span = 1
|
|
80
243
|
else if(span > 12) span = 12
|
|
81
244
|
|
|
82
|
-
|
|
83
|
-
|
|
245
|
+
if(height < this.curResize.ySize) height = this.curResize.ySize
|
|
246
|
+
else if(height > window.innerHeight) height = window.innerHeight
|
|
84
247
|
|
|
85
248
|
this.curResize.widget.span = span
|
|
86
249
|
this.curResize.widget.height = height
|
|
@@ -92,12 +255,12 @@ export default{
|
|
|
92
255
|
this.curResize = null
|
|
93
256
|
},
|
|
94
257
|
|
|
95
|
-
|
|
258
|
+
onMoverStart(e, widget, index){
|
|
96
259
|
|
|
97
|
-
|
|
98
|
-
|
|
260
|
+
const columnEl = e.target.parentNode;
|
|
261
|
+
const rect = columnEl.getBoundingClientRect()
|
|
99
262
|
|
|
100
|
-
|
|
263
|
+
const cloned = columnEl.cloneNode(true)
|
|
101
264
|
cloned.classList.add(this.$style.dragged)
|
|
102
265
|
cloned.style.left = (Math.round(rect.x) + 16) + 'px'
|
|
103
266
|
cloned.style.top = (Math.round(rect.y) + 16) + 'px'
|
|
@@ -105,73 +268,135 @@ export default{
|
|
|
105
268
|
cloned.style.height = columnEl.clientHeight + 'px'
|
|
106
269
|
this.$el.appendChild(cloned)
|
|
107
270
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
271
|
+
this.curResize = {
|
|
272
|
+
widget,
|
|
273
|
+
index,
|
|
111
274
|
cloned,
|
|
112
275
|
startX: e.clientX,
|
|
113
276
|
startY: e.clientY
|
|
114
|
-
|
|
277
|
+
}
|
|
115
278
|
|
|
116
|
-
|
|
117
|
-
|
|
279
|
+
window.addEventListener('mousemove', this.onMoverMove)
|
|
280
|
+
window.addEventListener('mouseup', this.onMoverUp)
|
|
118
281
|
},
|
|
119
282
|
|
|
120
283
|
swapArray(arr, i, j){
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
284
|
+
const temp = arr[i];
|
|
285
|
+
arr[i] = arr[j];
|
|
286
|
+
arr[j] = temp;
|
|
287
|
+
},
|
|
125
288
|
|
|
126
|
-
|
|
127
|
-
|
|
289
|
+
onMoverMove(e){
|
|
290
|
+
if(!this.curResize) return
|
|
128
291
|
|
|
129
|
-
|
|
292
|
+
e.preventDefault()
|
|
130
293
|
|
|
131
294
|
const cloned = this.curResize.cloned
|
|
132
295
|
const distanceX = e.clientX - this.curResize.startX
|
|
133
296
|
const distanceY = e.clientY - this.curResize.startY
|
|
134
|
-
|
|
297
|
+
this.curResize.startX = e.clientX
|
|
135
298
|
this.curResize.startY = e.clientY
|
|
136
299
|
|
|
137
300
|
cloned.style.left = (parseInt(cloned.style.left) + distanceX) + 'px'
|
|
138
301
|
cloned.style.top = (parseInt(cloned.style.top) + distanceY) + 'px'
|
|
139
302
|
},
|
|
140
303
|
|
|
141
|
-
|
|
142
|
-
|
|
304
|
+
onMoverMouseOver(e){
|
|
305
|
+
if(!this.curResize || !this.curResize.cloned) return
|
|
306
|
+
|
|
307
|
+
e.preventDefault()
|
|
143
308
|
|
|
144
|
-
const
|
|
309
|
+
const column = e.target.closest('.' + this.$style.column)
|
|
145
310
|
|
|
146
|
-
|
|
311
|
+
const targetIdx = Array.prototype.indexOf.call(this.$refs.pageGrid.children, column)
|
|
312
|
+
|
|
313
|
+
this.$refs.pageGrid.querySelectorAll('.' + this.$style.highlight).forEach(el => el.classList.remove(this.$style.highlight))
|
|
147
314
|
|
|
148
315
|
if(targetIdx !== this.curResize.index){
|
|
149
|
-
|
|
150
|
-
|
|
316
|
+
this.curResize.targetIdx = targetIdx
|
|
317
|
+
e.target.classList.add(this.$style.highlight)
|
|
151
318
|
}
|
|
152
319
|
},
|
|
153
320
|
|
|
154
|
-
|
|
155
|
-
this.swapArray(this.widgets, this.curResize.targetIdx, this.curResize.index)
|
|
321
|
+
onMoverUp(){
|
|
322
|
+
this.swapArray(this.config.widgets, this.curResize.targetIdx, this.curResize.index)
|
|
323
|
+
|
|
324
|
+
window.removeEventListener('mousemove', this.onMoverMove)
|
|
325
|
+
window.removeEventListener('mouseup', this.onMoverUp)
|
|
326
|
+
this.$el.removeChild(this.curResize.cloned)
|
|
327
|
+
this.curResize = null
|
|
328
|
+
|
|
329
|
+
this.$refs.pageGrid.querySelectorAll('.' + this.$style.highlight).forEach(el => el.classList.remove(this.$style.highlight))
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
},
|
|
156
333
|
|
|
157
|
-
window.removeEventListener('mousemove', this.onMoverMove)
|
|
158
|
-
window.removeEventListener('mouseup', this.onMoverUp)
|
|
159
|
-
this.$el.removeChild(this.curResize.cloned)
|
|
160
|
-
this.curResize = null
|
|
161
334
|
|
|
162
|
-
|
|
335
|
+
computed: {
|
|
336
|
+
|
|
337
|
+
configStoreObj(){
|
|
338
|
+
const splitted = ((this.configStore ?? '').toString()).split(':')
|
|
339
|
+
const splitted2 = (splitted[1] ?? '').split(',')
|
|
340
|
+
const obj = {
|
|
341
|
+
type: splitted[0],
|
|
342
|
+
src: splitted2[0],
|
|
343
|
+
name: splitted2[1]
|
|
344
|
+
}
|
|
345
|
+
return obj.type && obj.src ? obj : null
|
|
163
346
|
},
|
|
164
347
|
|
|
165
|
-
|
|
166
|
-
|
|
348
|
+
useHeader(){
|
|
349
|
+
return parseBoolean(this.header)
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
pageGrid(){
|
|
353
|
+
const style = {
|
|
354
|
+
display: 'grid',
|
|
355
|
+
gridTemplateColumns: `repeat(${this.grid}, 1fr)`,
|
|
356
|
+
gridGap: this.gap
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if(this.mode === 'screen'){
|
|
360
|
+
Object.assign(style, {
|
|
361
|
+
gridTemplateRows: `repeat(${this.grid}, 1fr)`
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return style
|
|
167
366
|
}
|
|
168
367
|
|
|
169
368
|
},
|
|
170
369
|
|
|
171
370
|
data(){
|
|
172
371
|
return {
|
|
173
|
-
curResize: null
|
|
372
|
+
curResize: null,
|
|
373
|
+
editMode: false,
|
|
374
|
+
tabItems: [
|
|
375
|
+
{ text:"Add Widget", value:1 },
|
|
376
|
+
{ text:"Widgets", value:2 }
|
|
377
|
+
],
|
|
378
|
+
tabIndex: 1,
|
|
379
|
+
rowHeight: 0
|
|
174
380
|
}
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
inject: [ 'socketEmit2' ],
|
|
384
|
+
|
|
385
|
+
mounted() {
|
|
386
|
+
this.loadConfig()
|
|
387
|
+
|
|
388
|
+
this.rowHeight = Math.round(window.innerHeight / parseInt(this.grid))
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
watch: {
|
|
392
|
+
|
|
393
|
+
config: {
|
|
394
|
+
handler(){
|
|
395
|
+
this.saveConfig()
|
|
396
|
+
},
|
|
397
|
+
deep: true
|
|
398
|
+
}
|
|
399
|
+
|
|
175
400
|
}
|
|
176
401
|
|
|
177
402
|
}
|
|
@@ -181,6 +406,7 @@ export default{
|
|
|
181
406
|
<style module>
|
|
182
407
|
|
|
183
408
|
.comp{
|
|
409
|
+
@apply flex flex-col gap-4;
|
|
184
410
|
}
|
|
185
411
|
|
|
186
412
|
.column{
|
|
@@ -188,20 +414,23 @@ export default{
|
|
|
188
414
|
}
|
|
189
415
|
|
|
190
416
|
.pageGrid{
|
|
191
|
-
@apply
|
|
417
|
+
@apply flex-1;
|
|
192
418
|
}
|
|
193
419
|
.pageGrid>*{
|
|
194
420
|
@apply relative flex;
|
|
195
421
|
}
|
|
196
422
|
|
|
423
|
+
.resizeLeft{
|
|
424
|
+
@apply absolute top-[-8px] left-[-8px] w-[4px] bottom-[-8px] bg-text-50 cursor-e-resize;
|
|
425
|
+
}
|
|
197
426
|
.resizeRight{
|
|
198
|
-
@apply absolute top-
|
|
427
|
+
@apply absolute top-[-8px] right-[-8px] w-[4px] bottom-[-8px] bg-text-50 cursor-e-resize;
|
|
199
428
|
}
|
|
200
429
|
.resizeBottom{
|
|
201
|
-
@apply absolute bottom-
|
|
430
|
+
@apply absolute bottom-[-8px] left-[-8px] right-[-8px] h-[4px] bg-text-50 cursor-s-resize;
|
|
202
431
|
}
|
|
203
|
-
.
|
|
204
|
-
@apply absolute
|
|
432
|
+
.resizeTop{
|
|
433
|
+
@apply absolute top-[-8px] left-[-8px] right-[-8px] h-[4px] bg-text-50 cursor-s-resize;
|
|
205
434
|
}
|
|
206
435
|
|
|
207
436
|
.mover{
|
|
@@ -217,3 +446,4 @@ export default{
|
|
|
217
446
|
}
|
|
218
447
|
|
|
219
448
|
</style>
|
|
449
|
+
|
|
@@ -163,8 +163,12 @@ export default{
|
|
|
163
163
|
const elHeight = parseInt(window.getComputedStyle(this.$el).height !== '0px' ?
|
|
164
164
|
window.getComputedStyle(this.$el).height :
|
|
165
165
|
window.getComputedStyle(this.$el).maxHeight)
|
|
166
|
+
|
|
167
|
+
if(isNaN(elHeight)) return
|
|
168
|
+
|
|
166
169
|
this.itemHeight = parseInt(window.getComputedStyle(this.$refs.calc).height)
|
|
167
170
|
this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.items.length
|
|
171
|
+
|
|
168
172
|
//console.log('Virtual scroll resize', { elHeight, itemHeight:this.itemHeight, maxVisibleItems:this.maxVisibleItems })
|
|
169
173
|
|
|
170
174
|
if(this.itemHeight <= 0){
|
|
@@ -236,4 +240,4 @@ export default{
|
|
|
236
240
|
top: -10000px;
|
|
237
241
|
}
|
|
238
242
|
|
|
239
|
-
</style>
|
|
243
|
+
</style>
|