@mixd-id/web-scaffold 0.1.2301231316 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.2301231316",
4
+ "version": "0.1.2301231317",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -23,6 +23,10 @@ export default{
23
23
 
24
24
  props:{
25
25
 
26
+ class: String,
27
+
28
+ outerClass: String,
29
+
26
30
  editable:{
27
31
  type: [ Boolean, String ],
28
32
  default: false
@@ -47,7 +51,7 @@ export default{
47
51
 
48
52
  computedClass(){
49
53
  return [
50
- this.$style.img
54
+ this.class
51
55
  ]
52
56
  .join(' ')
53
57
  },
@@ -150,10 +154,7 @@ export default{
150
154
  <style module>
151
155
 
152
156
  .img{
153
- }
154
-
155
- .img img{
156
- height: 100%;
157
+ @apply relative
157
158
  }
158
159
 
159
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-3">
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="columns" :items="items"
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-2 mb-3">
58
- <input class="flex-1 text-xl bg-transparent outline-none" :value="preset.name" @blur="preset.name = $event.target.value" />
59
- <button @click="layout.presetContextMenu = { caller:$event.target }">
60
- <svg width="21" height="21" viewBox="0 0 24 24" class="fill-text-300 pointer-events-none" xmlns="http://www.w3.org/2000/svg">
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="layout.presetOpen = false">
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="columns" @reorder="reorderColumns">
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
- <input :id="`lp1column${item.key}`" type="checkbox" v-model="item.visible" :true-value="true" :false-value="false" @change="load"/>
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
- </label>
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="preset.columns.filter((_) => _.key === filter.key).pop()"
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="p-2 flex flex-col" v-if="layout.presetTab === 'sort'">
127
- <div v-if="sortableColumns.length > 0">
128
- <div v-for="sort in preset.sorts" class="py-4 border-b-[1px] border-text-100">
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-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
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="py-8">
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
- columns(){
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.preset.columns.filter((_) => _.filterable)
222
+ return Object.values(this.columns).filter((_) => _.filterable)
206
223
  },
207
224
 
208
225
  sortableColumns(){
209
- return this.preset.columns.filter((_) => _.sortable)
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
@@ -281,20 +340,39 @@ export default{
281
340
  this.load()
282
341
  },
283
342
 
284
- selectPreset(preset, edit){
343
+ selectPreset(preset){
285
344
  this.presetIdx = this.presets.findIndex((_) => _ === preset)
286
- if(edit){
287
- this.layout.presetOpen = true
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 = Object.assign({}, this.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.preset.columns.filter((_) => _.key === key).pop()
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
- <div v-for="(obj, idx) in filter.typeParams" class="flex flex-row items-center gap-2">
55
- <input :id="`lp1${filter.key}${idx}`" v-model="item.value" type="checkbox" :value="obj.value" />
56
- <label :for="`lp1${filter.key}${idx}`" class="p-1">{{ obj.text }}</label>
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,
@@ -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")))