@mixd-id/web-scaffold 0.1.2301231315 → 0.1.2301231317
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 +3 -1
- package/src/components/Dropdown.vue +7 -1
- package/src/components/Image.vue +7 -4
- package/src/components/ImagePreview.vue +60 -0
- package/src/components/ListPage1.vue +116 -38
- package/src/components/ListPage1Filter.vue +6 -8
- package/src/components/ListPage2.vue +1 -1
- package/src/components/Tabs.vue +5 -1
- package/src/components/TextEditor.vue +85 -0
- package/src/components/Textbox.vue +8 -1
- package/src/components/VirtualScroll.vue +1 -1
- package/src/components/VirtualTable.vue +1 -1
- package/src/index.js +2 -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.2301231317",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite serve",
|
|
7
7
|
"build": "vite build",
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
"dayjs": "^1.11.2",
|
|
28
28
|
"express": "^4.18.1",
|
|
29
29
|
"glob": "^8.0.3",
|
|
30
|
+
"lodash": "^4.17.21",
|
|
30
31
|
"lodash-es": "^4.17.21",
|
|
32
|
+
"lodash.throttle": "^4.1.1",
|
|
31
33
|
"nprogress": "^0.2.0",
|
|
32
34
|
"pinia": "^2.0.14",
|
|
33
35
|
"prismjs": "^1.28.0",
|
|
@@ -48,6 +48,8 @@ export default {
|
|
|
48
48
|
|
|
49
49
|
position: String,
|
|
50
50
|
|
|
51
|
+
width: String,
|
|
52
|
+
|
|
51
53
|
state: {
|
|
52
54
|
type: [ Number, String ],
|
|
53
55
|
default: 1 // 1:normal, -1:disabled, -2:error
|
|
@@ -178,13 +180,17 @@ export default {
|
|
|
178
180
|
|
|
179
181
|
.size-sm select,
|
|
180
182
|
.size-sm input{
|
|
181
|
-
@apply p-
|
|
183
|
+
@apply p-0;
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
.size-sm .arrow{
|
|
185
187
|
@apply p-2
|
|
186
188
|
}
|
|
187
189
|
|
|
190
|
+
.variant-transparent{
|
|
191
|
+
@apply bg-transparent border-transparent hover:border-transparent
|
|
192
|
+
}
|
|
193
|
+
|
|
188
194
|
.state--2{
|
|
189
195
|
@apply border-red-500
|
|
190
196
|
}
|
package/src/components/Image.vue
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<div :class="$style.img">
|
|
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>
|
|
6
7
|
</template>
|
|
7
8
|
|
|
8
9
|
<script>
|
|
@@ -24,6 +25,8 @@ export default{
|
|
|
24
25
|
|
|
25
26
|
class: String,
|
|
26
27
|
|
|
28
|
+
outerClass: String,
|
|
29
|
+
|
|
27
30
|
editable:{
|
|
28
31
|
type: [ Boolean, String ],
|
|
29
32
|
default: false
|
|
@@ -48,8 +51,7 @@ export default{
|
|
|
48
51
|
|
|
49
52
|
computedClass(){
|
|
50
53
|
return [
|
|
51
|
-
this.class
|
|
52
|
-
this.$style.img
|
|
54
|
+
this.class
|
|
53
55
|
]
|
|
54
56
|
.join(' ')
|
|
55
57
|
},
|
|
@@ -152,6 +154,7 @@ export default{
|
|
|
152
154
|
<style module>
|
|
153
155
|
|
|
154
156
|
.img{
|
|
157
|
+
@apply relative
|
|
155
158
|
}
|
|
156
159
|
|
|
157
160
|
|
|
@@ -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 !bg-transparent !w-screen !h-screen !bg-base-300/80;
|
|
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>
|
|
@@ -173,7 +179,7 @@
|
|
|
173
179
|
|
|
174
180
|
<script>
|
|
175
181
|
|
|
176
|
-
import
|
|
182
|
+
import throttle from "lodash.throttle";
|
|
177
183
|
|
|
178
184
|
export default{
|
|
179
185
|
|
|
@@ -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: [],
|
|
@@ -240,8 +258,10 @@ export default{
|
|
|
240
258
|
|
|
241
259
|
patch(){
|
|
242
260
|
this.socketEmit(`${this.model}.patch`, {}, (res) => {
|
|
261
|
+
this.columns = res.columns
|
|
243
262
|
this.presets = res.presets
|
|
244
263
|
this.presetIdx = res.presetIdx
|
|
264
|
+
this.patchPresets()
|
|
245
265
|
this.$nextTick(() => {
|
|
246
266
|
this.items = res.items
|
|
247
267
|
this.hasNext = res.hasNext
|
|
@@ -249,6 +269,45 @@ export default{
|
|
|
249
269
|
})
|
|
250
270
|
},
|
|
251
271
|
|
|
272
|
+
patchPresets(){
|
|
273
|
+
|
|
274
|
+
if(!this.columns) return
|
|
275
|
+
|
|
276
|
+
this.presets.forEach((preset) => {
|
|
277
|
+
|
|
278
|
+
const presetColumnKeys = {}
|
|
279
|
+
const removedKeys = []
|
|
280
|
+
for(let i = (preset.columns ?? []).length - 1 ; i >= 0 ; i--){
|
|
281
|
+
const presetColumn = preset.columns[i]
|
|
282
|
+
const presetColumnKey = presetColumn.key
|
|
283
|
+
if(this.columns[presetColumnKey]){
|
|
284
|
+
const updated = {}
|
|
285
|
+
if(this.columns[presetColumnKey].label !== presetColumn.label)
|
|
286
|
+
updated['label'] = this.columns[presetColumnKey].label
|
|
287
|
+
if(this.columns[presetColumnKey].filterable !== presetColumn.filterable)
|
|
288
|
+
updated['filterable'] = this.columns[presetColumnKey].filterable
|
|
289
|
+
if(this.columns[presetColumnKey].sortable !== presetColumn.sortable)
|
|
290
|
+
updated['sortable'] = this.columns[presetColumnKey].sortable
|
|
291
|
+
if(Object.keys(updated).length > 0){
|
|
292
|
+
Object.assign(preset.columns[i], updated)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else{
|
|
296
|
+
preset.columns.splice(i, 1)
|
|
297
|
+
removedKeys.push(presetColumnKey)
|
|
298
|
+
}
|
|
299
|
+
presetColumnKeys[presetColumn.key] = 1
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for(let key in this.columns){
|
|
303
|
+
if(typeof presetColumnKeys[key] === 'undefined'){
|
|
304
|
+
preset.columns.push(this.columns[key])
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
},
|
|
310
|
+
|
|
252
311
|
load(){
|
|
253
312
|
this.socket.emit(`${this.model}.load`, {
|
|
254
313
|
preset: this.preset
|
|
@@ -268,7 +327,7 @@ export default{
|
|
|
268
327
|
})
|
|
269
328
|
},
|
|
270
329
|
|
|
271
|
-
savePreset:
|
|
330
|
+
savePreset: throttle(function(preset) {
|
|
272
331
|
this.socket.emit('user.save-preset', { key:this.model, preset:{
|
|
273
332
|
presetIdx: this.presetIdx,
|
|
274
333
|
presets: this.presets
|
|
@@ -281,20 +340,39 @@ export default{
|
|
|
281
340
|
this.load()
|
|
282
341
|
},
|
|
283
342
|
|
|
284
|
-
selectPreset(preset
|
|
343
|
+
selectPreset(preset){
|
|
285
344
|
this.presetIdx = this.presets.findIndex((_) => _ === preset)
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
openPreset(){
|
|
348
|
+
this.layout.presetOpen = true
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
closePreset(){
|
|
352
|
+
this.layout.presetOpen = false
|
|
289
353
|
},
|
|
290
354
|
|
|
291
355
|
copyPreset(){
|
|
292
|
-
const preset =
|
|
356
|
+
const preset = JSON.parse(JSON.stringify(this.preset))
|
|
293
357
|
preset.name += '(Copy)'
|
|
294
358
|
this.presets.push(preset)
|
|
295
359
|
this.presetIdx = this.presets.length - 1
|
|
296
360
|
},
|
|
297
361
|
|
|
362
|
+
removePreset(){
|
|
363
|
+
if(this.presets.length <= 1){
|
|
364
|
+
this.alert('Unable to remove preset')
|
|
365
|
+
}
|
|
366
|
+
else{
|
|
367
|
+
this.confirm('Remove this preset?', '', () => {
|
|
368
|
+
this.presets.splice(this.presetIdx, 1)
|
|
369
|
+
if(this.presetIdx > this.presets.length - 1){
|
|
370
|
+
this.presetIdx = this.presets.length - 1
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
|
|
298
376
|
onHooks(module, event, items){
|
|
299
377
|
|
|
300
378
|
console.log('onHooks', module, event, items)
|
|
@@ -339,7 +417,7 @@ export default{
|
|
|
339
417
|
|
|
340
418
|
addFilter(key){
|
|
341
419
|
|
|
342
|
-
const column = this.
|
|
420
|
+
const column = this.columns[key]
|
|
343
421
|
|
|
344
422
|
if(!this.preset.filters){
|
|
345
423
|
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>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
<Textbox v-model="modelValue.text" @blur="$emit('change')" class="border-none"/>
|
|
4
|
+
<div class="bg-base-300 flex flex-row gap-2 border-t-[1px] border-text-200 px-2">
|
|
5
|
+
<Dropdown v-model="modelValue.tagName" size="sm" variant="transparent">
|
|
6
|
+
<option value="default">Default</option>
|
|
7
|
+
<option value="h1">Heading 1</option>
|
|
8
|
+
<option value="h2">Heading 2</option>
|
|
9
|
+
<option value="h3">Heading 3</option>
|
|
10
|
+
<option value="h4">Heading 4</option>
|
|
11
|
+
<option value="h5">Heading 5</option>
|
|
12
|
+
<option value="custom">Custom</option>
|
|
13
|
+
</Dropdown>
|
|
14
|
+
<Dropdown v-if="modelValue.style && modelValue.tagName === 'custom'"
|
|
15
|
+
v-model="modelValue.style.fontFamily" size="sm" variant="transparent">
|
|
16
|
+
<option value="default">Default</option>
|
|
17
|
+
<option value="Arial">Arial</option>
|
|
18
|
+
<option value="Arial Black">Arial Black</option>
|
|
19
|
+
<option value="Impact">Impact</option>
|
|
20
|
+
<option value="Helvetica">Helvetica</option>
|
|
21
|
+
</Dropdown>
|
|
22
|
+
<Dropdown v-if="modelValue.style && modelValue.tagName === 'custom'"
|
|
23
|
+
v-model="modelValue.style.fontSize" size="sm" variant="transparent">
|
|
24
|
+
<option value="default">Default</option>
|
|
25
|
+
<option value="48px">48px</option>
|
|
26
|
+
<option value="42px">42px</option>
|
|
27
|
+
<option value="36px">36px</option>
|
|
28
|
+
<option value="32px">32px</option>
|
|
29
|
+
<option value="28px">28px</option>
|
|
30
|
+
<option value="24px">24px</option>
|
|
31
|
+
<option value="22px">22px</option>
|
|
32
|
+
<option value="21px">21px</option>
|
|
33
|
+
<option value="20px">20px</option>
|
|
34
|
+
<option value="18px">18px</option>
|
|
35
|
+
<option value="16px">16px</option>
|
|
36
|
+
<option value="14px">14px</option>
|
|
37
|
+
<option value="13px">13px</option>
|
|
38
|
+
<option value="12px">12px</option>
|
|
39
|
+
<option value="11px">11px</option>
|
|
40
|
+
</Dropdown>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script>
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* modelValue: { text:"", style:"", tagName:"" }
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
export default{
|
|
52
|
+
|
|
53
|
+
props: {
|
|
54
|
+
|
|
55
|
+
modelValue: Object
|
|
56
|
+
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
mounted() {
|
|
60
|
+
if(this.modelValue){
|
|
61
|
+
if(!this.modelValue.style){
|
|
62
|
+
this.modelValue.style = {
|
|
63
|
+
fontFamily: 'default',
|
|
64
|
+
fontSize: 'default',
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if(!this.modelValue.tagName){
|
|
69
|
+
this.modelValue.tagName = 'default'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
console.log('mounted', this.modelValue)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<style module>
|
|
80
|
+
|
|
81
|
+
.comp{
|
|
82
|
+
@apply flex flex-col border-[1px] border-text-200 bg-base-50 rounded-lg overflow-hidden;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
</style>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<slot name="start"></slot>
|
|
4
4
|
<input :type="type" :disabled="isDisabled" @focus="isActive = true" @blur="onBlur"
|
|
5
5
|
:placeholder="placeholder" :maxlength="maxlength" ref="input" autocomplete="new-password"
|
|
6
|
-
:value="modelValue" @input="
|
|
6
|
+
:value="modelValue ?? value" @input="onInput"
|
|
7
7
|
@keydown="onKeyDown"/>
|
|
8
8
|
<div v-if="!!(errors)">
|
|
9
9
|
<svg :class="$style.svg" width="24" height="24" class="fill-red-500" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -59,6 +59,8 @@ export default{
|
|
|
59
59
|
|
|
60
60
|
modelValue: [ String, Number ],
|
|
61
61
|
|
|
62
|
+
value: String,
|
|
63
|
+
|
|
62
64
|
placeholder: [ String, Number ],
|
|
63
65
|
maxlength: String,
|
|
64
66
|
type: String,
|
|
@@ -126,6 +128,11 @@ export default{
|
|
|
126
128
|
}
|
|
127
129
|
},
|
|
128
130
|
|
|
131
|
+
onInput(e){
|
|
132
|
+
this.$emit('update:modelValue', e.target.value)
|
|
133
|
+
this.$emit('change', e.target.value)
|
|
134
|
+
},
|
|
135
|
+
|
|
129
136
|
onBlur(){
|
|
130
137
|
this.isActive = false
|
|
131
138
|
this.$emit('blur')
|
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")))
|
|
@@ -82,6 +83,7 @@ export default{
|
|
|
82
83
|
app.component('VirtualTable', defineAsyncComponent(() => import("./components/VirtualTable.vue")))
|
|
83
84
|
app.component('Slider', defineAsyncComponent(() => import("./components/Slider.vue")))
|
|
84
85
|
app.component('TabView', defineAsyncComponent(() => import("./components/TabView.vue")))
|
|
86
|
+
app.component('TextEditor', defineAsyncComponent(() => import("./components/TextEditor.vue")))
|
|
85
87
|
app.component('SplitPane', defineAsyncComponent(() => import("./components/SplitPane.vue")))
|
|
86
88
|
|
|
87
89
|
|