@mixd-id/web-scaffold 0.1.230406246 → 0.1.230406248
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 +2 -1
- package/src/components/Alert.vue +2 -2
- package/src/components/Chart.vue +296 -0
- package/src/components/DGrid.vue +21 -0
- package/src/components/DGridItem.vue +263 -0
- package/src/components/List.vue +307 -0
- package/src/components/ListItem.vue +30 -21
- package/src/components/LogViewerItem.vue +113 -0
- package/src/components/ObjectTree.vue +1 -1
- package/src/components/PresetSelectorFilterItem.vue +85 -0
- package/src/components/TextWithTag.vue +17 -8
- package/src/components/Textbox.vue +1 -1
- package/src/components/VirtualGrid.vue +3 -0
- package/src/components/VirtualScroll.vue +15 -11
- package/src/components/VirtualTable.vue +1 -1
- package/src/index.js +34 -35
- package/src/utils/helpers.js +1 -1
- package/src/utils/importer.js +1 -1
- package/src/utils/preset-selector.js +536 -0
- package/src/utils/wss.mjs +2 -2
- package/src/widgets/LogViewer.vue +85 -0
- package/src/widgets/PresetSelector.vue +514 -0
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.
|
|
4
|
+
"version": "0.1.230406248",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite serve",
|
|
7
7
|
"build": "vite build",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"./importer": "./src/utils/importer.js",
|
|
27
27
|
"./listpage1": "./src/utils/listpage1.js",
|
|
28
28
|
"./listview": "./src/utils/listview.js",
|
|
29
|
+
"./preset-selector": "./src/utils/preset-selector.js",
|
|
29
30
|
"./web": "./src/utils/web.js"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
package/src/components/Alert.vue
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
18
|
<div :class="$style.details">
|
|
19
|
-
<p class="text-center break-words" v-if="message">{{ message }}</p>
|
|
20
|
-
<p class="text-center break-words max-w-[420px]" v-if="stack">{{ stack }}</p>
|
|
19
|
+
<p class="text-center break-words whitespace-pre-line" v-if="message">{{ message }}</p>
|
|
20
|
+
<p class="text-center break-words max-w-[420px] whitespace-pre-line" v-if="stack">{{ stack }}</p>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<div :class="$style.details" v-if="details">
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="readyState === 1" :class="$style.comp">
|
|
3
|
+
|
|
4
|
+
<div class="p-3 flex flex-col items-start leading-tight">
|
|
5
|
+
<small class="text-text-400">{{ title ?? 'Untitled' }}</small>
|
|
6
|
+
<h5 class="inline align-top cursor-pointer hover:text-primary group" @click="$refs.presetSelector.open()">
|
|
7
|
+
{{ preset.name ?? 'Preset Name' }}
|
|
8
|
+
<span v-if="badgeCount > 0" class="mx-1 min-w-[19px] px-2 h-[19px] relative top-[-2px] rounded-full bg-primary text-white inline-flex items-center justify-center">
|
|
9
|
+
{{ badgeCount }}
|
|
10
|
+
</span>
|
|
11
|
+
<svg width="13" height="13" class="inline fill-text pointer-events-none group-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>
|
|
12
|
+
</h5>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<Bar class="w-full"
|
|
16
|
+
id="my-chart-id"
|
|
17
|
+
:options="chartOptions"
|
|
18
|
+
:data="chartData"
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
<PresetSelector ref="presetSelector" :config="config" @select="load" type="chart" />
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div v-else-if="readyState < 0" :class="$style.comp"
|
|
26
|
+
class="flex items-center justify-center gap-3">
|
|
27
|
+
<svg width="32" height="32" class="fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7 0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464zM359.5 133.7c-10.11-8.578-25.28-7.297-33.83 2.828L256 218.8L186.3 136.5C177.8 126.4 162.6 125.1 152.5 133.7C142.4 142.2 141.1 157.4 149.7 167.5L224.6 256l-74.88 88.5c-8.562 10.11-7.297 25.27 2.828 33.83C157 382.1 162.5 384 167.1 384c6.812 0 13.59-2.891 18.34-8.5L256 293.2l69.67 82.34C330.4 381.1 337.2 384 344 384c5.469 0 10.98-1.859 15.48-5.672c10.12-8.562 11.39-23.72 2.828-33.83L287.4 256l74.88-88.5C370.9 157.4 369.6 142.2 359.5 133.7z"/></svg>
|
|
28
|
+
<h5>{{ (error ?? {}).message ?? 'An error occurred' }}</h5>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script>
|
|
33
|
+
|
|
34
|
+
import { Bar } from 'vue-chartjs'
|
|
35
|
+
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
|
|
36
|
+
import PresetSelector from "../widgets/PresetSelector.vue";
|
|
37
|
+
import throttle from "lodash/throttle";
|
|
38
|
+
|
|
39
|
+
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
|
|
40
|
+
|
|
41
|
+
export default{
|
|
42
|
+
|
|
43
|
+
components: {Bar, PresetSelector},
|
|
44
|
+
|
|
45
|
+
inject: [ 'alert', 'socket' ],
|
|
46
|
+
|
|
47
|
+
props: {
|
|
48
|
+
config: {
|
|
49
|
+
type: Object,
|
|
50
|
+
default: {}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
presetKey: undefined,
|
|
54
|
+
src: undefined,
|
|
55
|
+
title: String,
|
|
56
|
+
subscribeKey: String,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
data(){
|
|
60
|
+
return {
|
|
61
|
+
badgeCount: 0,
|
|
62
|
+
readyState: 0,
|
|
63
|
+
data: {},
|
|
64
|
+
error: null,
|
|
65
|
+
|
|
66
|
+
backgroundColors: [
|
|
67
|
+
'#5D9CEC',
|
|
68
|
+
'#A0D468',
|
|
69
|
+
'#FFCE54',
|
|
70
|
+
'#FC6E51',
|
|
71
|
+
'#48CFAD',
|
|
72
|
+
'#AC92EC',
|
|
73
|
+
'#4FC1E9',
|
|
74
|
+
'#FFCE54',
|
|
75
|
+
'#ED5565',
|
|
76
|
+
'#EC87C0'
|
|
77
|
+
],
|
|
78
|
+
borderColors: [
|
|
79
|
+
'#4A89DC',
|
|
80
|
+
'#8CC152',
|
|
81
|
+
'#F6BB42',
|
|
82
|
+
'#E9573F',
|
|
83
|
+
'#37BC9B',
|
|
84
|
+
'#967ADC',
|
|
85
|
+
'#3BAFDA',
|
|
86
|
+
'#F6BB42',
|
|
87
|
+
'#DA4453',
|
|
88
|
+
'#D770AD'
|
|
89
|
+
],
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
computed: {
|
|
94
|
+
|
|
95
|
+
chartData(){
|
|
96
|
+
|
|
97
|
+
const { type, xAxis = [], yAxis = [] } = this.preset.chart ?? {}
|
|
98
|
+
|
|
99
|
+
const items = this.data.items ?? []
|
|
100
|
+
|
|
101
|
+
const datasets = []
|
|
102
|
+
if((yAxis[0] ?? {}).aggregrate === 'count'){
|
|
103
|
+
datasets.push({
|
|
104
|
+
label: 'count',
|
|
105
|
+
data: [],
|
|
106
|
+
borderColor: this.borderColors[datasets.length % this.borderColors.length],
|
|
107
|
+
backgroundColor: this.backgroundColors[datasets.length % this.backgroundColors.length],
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
else{
|
|
111
|
+
for(let key in items[0] ?? {}){
|
|
112
|
+
if(key !== 'date'){
|
|
113
|
+
datasets.push({
|
|
114
|
+
label: key,
|
|
115
|
+
data: [],
|
|
116
|
+
borderColor: this.borderColors[datasets.length % this.borderColors.length],
|
|
117
|
+
backgroundColor: this.backgroundColors[datasets.length % this.backgroundColors.length],
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const labels = []
|
|
124
|
+
for(let item of this.data.items ?? []){
|
|
125
|
+
labels.push(item[xAxis[0].key])
|
|
126
|
+
|
|
127
|
+
if((yAxis[0] ?? {}).aggregrate === 'count'){
|
|
128
|
+
datasets[0].data.push(item['count'])
|
|
129
|
+
}
|
|
130
|
+
else{
|
|
131
|
+
for(let i in datasets){
|
|
132
|
+
datasets[i].data.push(item[datasets[i].label])
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
labels,
|
|
139
|
+
datasets
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
chartOptions(){
|
|
144
|
+
if(typeof window === 'undefined') return
|
|
145
|
+
|
|
146
|
+
var style = getComputedStyle(document.body)
|
|
147
|
+
var gridColor = style.getPropertyValue('--text-100')
|
|
148
|
+
var gridColor2 = style.getPropertyValue('--text-200')
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
responsive: true,
|
|
152
|
+
maintainAspectRatio: false,
|
|
153
|
+
animation: false,
|
|
154
|
+
plugins: {
|
|
155
|
+
legend: {
|
|
156
|
+
display: false, // Disable the legend
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
scales: {
|
|
160
|
+
x: {
|
|
161
|
+
//display: false, // Disable x-axis labels
|
|
162
|
+
grid: {
|
|
163
|
+
display: true,
|
|
164
|
+
color: function(context){
|
|
165
|
+
return `rgb(${gridColor2})`
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
y: {
|
|
170
|
+
beginAtZero: true, // Adjust y-axis as needed
|
|
171
|
+
grid: {
|
|
172
|
+
display: true,
|
|
173
|
+
color: function(context){
|
|
174
|
+
return `rgb(${gridColor})`
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
preset(){
|
|
183
|
+
return ((this.config ?? {}).presets ?? [])[(this.config ?? {}).presetIdx ?? 0] ?? {}
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
methods: {
|
|
189
|
+
|
|
190
|
+
load(){
|
|
191
|
+
this.socket.send(this.src, this.preset)
|
|
192
|
+
.then(data => this.data = data)
|
|
193
|
+
.catch(err => {
|
|
194
|
+
this.readyState = -1
|
|
195
|
+
this.error = err
|
|
196
|
+
})
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
loadPreset(){
|
|
200
|
+
if(this.presetKey){
|
|
201
|
+
return this.socket.send('user.preset', { key:this.presetKey, reset:'reset' in this.$route.query })
|
|
202
|
+
.then(config => {
|
|
203
|
+
Object.assign(this.config, config)
|
|
204
|
+
|
|
205
|
+
if('reset' in this.$route.query){
|
|
206
|
+
this.savePreset()
|
|
207
|
+
this.$router.replace({ name:this.$route.name })
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
return new Promise(resolve => resolve())
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
saveConfig: throttle(function() {
|
|
215
|
+
if(this.presetKey){
|
|
216
|
+
this.socket.send('user.preset',
|
|
217
|
+
{ key:this.presetKey, config:this.config })
|
|
218
|
+
}
|
|
219
|
+
}, 1000, { leading:true }),
|
|
220
|
+
|
|
221
|
+
onSignal(event, items){
|
|
222
|
+
console.log('onSignal', event, items)
|
|
223
|
+
|
|
224
|
+
const hasData = items.some(item => item._data)
|
|
225
|
+
if(hasData){
|
|
226
|
+
for(let item of items){
|
|
227
|
+
if(item._data){
|
|
228
|
+
const length = this.data.items.length
|
|
229
|
+
this.$util.push(this.data.items, { id:item.id, ...item._data })
|
|
230
|
+
this.data.items.length > length ? this.data.items.shift() : null
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else{
|
|
235
|
+
this.socket.send(this.src, {
|
|
236
|
+
...this.preset,
|
|
237
|
+
id: items.map(item => item.id)
|
|
238
|
+
})
|
|
239
|
+
.then(data => {
|
|
240
|
+
if(!Array.isArray((data ?? {}).items)) return
|
|
241
|
+
|
|
242
|
+
for(let item of data.items){
|
|
243
|
+
const length = this.data.items.length
|
|
244
|
+
this.$util.push(this.data.items, item)
|
|
245
|
+
this.data.items.length > length ? this.data.items.shift() : null
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
mounted() {
|
|
254
|
+
this.loadPreset()
|
|
255
|
+
.then(() => {
|
|
256
|
+
this.readyState = 1
|
|
257
|
+
this.load()
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
if(this.subscribeKey){
|
|
261
|
+
this.socket.send('user.subscribe', { name:this.subscribeKey })
|
|
262
|
+
this.socket.on(this.subscribeKey, this.onSignal)
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
unmounted() {
|
|
267
|
+
if(this.subscribeKey) {
|
|
268
|
+
this.socket.send('user.unsubscribe', {name: this.subscribeKey})
|
|
269
|
+
this.socket.off(this.subscribeKey, this.onSignal)
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
watch: {
|
|
274
|
+
|
|
275
|
+
config: {
|
|
276
|
+
deep: true,
|
|
277
|
+
handler(){
|
|
278
|
+
this.saveConfig()
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
</script>
|
|
287
|
+
|
|
288
|
+
<style module>
|
|
289
|
+
|
|
290
|
+
.comp{
|
|
291
|
+
@apply flex flex-col;
|
|
292
|
+
@apply bg-base-400;
|
|
293
|
+
padding-bottom: 50px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
<slot name="default"></slot>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
|
|
9
|
+
export default{
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<style module>
|
|
16
|
+
|
|
17
|
+
.comp{
|
|
18
|
+
@apply flex flex-col md:grid grid-cols-12 gap-5 md:items-stretch;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
</style>
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="computedClass">
|
|
3
|
+
<slot name="default"></slot>
|
|
4
|
+
|
|
5
|
+
<div :class="`${$style.left} ${editMode ? $style.editMode : ''}`"
|
|
6
|
+
@click="editMode = true"
|
|
7
|
+
@mousedown="(e) => onMouseDown(e, 'left')"></div>
|
|
8
|
+
<div :class="`${$style.top} ${editMode ? $style.editMode : ''}`"
|
|
9
|
+
@click="editMode = true"
|
|
10
|
+
@mousedown="(e) => onMouseDown(e, 'top')"></div>
|
|
11
|
+
<div :class="`${$style.right} ${editMode ? $style.editMode : ''}`"
|
|
12
|
+
@click="editMode = true"
|
|
13
|
+
@mousedown="(e) => onMouseDown(e, 'right')"></div>
|
|
14
|
+
<div :class="`${$style.bottom} ${editMode ? $style.editMode : ''}`"
|
|
15
|
+
@click="editMode = true"
|
|
16
|
+
@mousedown="(e) => onMouseDown(e, 'bottom')"></div>
|
|
17
|
+
|
|
18
|
+
<div ref="drag" :class="`${$style.drag} ${editMode ? $style.editMode : ''}`">
|
|
19
|
+
<svg width="48" height="48" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M512 255.1c0 6.755-2.844 13.09-7.844 17.62l-88 80.05C411.5 357.8 405.8 359.9 400 359.9c-13.27 0-24-10.76-24-24c0-6.534 2.647-13.04 7.844-17.78l42.07-38.28H280v146l38.25-42.1c4.715-5.2 11.21-7.849 17.74-7.849c13.23 0 24.01 10.71 24.01 24.03c0 5.765-2.061 11.55-6.25 16.15l-80 88.06C269.2 509.2 262.8 512 256 512s-13.22-2.846-17.75-7.849l-80-88.06c-4.189-4.603-6.25-10.39-6.25-16.15c0-13.38 10.83-24.03 23.1-24.03c6.526 0 13.02 2.649 17.75 7.849L232 425.9V279.8H86.09l42.07 38.28c5.196 4.735 7.844 11.24 7.844 17.78c0 13.22-10.71 24-24 24c-5.781 0-11.53-2.064-16.16-6.254l-88-80.05C2.844 269.1 0 262.7 0 255.1c0-6.755 2.844-13.37 7.844-17.9l88-80.05C100.5 153.8 106.2 151.8 112 151.8c13.26 0 23.99 10.74 23.99 23.99c0 6.534-2.647 13.04-7.844 17.78L86.09 231.8H232V85.8L193.8 127.9C189 133.1 182.5 135.7 175.1 135.7c-13.16 0-23.1-10.66-23.1-24.03c0-5.765 2.061-11.55 6.25-16.15l80-88.06C242.8 2.502 249.4 0 256 0s13.22 2.502 17.75 7.505l80 88.06c4.189 4.603 6.25 10.39 6.25 16.15c0 13.35-10.81 24.03-24 24.03c-6.531 0-13.03-2.658-17.75-7.849L280 85.8v146h145.9l-42.07-38.28c-5.196-4.735-7.844-11.24-7.844-17.78c0-13.25 10.74-23.99 23.98-23.99c5.759 0 11.55 2.061 16.18 6.242l88 80.05C509.2 242.6 512 249.2 512 255.1z"/></svg>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<button type="button" :class="`${$style.removeBtn} ${editMode ? $style.editMode : ''}`" @click="$emit('remove')">
|
|
23
|
+
<svg width="11" height="11" class="fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M378.4 440.6c8.531 10.16 7.203 25.28-2.938 33.81C370.9 478.2 365.5 480 360 480c-6.844 0-13.64-2.906-18.39-8.562L192 293.3l-149.6 178.1C37.63 477.1 30.83 480 23.98 480c-5.453 0-10.92-1.844-15.42-5.625c-10.14-8.531-11.47-23.66-2.938-33.81L160.7 256L5.625 71.44C-2.906 61.28-1.578 46.16 8.563 37.63C18.69 29.08 33.84 30.39 42.38 40.56L192 218.7l149.6-178.1c8.547-10.17 23.67-11.47 33.81-2.938s11.47 23.66 2.938 33.81L223.3 256L378.4 440.6z"/></svg>
|
|
24
|
+
</button>
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script>
|
|
30
|
+
|
|
31
|
+
export default{
|
|
32
|
+
|
|
33
|
+
emits: [ 'class-change', 'remove', 'reorder' ],
|
|
34
|
+
|
|
35
|
+
props: {
|
|
36
|
+
|
|
37
|
+
class: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: ''
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
computed: {
|
|
45
|
+
|
|
46
|
+
computedClass(){
|
|
47
|
+
return [
|
|
48
|
+
this.$style.comp,
|
|
49
|
+
this.class
|
|
50
|
+
]
|
|
51
|
+
.join(' ')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
data(){
|
|
57
|
+
return {
|
|
58
|
+
drag: null,
|
|
59
|
+
editMode: false,
|
|
60
|
+
oEl: null,
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
methods: {
|
|
65
|
+
|
|
66
|
+
onMouseDown(e, direction){
|
|
67
|
+
if(!this.editMode) return
|
|
68
|
+
|
|
69
|
+
this.drag = {
|
|
70
|
+
x: e.clientX,
|
|
71
|
+
y: e.clientY,
|
|
72
|
+
colSize: Math.round(this.$el.clientWidth / 12),
|
|
73
|
+
target: e.target,
|
|
74
|
+
direction
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
window.addEventListener('mousemove', this.onMouseMove)
|
|
78
|
+
window.addEventListener('mouseup', this.onMouseUp)
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
onMouseMove(e){
|
|
82
|
+
|
|
83
|
+
switch(this.drag.direction){
|
|
84
|
+
|
|
85
|
+
case 'right':
|
|
86
|
+
const distanceX = e.clientX - this.drag.x
|
|
87
|
+
|
|
88
|
+
if(Math.abs(distanceX) > 35){
|
|
89
|
+
const match = this.class.match(/col-span-(\d+)/)
|
|
90
|
+
const colSpan = match ? parseInt(match[1]) : 1
|
|
91
|
+
const nextColSpan = distanceX > 0 ? colSpan + 1 <= 12 ? colSpan + 1 : 12 :
|
|
92
|
+
colSpan - 1 >= 1 ? colSpan - 1 : 1
|
|
93
|
+
|
|
94
|
+
const nextClass = match ? this.class.replace(`col-span-${colSpan}`, `col-span-${nextColSpan}`) :
|
|
95
|
+
`${this.class} col-span-${nextColSpan}`
|
|
96
|
+
|
|
97
|
+
this.drag.x = e.clientX
|
|
98
|
+
this.$emit('class-change', nextClass)
|
|
99
|
+
}
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
case 'bottom':
|
|
103
|
+
const distanceY = e.clientY - this.drag.y
|
|
104
|
+
if(Math.abs(distanceY) > 70){
|
|
105
|
+
const match = this.class.match(/row-span-(\d+)/)
|
|
106
|
+
const rowSpan = match ? parseInt(match[1]) : 1
|
|
107
|
+
const nextRowSpan = distanceY > 0 ? rowSpan + 1 <= 12 ? rowSpan + 1 : 12 :
|
|
108
|
+
rowSpan - 1 >= 1 ? rowSpan - 1 : 1
|
|
109
|
+
|
|
110
|
+
const nextClass = match ? this.class.replace(`row-span-${rowSpan}`, `row-span-${nextRowSpan}`) :
|
|
111
|
+
`${this.class} row-span-${nextRowSpan}`
|
|
112
|
+
|
|
113
|
+
this.drag.y = e.clientY
|
|
114
|
+
this.$emit('class-change', nextClass)
|
|
115
|
+
}
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
onMouseUp(e){
|
|
122
|
+
|
|
123
|
+
window.removeEventListener('mousemove', this.onMouseMove)
|
|
124
|
+
window.removeEventListener('mouseup', this.onMouseUp)
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
checkEditMode(e){
|
|
128
|
+
|
|
129
|
+
if(e.target.closest(`.${this.$style.comp}`) !== this.$el){
|
|
130
|
+
this.editMode = false
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
onDragOver(e){
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
const oEl = e.target.closest(`.${this.$style.comp}`)
|
|
138
|
+
|
|
139
|
+
if(this.oEl !== oEl){
|
|
140
|
+
this.oEl ? this.oEl.style.opacity = '' : '';
|
|
141
|
+
|
|
142
|
+
if(oEl){
|
|
143
|
+
this.oEl = oEl
|
|
144
|
+
this.oEl.style.opacity = '.5'
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
onDragStart(e){
|
|
150
|
+
window.addEventListener('dragover', this.onDragOver)
|
|
151
|
+
window.addEventListener('dragend', this.onDragEnd)
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
onDragEnd(e){
|
|
155
|
+
|
|
156
|
+
e.preventDefault()
|
|
157
|
+
|
|
158
|
+
const childNodes = Array.from(this.$el.parentNode.children)
|
|
159
|
+
const fromIdx = childNodes.indexOf(this.$el)
|
|
160
|
+
const toIdx = childNodes.indexOf(this.oEl)
|
|
161
|
+
|
|
162
|
+
this.oEl ? this.oEl.style.opacity = '' : '';
|
|
163
|
+
|
|
164
|
+
this.$el.setAttribute('draggable', false)
|
|
165
|
+
window.removeEventListener('dragover', this.onDragOver)
|
|
166
|
+
window.removeEventListener('dragend', this.onDragEnd)
|
|
167
|
+
|
|
168
|
+
this.$emit('reorder', fromIdx, toIdx)
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
onDrag(e){
|
|
172
|
+
this.$el.addEventListener('dragstart', this.onDragStart)
|
|
173
|
+
this.$el.setAttribute('draggable', true)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
watch: {
|
|
179
|
+
|
|
180
|
+
editMode(to){
|
|
181
|
+
to ? window.addEventListener('click', this.checkEditMode) :
|
|
182
|
+
window.removeEventListener('click', this.checkEditMode)
|
|
183
|
+
|
|
184
|
+
to ? this.$refs.drag.addEventListener('mousedown', this.onDrag) :
|
|
185
|
+
this.$refs.drag.removeEventListener('mousedown', this.onDrag)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
</script>
|
|
193
|
+
|
|
194
|
+
<style module>
|
|
195
|
+
|
|
196
|
+
.comp{
|
|
197
|
+
@apply relative flex;
|
|
198
|
+
}
|
|
199
|
+
.comp[class~='row-span-2']>*:first-child,
|
|
200
|
+
.comp[class~='row-span-3']>*:first-child,
|
|
201
|
+
.comp[class~='row-span-4']>*:first-child,
|
|
202
|
+
.comp[class~='row-span-5']>*:first-child,
|
|
203
|
+
.comp[class~='row-span-6']>*:first-child,
|
|
204
|
+
.comp[class~='row-span-7']>*:first-child,
|
|
205
|
+
.comp[class~='row-span-8']>*:first-child,
|
|
206
|
+
.comp[class~='row-span-9']>*:first-child,
|
|
207
|
+
.comp[class~='row-span-10']>*:first-child,
|
|
208
|
+
.comp[class~='row-span-11']>*:first-child
|
|
209
|
+
.comp[class~='row-span-12']>*:first-child{
|
|
210
|
+
@apply !absolute !top-0 !left-0 !right-0 !bottom-0 !h-auto;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.top{
|
|
214
|
+
@apply h-[3px];
|
|
215
|
+
@apply absolute top-[-6px] right-[-6px] left-[-6px] cursor-move bg-transparent hover:bg-text-50;
|
|
216
|
+
}
|
|
217
|
+
.top.editMode{
|
|
218
|
+
@apply cursor-n-resize bg-primary hover:bg-primary;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.bottom{
|
|
222
|
+
@apply h-[3px];
|
|
223
|
+
@apply absolute bottom-[-6px] right-[-6px] left-[-6px] cursor-move bg-transparent hover:bg-text-50;
|
|
224
|
+
}
|
|
225
|
+
.bottom.editMode{
|
|
226
|
+
@apply cursor-s-resize bg-primary hover:bg-primary;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.left{
|
|
230
|
+
@apply w-[3px];
|
|
231
|
+
@apply absolute top-[-6px] left-[-6px] bottom-[-6px] cursor-move bg-transparent hover:bg-text-50;
|
|
232
|
+
}
|
|
233
|
+
.left.editMode{
|
|
234
|
+
@apply cursor-w-resize bg-primary hover:bg-primary;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.right{
|
|
238
|
+
@apply w-[3px];
|
|
239
|
+
@apply absolute top-[-6px] right-[-6px] bottom-[-6px] cursor-move bg-transparent hover:bg-text-50;
|
|
240
|
+
}
|
|
241
|
+
.right.editMode{
|
|
242
|
+
@apply cursor-e-resize bg-primary hover:bg-primary;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.removeBtn{
|
|
246
|
+
@apply absolute top-[.5rem] right-[.5rem] hidden;
|
|
247
|
+
@apply w-[24px] h-[24px] rounded-full bg-primary;
|
|
248
|
+
@apply items-center justify-center;
|
|
249
|
+
}
|
|
250
|
+
.removeBtn.editMode{
|
|
251
|
+
@apply flex;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.drag{
|
|
255
|
+
@apply absolute top-0 left-0 right-0 bottom-0;
|
|
256
|
+
@apply rounded-full hidden;
|
|
257
|
+
}
|
|
258
|
+
.drag.editMode{
|
|
259
|
+
@apply flex items-center justify-center flex items-center justify-center;
|
|
260
|
+
@apply cursor-move;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
</style>
|