@mixd-id/web-scaffold 0.1.2301231316 → 0.1.2301231318
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 +1 -1
- package/src/components/Carousel.vue +1 -3
- package/src/components/Image.vue +55 -13
- package/src/components/ImagePreview.vue +60 -0
- package/src/components/ListPage1.vue +118 -36
- package/src/components/ListPage1Filter.vue +6 -8
- package/src/components/Tabs.vue +5 -1
- package/src/components/Textbox.vue +2 -2
- package/src/index.js +1 -0
package/package.json
CHANGED
|
@@ -123,9 +123,7 @@ export default{
|
|
|
123
123
|
})
|
|
124
124
|
left *= -1
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if(noAnimation){
|
|
126
|
+
if(!noAnimation){
|
|
129
127
|
this.$el.firstElementChild.addEventListener('transitionend', function(){
|
|
130
128
|
this.classList.remove('transition-carousel')
|
|
131
129
|
})
|
package/src/components/Image.vue
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="
|
|
2
|
+
<div :class="computedOuterClass">
|
|
3
3
|
<img :class="computedClass" :src="actualSrc" ref="img" @click="onClick" :style="imageStyle"/>
|
|
4
4
|
<input v-if="Boolean(editable)" class="hidden" type="file" accept="image/*" ref="file" @change="onChange"/>
|
|
5
5
|
<slot></slot>
|
|
6
|
+
<div :class="$style.isLoading" v-if="isLoading">
|
|
7
|
+
<svg class="animate-spin aspect-square w-[15%] text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
|
|
8
|
+
</div>
|
|
6
9
|
</div>
|
|
7
10
|
</template>
|
|
8
11
|
|
|
@@ -23,6 +26,10 @@ export default{
|
|
|
23
26
|
|
|
24
27
|
props:{
|
|
25
28
|
|
|
29
|
+
class: String,
|
|
30
|
+
|
|
31
|
+
outerClass: String,
|
|
32
|
+
|
|
26
33
|
editable:{
|
|
27
34
|
type: [ Boolean, String ],
|
|
28
35
|
default: false
|
|
@@ -38,23 +45,31 @@ export default{
|
|
|
38
45
|
|
|
39
46
|
defaultSrc: {
|
|
40
47
|
type: String,
|
|
41
|
-
|
|
48
|
+
default: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMS4xNTkyIDIxLjA4MjhDMjEuNjc5OCAyMC41NDMyIDIyIDE5LjgwOSAyMiAxOVY1QzIyIDMuMzQzMTUgMjAuNjU2OSAyIDE5IDJINUMzLjM0MzE1IDIgMiAzLjM0MzE1IDIgNVYxOUMyIDIwLjY1NjkgMy4zNDMxNSAyMiA1IDIySDE5QzE5LjI5NjIgMjIgMTkuNTgyMyAyMS45NTcxIDE5Ljg1MjUgMjEuODc3MUMxOS44NjU4IDIxLjg3MzIgMTkuODc5IDIxLjg2OTIgMTkuODkyMSAyMS44NjUxQzIwLjI1ODYgMjEuNzUxMSAyMC41OTUgMjEuNTY4NyAyMC44ODYzIDIxLjMzMjlDMjAuODkzNyAyMS4zMjY5IDIwLjkwMSAyMS4zMjEgMjAuOTA4MyAyMS4zMTQ5QzIwLjk4MjQgMjEuMjUzOCAyMS4wNTM1IDIxLjE4OTIgMjEuMTIxMyAyMS4xMjEzQzIxLjEzNDEgMjEuMTA4NiAyMS4xNDY3IDIxLjA5NTcgMjEuMTU5MiAyMS4wODI4Wk0xOSAzLjVINUM0LjE3MTU3IDMuNSAzLjUgNC4xNzE1NyAzLjUgNVYxMi43TDYuMDUyOTIgOS42MzY0OUM3LjIxNTY2IDguMjQxMjEgOS4zNDE3NyA4LjE5MTAyIDEwLjU2OSA5LjUyOTg3TDIwLjE0MTggMTkuOTcyOEMyMC4zNjUyIDE5LjcxMDkgMjAuNSAxOS4zNzEyIDIwLjUgMTlWNUMyMC41IDQuMTcxNTcgMTkuODI4NCAzLjUgMTkgMy41Wk01IDIwLjVDNC4xNzE1NyAyMC41IDMuNSAxOS44Mjg0IDMuNSAxOVYxNS4wNDMxTDcuMjA1MjYgMTAuNTk2OEM3LjcxMzk1IDkuOTg2MzMgOC41OTE0NCA5Ljg5MDgxIDkuMjEzOTUgMTAuMzI0OUM5LjIxOTUxIDEwLjMyODggOS4yMjUwNSAxMC4zMzI3IDkuMjMwNTcgMTAuMzM2N0M5LjMxMzMyIDEwLjM5NjEgOS4zOTE0MSAxMC40NjUgOS40NjMzMiAxMC41NDM1TDE4LjU5MDEgMjAuNUg1WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iLjA4Ii8+CjxjaXJjbGUgY3g9IjE3IiBjeT0iNyIgcj0iMS4yNSIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLW9wYWNpdHk9Ii4wOCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KPC9zdmc+Cg=="
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
},
|
|
45
52
|
|
|
46
53
|
computed:{
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
computedOuterClass(){
|
|
49
56
|
return [
|
|
50
57
|
this.$style.img
|
|
51
58
|
]
|
|
52
59
|
.join(' ')
|
|
53
60
|
},
|
|
54
61
|
|
|
62
|
+
computedClass(){
|
|
63
|
+
return [
|
|
64
|
+
this.class
|
|
65
|
+
]
|
|
66
|
+
.join(' ')
|
|
67
|
+
},
|
|
68
|
+
|
|
55
69
|
imageStyle(){
|
|
56
70
|
return {
|
|
57
|
-
...(this.aspectRatio ? { 'aspect-ratio':this.aspectRatio } : {})
|
|
71
|
+
...(this.aspectRatio ? { 'aspect-ratio':this.aspectRatio } : {}),
|
|
72
|
+
...(this.actualSrc ? {} : { visibility:'hidden' })
|
|
58
73
|
}
|
|
59
74
|
}
|
|
60
75
|
|
|
@@ -63,7 +78,9 @@ export default{
|
|
|
63
78
|
data(){
|
|
64
79
|
return {
|
|
65
80
|
visible: 0,
|
|
66
|
-
|
|
81
|
+
isLoading: false,
|
|
82
|
+
actualSrc: null,
|
|
83
|
+
loaded: false
|
|
67
84
|
}
|
|
68
85
|
},
|
|
69
86
|
|
|
@@ -92,8 +109,12 @@ export default{
|
|
|
92
109
|
},
|
|
93
110
|
|
|
94
111
|
async loadSrc(){
|
|
112
|
+
|
|
113
|
+
this.loaded = false
|
|
114
|
+
|
|
95
115
|
if(typeof this.src === 'string') {
|
|
96
116
|
if (this.src.startsWith('data:image')) {
|
|
117
|
+
this.loaded = true
|
|
97
118
|
this.actualSrc = this.src
|
|
98
119
|
}
|
|
99
120
|
else{
|
|
@@ -113,33 +134,52 @@ export default{
|
|
|
113
134
|
|
|
114
135
|
var img = new Image()
|
|
115
136
|
img.addEventListener('load', () => {
|
|
137
|
+
this.loaded = true
|
|
116
138
|
this.actualSrc = img.src
|
|
139
|
+
this.isLoading = false
|
|
140
|
+
})
|
|
141
|
+
img.addEventListener('error', () => {
|
|
142
|
+
this.loaded = true
|
|
143
|
+
this.actualSrc = this.defaultSrc
|
|
144
|
+
this.isLoading = false
|
|
117
145
|
})
|
|
118
|
-
img.addEventListener('error', () => {})
|
|
119
146
|
img.src = src[screens[b]]
|
|
120
|
-
|
|
121
|
-
//this.actualSrc = src[screens[b]]
|
|
122
147
|
}
|
|
123
148
|
}
|
|
124
149
|
}
|
|
125
150
|
}
|
|
126
|
-
|
|
127
151
|
else if(this.src instanceof File){
|
|
128
152
|
var reader = new FileReader();
|
|
153
|
+
|
|
129
154
|
reader.addEventListener('load', () => {
|
|
155
|
+
this.loaded = true
|
|
130
156
|
this.actualSrc = reader.result
|
|
157
|
+
this.isLoading = false
|
|
131
158
|
}, false)
|
|
159
|
+
|
|
160
|
+
reader.addEventListener('error', () => {
|
|
161
|
+
this.loaded = true
|
|
162
|
+
this.actualSrc = this.defaultSrc
|
|
163
|
+
this.isLoading = false
|
|
164
|
+
})
|
|
165
|
+
|
|
132
166
|
reader.readAsDataURL(this.src)
|
|
133
167
|
}
|
|
134
|
-
|
|
135
168
|
}
|
|
136
169
|
|
|
137
170
|
},
|
|
138
171
|
|
|
139
172
|
watch:{
|
|
140
173
|
|
|
141
|
-
src(){
|
|
174
|
+
src(to){
|
|
142
175
|
this.loadSrc()
|
|
176
|
+
|
|
177
|
+
window.setTimeout(() => {
|
|
178
|
+
if(!this.loaded){
|
|
179
|
+
this.actualSrc = null
|
|
180
|
+
this.isLoading = true
|
|
181
|
+
}
|
|
182
|
+
}, 200)
|
|
143
183
|
}
|
|
144
184
|
|
|
145
185
|
}
|
|
@@ -150,10 +190,12 @@ export default{
|
|
|
150
190
|
<style module>
|
|
151
191
|
|
|
152
192
|
.img{
|
|
193
|
+
@apply relative;
|
|
153
194
|
}
|
|
154
195
|
|
|
155
|
-
.
|
|
156
|
-
|
|
196
|
+
.isLoading{
|
|
197
|
+
@apply absolute top-0 left-0 right-0 bottom-0;
|
|
198
|
+
@apply flex items-center justify-center;
|
|
157
199
|
}
|
|
158
200
|
|
|
159
201
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal :state="isOpen" width="400" height="400" :class="$style.previewModal">
|
|
3
|
+
<div class="flex-1">
|
|
4
|
+
<div class="flex flex-row justify-end items-center p-3">
|
|
5
|
+
<a :href="imageUrl" download>
|
|
6
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="42" height="42" viewBox="0 0 24 24" class="fill-text"><path class="primary" d="M15 15v-3a3 3 0 0 0-6 0v3H6a4 4 0 0 1-.99-7.88 5.5 5.5 0 0 1 10.86-.82A4.49 4.49 0 0 1 22 10.5a4.5 4.5 0 0 1-4.5 4.5H15z"/><path class="secondary" d="M11 18.59V12a1 1 0 0 1 2 0v6.59l1.3-1.3a1 1 0 0 1 1.4 1.42l-3 3a1 1 0 0 1-1.4 0l-3-3a1 1 0 0 1 1.4-1.42l1.3 1.3z"/></svg>
|
|
7
|
+
</a>
|
|
8
|
+
<button class="ml-3" @click="close">
|
|
9
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="56" viewBox="0 0 24 24" class="fill-text"><path class="secondary" fill-rule="evenodd" d="M15.78 14.36a1 1 0 0 1-1.42 1.42l-2.82-2.83-2.83 2.83a1 1 0 1 1-1.42-1.42l2.83-2.82L7.3 8.7a1 1 0 0 1 1.42-1.42l2.83 2.83 2.82-2.83a1 1 0 0 1 1.42 1.42l-2.83 2.83 2.83 2.82z"/></svg>
|
|
10
|
+
</button>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="flex items-center justify-center">
|
|
13
|
+
<img :src="imageUrl" class="max-h-[85vh]"/>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</Modal>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
|
|
21
|
+
export default{
|
|
22
|
+
|
|
23
|
+
data(){
|
|
24
|
+
return {
|
|
25
|
+
isOpen: false,
|
|
26
|
+
imageUrl: null
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
methods: {
|
|
31
|
+
|
|
32
|
+
open(imageUrl){
|
|
33
|
+
this.imageUrl = imageUrl
|
|
34
|
+
this.isOpen = true
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
close(){
|
|
38
|
+
this.isOpen = false
|
|
39
|
+
this.imageUrl = null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<style module>
|
|
49
|
+
|
|
50
|
+
.comp{
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.previewModal{
|
|
55
|
+
@apply !w-screen !h-screen !bg-base-300;
|
|
56
|
+
max-width: unset !important;
|
|
57
|
+
max-height: unset !important;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
</style>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<div class="mr-6">
|
|
9
9
|
<h2>{{ title }}</h2>
|
|
10
10
|
</div>
|
|
11
|
-
<div class="flex-1 overflow-hidden">
|
|
11
|
+
<div class="flex-1 overflow-hidden mr-4">
|
|
12
12
|
<slot v-if="$slots['lp-search']" name="lp-search" :preset="preset"/>
|
|
13
13
|
<Textbox v-else :clearable="true" placeholder="Cari..." class="w-[200px]" v-model="preset.search"
|
|
14
14
|
@clear="clearSearch" @submit="load">
|
|
@@ -24,25 +24,28 @@
|
|
|
24
24
|
<div>
|
|
25
25
|
<slot name="lp-tabspace" :preset="preset"/>
|
|
26
26
|
</div>
|
|
27
|
-
<div>
|
|
27
|
+
<div class="flex flex-row gap-1 items-center">
|
|
28
28
|
<Dropdown class="w-[150px]" :value="preset.name" mode="custom" position="bottom-right">
|
|
29
|
-
<div class="min-w-[240px] divide-y divide-text-50 p-
|
|
30
|
-
<div v-for="(_preset, idx) in presets" class="cursor-pointer flex flex-row">
|
|
29
|
+
<div class="min-w-[240px] divide-y divide-text-50 p-2 flex flex-col gap-2">
|
|
30
|
+
<div v-for="(_preset, idx) in presets" class="cursor-pointer flex flex-row hover:bg-primary-100 rounded-md">
|
|
31
31
|
<div class="flex-1 p-3" @click="selectPreset(_preset)">
|
|
32
32
|
{{ _preset.name }}
|
|
33
33
|
</div>
|
|
34
|
-
<div>
|
|
35
|
-
<button class="p-3 text-primary" @click="selectPreset(_preset, true)">
|
|
36
|
-
Edit
|
|
37
|
-
</button>
|
|
38
|
-
</div>
|
|
39
34
|
</div>
|
|
40
35
|
</div>
|
|
41
36
|
</Dropdown>
|
|
37
|
+
<button class="border-[1px] border-text-200 bg-base-50 hover:border-text-300 rounded-lg p-2"
|
|
38
|
+
@click="openPreset">
|
|
39
|
+
<svg width="20.5" height="20.5" viewBox="0 0 24 24" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg">
|
|
40
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 13.5C5.82843 13.5 6.5 12.8284 6.5 12C6.5 11.1716 5.82843 10.5 5 10.5C4.17157 10.5 3.5 11.1716 3.5 12C3.5 12.8284 4.17157 13.5 5 13.5ZM5 15C6.65685 15 8 13.6569 8 12C8 10.3431 6.65685 9 5 9C3.34315 9 2 10.3431 2 12C2 13.6569 3.34315 15 5 15Z" />
|
|
41
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 13.5C12.8284 13.5 13.5 12.8284 13.5 12C13.5 11.1716 12.8284 10.5 12 10.5C11.1716 10.5 10.5 11.1716 10.5 12C10.5 12.8284 11.1716 13.5 12 13.5ZM12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" />
|
|
42
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 13.5C19.8284 13.5 20.5 12.8284 20.5 12C20.5 11.1716 19.8284 10.5 19 10.5C18.1716 10.5 17.5 11.1716 17.5 12C17.5 12.8284 18.1716 13.5 19 13.5ZM19 15C20.6569 15 22 13.6569 22 12C22 10.3431 20.6569 9 19 9C17.3431 9 16 10.3431 16 12C16 13.6569 17.3431 15 19 15Z" />
|
|
43
|
+
</svg>
|
|
44
|
+
</button>
|
|
42
45
|
</div>
|
|
43
46
|
</div>
|
|
44
47
|
|
|
45
|
-
<VirtualTable class="flex-1 m-6" :columns="
|
|
48
|
+
<VirtualTable class="flex-1 m-6" :columns="presetColumns" :items="items"
|
|
46
49
|
:appearances="appearances" @scroll-end="loadNext">
|
|
47
50
|
<template v-for="(_, slot) in $slots" #[slot]="{ item, index }">
|
|
48
51
|
<slot :name="slot" :item="item" :index="index"></slot>
|
|
@@ -54,10 +57,11 @@
|
|
|
54
57
|
<div v-if="layout.presetOpen" class="w-[360px] border-l-[1px] border-text-50 bg-base-500 flex flex-col">
|
|
55
58
|
|
|
56
59
|
<div class="p-6 pb-0">
|
|
57
|
-
<div class="flex flex-row gap-
|
|
58
|
-
<input class="flex-1 text-xl bg-transparent outline-none" :value="preset.name" @blur="preset.name = $event.target.value"
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
<div class="flex flex-row gap-4 mb-3">
|
|
61
|
+
<input class="flex-1 text-xl bg-transparent outline-none" :value="preset.name" @blur="preset.name = $event.target.value"
|
|
62
|
+
@keyup.enter="preset.name = $event.target.value" />
|
|
63
|
+
<button ref="presetMenu" @click="layout.presetContextMenu = { caller:$refs.presetMenu }">
|
|
64
|
+
<svg width="21" height="21" viewBox="0 0 24 24" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg">
|
|
61
65
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6.5C12.8284 6.5 13.5 5.82843 13.5 5C13.5 4.17157 12.8284 3.5 12 3.5C11.1716 3.5 10.5 4.17157 10.5 5C10.5 5.82843 11.1716 6.5 12 6.5ZM12 8C13.6569 8 15 6.65685 15 5C15 3.34315 13.6569 2 12 2C10.3431 2 9 3.34315 9 5C9 6.65685 10.3431 8 12 8Z"/>
|
|
62
66
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 13.5C12.8284 13.5 13.5 12.8284 13.5 12C13.5 11.1716 12.8284 10.5 12 10.5C11.1716 10.5 10.5 11.1716 10.5 12C10.5 12.8284 11.1716 13.5 12 13.5ZM12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"/>
|
|
63
67
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 20.5C12.8284 20.5 13.5 19.8284 13.5 19C13.5 18.1716 12.8284 17.5 12 17.5C11.1716 17.5 10.5 18.1716 10.5 19C10.5 19.8284 11.1716 20.5 12 20.5ZM12 22C13.6569 22 15 20.6569 15 19C15 17.3431 13.6569 16 12 16C10.3431 16 9 17.3431 9 19C9 20.6569 10.3431 22 12 22Z"/>
|
|
@@ -68,10 +72,11 @@
|
|
|
68
72
|
@dismiss="layout.presetContextMenu = null" position="bottom-right">
|
|
69
73
|
<div class="min-w-[200px]">
|
|
70
74
|
<button class="w-full p-3 hover:bg-text-50" @click="copyPreset">Copy this Preset</button>
|
|
75
|
+
<button class="w-full p-3 text-red-500 hover:text-red-700" @click="removePreset">Remove</button>
|
|
71
76
|
</div>
|
|
72
77
|
</ContextMenu>
|
|
73
|
-
<button @click="
|
|
74
|
-
<svg width="21" height="21" viewBox="0 0 24 24" class="fill-text-300" xmlns="http://www.w3.org/2000/svg">
|
|
78
|
+
<button @click="closePreset">
|
|
79
|
+
<svg width="21" height="21" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
75
80
|
<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"/>
|
|
76
81
|
</svg>
|
|
77
82
|
</button>
|
|
@@ -85,7 +90,7 @@
|
|
|
85
90
|
<div class="flex-1 overflow-y-auto px-6 mb-6">
|
|
86
91
|
|
|
87
92
|
<div class="p-2 mt-6 flex flex-col" v-if="layout.presetTab === 'column'">
|
|
88
|
-
<ListItem :items="
|
|
93
|
+
<ListItem :items="presetColumns" @reorder="reorderColumns">
|
|
89
94
|
<template v-slot="{ item }">
|
|
90
95
|
<div class="flex flex-row items-center gap-2" :key="item">
|
|
91
96
|
<div class="cursor-move" data-reorder>
|
|
@@ -94,10 +99,9 @@
|
|
|
94
99
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8C4 7.44772 4.44772 7 5 7H19C19.5523 7 20 7.44772 20 8C20 8.55228 19.5523 9 19 9H5C4.44772 9 4 8.55228 4 8Z"/>
|
|
95
100
|
</svg>
|
|
96
101
|
</div>
|
|
97
|
-
<
|
|
98
|
-
<label :for="`lp1column${item.key}`" class="p-2">
|
|
102
|
+
<Checkbox v-model="item.visible" :true-value="true" :false-value="false" @change="load">
|
|
99
103
|
{{ item.label ?? '(No Name)' }}
|
|
100
|
-
</
|
|
104
|
+
</Checkbox>
|
|
101
105
|
</div>
|
|
102
106
|
</template>
|
|
103
107
|
</ListItem>
|
|
@@ -106,7 +110,7 @@
|
|
|
106
110
|
<div class="flex flex-col" v-if="layout.presetTab === 'filter'">
|
|
107
111
|
<div v-if="filterableColumns.length > 0">
|
|
108
112
|
<ListPage1Filter v-if="preset.filters" v-for="filter in preset.filters"
|
|
109
|
-
:filter="filter" :column="
|
|
113
|
+
:filter="filter" :column="columns[filter.key]"
|
|
110
114
|
@remove="removeFilter(filter)" @change="load"/>
|
|
111
115
|
|
|
112
116
|
<div class="py-8">
|
|
@@ -123,12 +127,12 @@
|
|
|
123
127
|
</div>
|
|
124
128
|
</div>
|
|
125
129
|
|
|
126
|
-
<div class="
|
|
127
|
-
<div v-if="sortableColumns.length > 0">
|
|
128
|
-
<div v-for="sort in preset.sorts" class="py-4
|
|
130
|
+
<div class="flex flex-col" v-if="layout.presetTab === 'sort'">
|
|
131
|
+
<div v-if="sortableColumns.length > 0" class="my-8">
|
|
132
|
+
<div v-for="sort in preset.sorts" class="py-4">
|
|
129
133
|
<div class="flex flex-row items-center gap-2">
|
|
130
134
|
<div class="flex-1">
|
|
131
|
-
<Dropdown v-model="sort.key">
|
|
135
|
+
<Dropdown v-model="sort.key" @change="load">
|
|
132
136
|
<option value="" disabled selected>Tambah Urutan</option>
|
|
133
137
|
<option v-for="column in sortableColumns" :value="column.key">{{ column.label }}</option>
|
|
134
138
|
</Dropdown>
|
|
@@ -140,14 +144,16 @@
|
|
|
140
144
|
</Dropdown>
|
|
141
145
|
</div>
|
|
142
146
|
<button @click="removeSort(sort)">
|
|
143
|
-
<svg width="21" height="21" class="fill-text-100 hover:fill-
|
|
147
|
+
<svg width="21" height="21" class="fill-text-100 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
144
148
|
<path class="secondary" fill-rule="evenodd" d="M15.78 14.36a1 1 0 0 1-1.42 1.42l-2.82-2.83-2.83 2.83a1 1 0 1 1-1.42-1.42l2.83-2.82L7.3 8.7a1 1 0 0 1 1.42-1.42l2.83 2.83 2.82-2.83a1 1 0 0 1 1.42 1.42l-2.83 2.83 2.83 2.82z"/>
|
|
145
149
|
</svg>
|
|
146
150
|
</button>
|
|
147
151
|
</div>
|
|
148
152
|
</div>
|
|
149
153
|
|
|
150
|
-
<div class="
|
|
154
|
+
<div v-if="preset.sorts && preset.sorts.length > 0" class="h-[1px] my-4 bg-text-100"></div>
|
|
155
|
+
|
|
156
|
+
<div class="py-4">
|
|
151
157
|
<Dropdown @change="addSort" v-model="layout.presetSortSelector">
|
|
152
158
|
<option value="" disabled selected>Tambah Urutan</option>
|
|
153
159
|
<option v-for="column in sortableColumns" :value="column.key">{{ column.label }}</option>
|
|
@@ -193,7 +199,18 @@ export default{
|
|
|
193
199
|
return this.presets[this.presetIdx] ?? {}
|
|
194
200
|
},
|
|
195
201
|
|
|
196
|
-
|
|
202
|
+
presetColumns(){
|
|
203
|
+
|
|
204
|
+
for(let i = 0 ; i < (this.preset.columns ?? []).length ; i++){
|
|
205
|
+
const presetColumn = this.preset.columns[i]
|
|
206
|
+
const column = this.columns[presetColumn.key] ?? {}
|
|
207
|
+
for(let key in column){
|
|
208
|
+
if(!presetColumn[key]){
|
|
209
|
+
this.preset.columns[i][key] = column[key]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
197
214
|
return this.preset.columns ?? []
|
|
198
215
|
},
|
|
199
216
|
|
|
@@ -202,11 +219,11 @@ export default{
|
|
|
202
219
|
},
|
|
203
220
|
|
|
204
221
|
filterableColumns(){
|
|
205
|
-
return this.
|
|
222
|
+
return Object.values(this.columns).filter((_) => _.filterable)
|
|
206
223
|
},
|
|
207
224
|
|
|
208
225
|
sortableColumns(){
|
|
209
|
-
return this.
|
|
226
|
+
return Object.values(this.columns).filter((_) => _.sortable)
|
|
210
227
|
}
|
|
211
228
|
|
|
212
229
|
},
|
|
@@ -220,6 +237,7 @@ export default{
|
|
|
220
237
|
presetFilterSelector: null,
|
|
221
238
|
presetSortSelector: null,
|
|
222
239
|
},
|
|
240
|
+
columns: [],
|
|
223
241
|
presets: [],
|
|
224
242
|
presetIdx: -1,
|
|
225
243
|
items: [],
|
|
@@ -230,6 +248,10 @@ export default{
|
|
|
230
248
|
|
|
231
249
|
mounted() {
|
|
232
250
|
this.socket.onAny(this.onHooks)
|
|
251
|
+
|
|
252
|
+
window.addEventListener('focus', () => {
|
|
253
|
+
this.load()
|
|
254
|
+
})
|
|
233
255
|
},
|
|
234
256
|
|
|
235
257
|
unmounted() {
|
|
@@ -240,8 +262,10 @@ export default{
|
|
|
240
262
|
|
|
241
263
|
patch(){
|
|
242
264
|
this.socketEmit(`${this.model}.patch`, {}, (res) => {
|
|
265
|
+
this.columns = res.columns
|
|
243
266
|
this.presets = res.presets
|
|
244
267
|
this.presetIdx = res.presetIdx
|
|
268
|
+
this.patchPresets()
|
|
245
269
|
this.$nextTick(() => {
|
|
246
270
|
this.items = res.items
|
|
247
271
|
this.hasNext = res.hasNext
|
|
@@ -249,6 +273,45 @@ export default{
|
|
|
249
273
|
})
|
|
250
274
|
},
|
|
251
275
|
|
|
276
|
+
patchPresets(){
|
|
277
|
+
|
|
278
|
+
if(!this.columns) return
|
|
279
|
+
|
|
280
|
+
this.presets.forEach((preset) => {
|
|
281
|
+
|
|
282
|
+
const presetColumnKeys = {}
|
|
283
|
+
const removedKeys = []
|
|
284
|
+
for(let i = (preset.columns ?? []).length - 1 ; i >= 0 ; i--){
|
|
285
|
+
const presetColumn = preset.columns[i]
|
|
286
|
+
const presetColumnKey = presetColumn.key
|
|
287
|
+
if(this.columns[presetColumnKey]){
|
|
288
|
+
const updated = {}
|
|
289
|
+
if(this.columns[presetColumnKey].label !== presetColumn.label)
|
|
290
|
+
updated['label'] = this.columns[presetColumnKey].label
|
|
291
|
+
if(this.columns[presetColumnKey].filterable !== presetColumn.filterable)
|
|
292
|
+
updated['filterable'] = this.columns[presetColumnKey].filterable
|
|
293
|
+
if(this.columns[presetColumnKey].sortable !== presetColumn.sortable)
|
|
294
|
+
updated['sortable'] = this.columns[presetColumnKey].sortable
|
|
295
|
+
if(Object.keys(updated).length > 0){
|
|
296
|
+
Object.assign(preset.columns[i], updated)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else{
|
|
300
|
+
preset.columns.splice(i, 1)
|
|
301
|
+
removedKeys.push(presetColumnKey)
|
|
302
|
+
}
|
|
303
|
+
presetColumnKeys[presetColumn.key] = 1
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
for(let key in this.columns){
|
|
307
|
+
if(typeof presetColumnKeys[key] === 'undefined'){
|
|
308
|
+
preset.columns.push(this.columns[key])
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
},
|
|
314
|
+
|
|
252
315
|
load(){
|
|
253
316
|
this.socket.emit(`${this.model}.load`, {
|
|
254
317
|
preset: this.preset
|
|
@@ -281,20 +344,39 @@ export default{
|
|
|
281
344
|
this.load()
|
|
282
345
|
},
|
|
283
346
|
|
|
284
|
-
selectPreset(preset
|
|
347
|
+
selectPreset(preset){
|
|
285
348
|
this.presetIdx = this.presets.findIndex((_) => _ === preset)
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
openPreset(){
|
|
352
|
+
this.layout.presetOpen = true
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
closePreset(){
|
|
356
|
+
this.layout.presetOpen = false
|
|
289
357
|
},
|
|
290
358
|
|
|
291
359
|
copyPreset(){
|
|
292
|
-
const preset =
|
|
360
|
+
const preset = JSON.parse(JSON.stringify(this.preset))
|
|
293
361
|
preset.name += '(Copy)'
|
|
294
362
|
this.presets.push(preset)
|
|
295
363
|
this.presetIdx = this.presets.length - 1
|
|
296
364
|
},
|
|
297
365
|
|
|
366
|
+
removePreset(){
|
|
367
|
+
if(this.presets.length <= 1){
|
|
368
|
+
this.alert('Unable to remove preset')
|
|
369
|
+
}
|
|
370
|
+
else{
|
|
371
|
+
this.confirm('Remove this preset?', '', () => {
|
|
372
|
+
this.presets.splice(this.presetIdx, 1)
|
|
373
|
+
if(this.presetIdx > this.presets.length - 1){
|
|
374
|
+
this.presetIdx = this.presets.length - 1
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
|
|
298
380
|
onHooks(module, event, items){
|
|
299
381
|
|
|
300
382
|
console.log('onHooks', module, event, items)
|
|
@@ -339,7 +421,7 @@ export default{
|
|
|
339
421
|
|
|
340
422
|
addFilter(key){
|
|
341
423
|
|
|
342
|
-
const column = this.
|
|
424
|
+
const column = this.columns[key]
|
|
343
425
|
|
|
344
426
|
if(!this.preset.filters){
|
|
345
427
|
this.preset.filters = []
|
|
@@ -49,13 +49,11 @@
|
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
|
-
<div v-else-if="column && column.type === 'enum'">
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
</div>
|
|
58
|
-
|
|
52
|
+
<div v-else-if="column && column.type === 'enum'" class="flex flex-col">
|
|
53
|
+
<Checkbox v-for="(obj, idx) in filter.typeParams" :value="obj.value" v-model="item.value"
|
|
54
|
+
@change="onFilterChange(item)">
|
|
55
|
+
{{ obj.text }}
|
|
56
|
+
</Checkbox>
|
|
59
57
|
</div>
|
|
60
58
|
|
|
61
59
|
<div v-else-if="column && column.type === 'currency'">
|
|
@@ -132,7 +130,7 @@
|
|
|
132
130
|
|
|
133
131
|
export default{
|
|
134
132
|
|
|
135
|
-
emits: [ 'remove' ],
|
|
133
|
+
emits: [ 'remove', 'change' ],
|
|
136
134
|
|
|
137
135
|
props:{
|
|
138
136
|
column: Object,
|
package/src/components/Tabs.vue
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<button v-for="(item, index) in items" :class="tabClass(item)"
|
|
4
4
|
@click="onClick(item)" type="button" >
|
|
5
5
|
<slot v-if="$slots.tab" name="tab" :="{ item, index }"></slot>
|
|
6
|
-
<div v-else>
|
|
6
|
+
<div v-else :class="$style.item">
|
|
7
7
|
{{ item.text }}
|
|
8
8
|
</div>
|
|
9
9
|
</button>
|
|
@@ -65,4 +65,8 @@ export default{
|
|
|
65
65
|
@apply border-b-[2px] border-primary;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
.item{
|
|
69
|
+
@apply whitespace-nowrap overflow-hidden;
|
|
70
|
+
}
|
|
71
|
+
|
|
68
72
|
</style>
|
package/src/index.js
CHANGED
|
@@ -61,6 +61,7 @@ export default{
|
|
|
61
61
|
app.component('Ahref', defineAsyncComponent(() => import("./components/Ahref.vue")))
|
|
62
62
|
app.component('Switch', defineAsyncComponent(() => import("./components/Switch.vue")))
|
|
63
63
|
app.component('Image', defineAsyncComponent(() => import("./components/Image.vue")))
|
|
64
|
+
app.component('ImagePreview', defineAsyncComponent(() => import("./components/ImagePreview.vue")))
|
|
64
65
|
app.component('ImageFullScreen', defineAsyncComponent(() => import("./components/ImageFullScreen.vue")))
|
|
65
66
|
app.component('ListPage1', defineAsyncComponent(() => import("./components/ListPage1.vue")))
|
|
66
67
|
app.component('ListPage2', defineAsyncComponent(() => import("./components/ListPage2.vue")))
|