@mixd-id/web-scaffold 0.1.230406247 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.230406247",
4
+ "version": "0.1.230406248",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -2,7 +2,7 @@
2
2
  <div v-if="readyState === 1" :class="$style.comp">
3
3
 
4
4
  <div class="p-3 flex flex-col items-start leading-tight">
5
- <small class="text-text-400">Users</small>
5
+ <small class="text-text-400">{{ title ?? 'Untitled' }}</small>
6
6
  <h5 class="inline align-top cursor-pointer hover:text-primary group" @click="$refs.presetSelector.open()">
7
7
  {{ preset.name ?? 'Preset Name' }}
8
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">
@@ -52,6 +52,7 @@ export default{
52
52
 
53
53
  presetKey: undefined,
54
54
  src: undefined,
55
+ title: String,
55
56
  subscribeKey: String,
56
57
  },
57
58
 
@@ -15,6 +15,10 @@
15
15
  @click="editMode = true"
16
16
  @mousedown="(e) => onMouseDown(e, 'bottom')"></div>
17
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
+
18
22
  <button type="button" :class="`${$style.removeBtn} ${editMode ? $style.editMode : ''}`" @click="$emit('remove')">
19
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>
20
24
  </button>
@@ -26,7 +30,7 @@
26
30
 
27
31
  export default{
28
32
 
29
- emits: [ 'class-change', 'remove' ],
33
+ emits: [ 'class-change', 'remove', 'reorder' ],
30
34
 
31
35
  props: {
32
36
 
@@ -53,6 +57,7 @@ export default{
53
57
  return {
54
58
  drag: null,
55
59
  editMode: false,
60
+ oEl: null,
56
61
  }
57
62
  },
58
63
 
@@ -82,16 +87,12 @@ export default{
82
87
 
83
88
  if(Math.abs(distanceX) > 35){
84
89
  const match = this.class.match(/col-span-(\d+)/)
85
- console.log(match)
86
90
  const colSpan = match ? parseInt(match[1]) : 1
87
91
  const nextColSpan = distanceX > 0 ? colSpan + 1 <= 12 ? colSpan + 1 : 12 :
88
92
  colSpan - 1 >= 1 ? colSpan - 1 : 1
89
- console.log(colSpan, nextColSpan)
90
93
 
91
- console.log(2, this.class)
92
94
  const nextClass = match ? this.class.replace(`col-span-${colSpan}`, `col-span-${nextColSpan}`) :
93
95
  `${this.class} col-span-${nextColSpan}`
94
- console.log(2, nextClass)
95
96
 
96
97
  this.drag.x = e.clientX
97
98
  this.$emit('class-change', nextClass)
@@ -100,17 +101,17 @@ export default{
100
101
 
101
102
  case 'bottom':
102
103
  const distanceY = e.clientY - this.drag.y
103
- if(Math.abs(distanceY) > 20){
104
+ if(Math.abs(distanceY) > 70){
104
105
  const match = this.class.match(/row-span-(\d+)/)
105
106
  const rowSpan = match ? parseInt(match[1]) : 1
106
107
  const nextRowSpan = distanceY > 0 ? rowSpan + 1 <= 12 ? rowSpan + 1 : 12 :
107
108
  rowSpan - 1 >= 1 ? rowSpan - 1 : 1
108
109
 
109
- match ? this.class.replace(`row-span-${rowSpan}`, `row-span-${nextRowSpan}`) :
110
- this.class += ` row-span-${nextRowSpan}`
110
+ const nextClass = match ? this.class.replace(`row-span-${rowSpan}`, `row-span-${nextRowSpan}`) :
111
+ `${this.class} row-span-${nextRowSpan}`
111
112
 
112
113
  this.drag.y = e.clientY
113
- this.$emit('class-change', this.class)
114
+ this.$emit('class-change', nextClass)
114
115
  }
115
116
  break
116
117
  }
@@ -131,6 +132,47 @@ export default{
131
132
 
132
133
  },
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
+
134
176
  },
135
177
 
136
178
  watch: {
@@ -138,6 +180,9 @@ export default{
138
180
  editMode(to){
139
181
  to ? window.addEventListener('click', this.checkEditMode) :
140
182
  window.removeEventListener('click', this.checkEditMode)
183
+
184
+ to ? this.$refs.drag.addEventListener('mousedown', this.onDrag) :
185
+ this.$refs.drag.removeEventListener('mousedown', this.onDrag)
141
186
  }
142
187
 
143
188
  }
@@ -151,6 +196,19 @@ export default{
151
196
  .comp{
152
197
  @apply relative flex;
153
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
+ }
154
212
 
155
213
  .top{
156
214
  @apply h-[3px];
@@ -193,4 +251,13 @@ export default{
193
251
  @apply flex;
194
252
  }
195
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
+
196
263
  </style>
@@ -1,91 +1,105 @@
1
1
  <template>
2
- <div v-if="readyState === 1" class="flex-1 flex flex-col gap-4">
3
-
4
- <div class="flex flex-row gap-4 items-center">
5
- <div class="pl-2 flex flex-col leading-tight">
6
- <small class="text-text-400">Users</small>
7
- <h3 class="inline align-top cursor-pointer hover:text-primary group" @click="$refs.presetSelector.open()">
8
- {{ preset.name ?? 'Preset Name' }}
9
- <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">
10
- {{ badgeCount }}
11
- </span>
12
- <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>
13
- </h3>
14
- </div>
15
-
16
- <div class="flex-1"></div>
17
-
18
- <slot name="start"></slot>
19
-
20
- <div class="flex flex-row gap-2 gap-1">
21
- <Textbox class="bg-base-500 w-[240px]" placeholder="Search..." clearable="1"
22
- v-model="preset.search"
23
- @clear="delete preset.search; load()"
24
- @keyup.enter="load">
25
- <template #start>
26
- <div class="p-2 pr-0">
27
- <svg width="16" height="16" class="fill-text-300" 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="M504.1 471l-134-134C399.1 301.5 415.1 256.8 415.1 208c0-114.9-93.13-208-208-208S-.0002 93.13-.0002 208S93.12 416 207.1 416c48.79 0 93.55-16.91 129-45.04l134 134C475.7 509.7 481.9 512 488 512s12.28-2.344 16.97-7.031C514.3 495.6 514.3 480.4 504.1 471zM48 208c0-88.22 71.78-160 160-160s160 71.78 160 160s-71.78 160-160 160S48 296.2 48 208z"/></svg>
28
- </div>
29
- </template>
30
- </Textbox>
31
-
32
- <div class="grid grid-cols-2 gap-[1px]">
33
- <Radio v-model="preset.view"
34
- name="view"
35
- value="table"
36
- :custom="true"
37
- class="p-3 rounded-lg rounded-r-none"
38
- :class="preset.view === 'table' ? 'bg-primary-500' : 'bg-base-500'">
39
- <svg width="14" height="14" :class="preset.view === 'table' ? 'fill-white' : 'fill-text'" 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="M448 32H64.05C28.7 32 .0492 60.65 .0492 96v320c0 35.35 28.65 64 64 64h383.1c35.35 0 64-28.65 64-64V96C512 60.65 483.4 32 448 32zM224 416H64v-96h160V416zM224 256H64V160h160V256zM448 416h-160v-96h160V416zM448 256h-160V160h160V256z"/></svg>
40
- </Radio>
41
- <Radio v-model="preset.view"
42
- name="view"
43
- value="grid"
44
- :custom="true"
45
- class="p-3 bg-base-500 rounded-lg rounded-l-none"
46
- :class="preset.view === 'grid' ? 'bg-primary-500' : 'bg-base-500'">
47
- <svg width="14" height="14" :class="preset.view === 'grid' ? 'fill-white' : 'fill-text'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M144 288h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96C176 302.3 161.7 288 144 288zM368 288h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96C400 302.3 385.7 288 368 288zM592 288h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96C624 302.3 609.7 288 592 288zM144 64h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V96C176 78.33 161.7 64 144 64zM368 64h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V96C400 78.33 385.7 64 368 64zM592 64h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V96C624 78.33 609.7 64 592 64z"/></svg>
48
- </Radio>
49
- </div>
50
- </div>
51
- </div>
2
+ <div class="flex flex-col">
3
+ <div v-if="readyState === 1"
4
+ class="flex-1 flex flex-col gap-3">
5
+
6
+ <slot name="head"
7
+ :preset="preset"
8
+ :badge-count="badgeCount"
9
+ :presetSelector="$refs.presetSelector"
10
+ :compPrefix="compPrefix">
11
+ <div class="flex flex-row gap-3 items-center overflow-hidden leading-tight pl-3">
12
+ <div class="flex flex-col whitespace-nowrap text-ellipsis overflow-hidden">
13
+ <small class="text-text-400">{{ title ?? 'Untitled' }}</small>
14
+ <h3 class="cursor-pointer whitespace-nowrap text-ellipsis overflow-hidden hover:text-primary group"
15
+ @click="$refs.presetSelector.open()">
16
+ {{ preset.name ?? 'Preset Name' }}
17
+ <span v-if="badgeCount > 0" class="inline mx-1 min-w-[19px] px-2 h-[19px] relative top-[-2px] rounded-full bg-primary text-white inline-flex items-center justify-center">
18
+ {{ badgeCount }}
19
+ </span>
20
+ <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>
21
+ </h3>
22
+ </div>
52
23
 
53
- <VirtualTable v-if="preset.view === 'table'"
54
- :columns="columns"
55
- class="flex-1"
56
- :items="users.items"
57
- @scroll-end="loadNext">
58
-
59
- <template v-for="(_, slot) in contentSlots" #[slot]="{ item, index }">
60
- <slot :name="slot" :item="item" :index="index"></slot>
61
- </template>
62
-
63
- </VirtualTable>
64
-
65
- <VirtualGrid v-else-if="preset.view === 'grid'"
66
- :items="users.items"
67
- :column="3"
68
- class="flex-1"
69
- @scroll-end=""
70
- container-class="gap-5"
71
- :config="config">
72
- <template #item="{ item }">
73
- <slot name="gridItem" :item="item">
74
- <div class="flex flex-row bg-base-400 rounded-lg overflow-hidden">
75
- <div>
76
- <Image :src="item.imageUrl" class="bg-text-50 w-[64px] h-[64px]" />
77
- </div>
78
- <div class="flex-1 p-3">
79
- <strong>{{ item.name }}</strong>
24
+ <div class="flex-1"></div>
25
+
26
+ <slot name="toolbar"></slot>
27
+
28
+ <div class="flex flex-row gap-2 gap-1">
29
+ <Textbox class="bg-base-500 w-[240px]" placeholder="Search..." clearable="1"
30
+ v-model="preset.search"
31
+ @clear="delete preset.search; load()"
32
+ @keyup.enter="load">
33
+ <template #start>
34
+ <div class="p-2 pr-0">
35
+ <svg width="16" height="16" class="fill-text-300" 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="M504.1 471l-134-134C399.1 301.5 415.1 256.8 415.1 208c0-114.9-93.13-208-208-208S-.0002 93.13-.0002 208S93.12 416 207.1 416c48.79 0 93.55-16.91 129-45.04l134 134C475.7 509.7 481.9 512 488 512s12.28-2.344 16.97-7.031C514.3 495.6 514.3 480.4 504.1 471zM48 208c0-88.22 71.78-160 160-160s160 71.78 160 160s-71.78 160-160 160S48 296.2 48 208z"/></svg>
36
+ </div>
37
+ </template>
38
+ </Textbox>
39
+
40
+ <div v-if="$slots.gridItem" class="grid grid-cols-2 gap-[1px]">
41
+ <Radio v-model="preset.view"
42
+ name="view"
43
+ value="table"
44
+ :custom="true"
45
+ class="p-3 rounded-lg rounded-r-none"
46
+ :class="preset.view === 'table' ? 'bg-primary-500' : 'bg-base-500'">
47
+ <svg width="16" height="16" :class="preset.view === 'table' ? 'fill-white' : 'fill-text'" 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="M448 32H64.05C28.7 32 .0492 60.65 .0492 96v320c0 35.35 28.65 64 64 64h383.1c35.35 0 64-28.65 64-64V96C512 60.65 483.4 32 448 32zM224 416H64v-96h160V416zM224 256H64V160h160V256zM448 416h-160v-96h160V416zM448 256h-160V160h160V256z"/></svg>
48
+ </Radio>
49
+ <Radio v-model="preset.view"
50
+ name="view"
51
+ value="grid"
52
+ :custom="true"
53
+ class="p-3 bg-base-500 rounded-lg rounded-l-none"
54
+ :class="preset.view === 'grid' ? 'bg-primary-500' : 'bg-base-500'">
55
+ <svg width="16" height="16" :class="preset.view === 'grid' ? 'fill-white' : 'fill-text'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M144 288h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96C176 302.3 161.7 288 144 288zM368 288h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96C400 302.3 385.7 288 368 288zM592 288h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96C624 302.3 609.7 288 592 288zM144 64h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V96C176 78.33 161.7 64 144 64zM368 64h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V96C400 78.33 385.7 64 368 64zM592 64h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V96C624 78.33 609.7 64 592 64z"/></svg>
56
+ </Radio>
80
57
  </div>
81
58
  </div>
82
- </slot>
83
- </template>
84
- </VirtualGrid>
85
59
 
86
- <PresetSelector ref="presetSelector" :config="config" @select="load" />
60
+ <slot name="toolbar2"></slot>
61
+
62
+ </div>
63
+ </slot>
64
+
65
+ <VirtualTable v-if="presetView === 'table'"
66
+ :columns="columns"
67
+ class="flex-1"
68
+ :items="users.items"
69
+ @scroll-end="loadNext">
70
+
71
+ <template v-for="(_, slot) in contentSlots" #[slot]="{ item, index }">
72
+ <slot :name="slot" :item="item" :index="index"></slot>
73
+ </template>
74
+
75
+ </VirtualTable>
76
+
77
+ <VirtualGrid v-else-if="presetView === 'grid'"
78
+ :items="users.items"
79
+ :column="computedGridColumn"
80
+ class="flex-1"
81
+ @scroll-end="loadNext"
82
+ container-class="gap-5"
83
+ :config="config">
84
+ <template #item="{ item }">
85
+ <slot name="gridItem" :item="item">
86
+ <div class="flex flex-row bg-base-400 rounded-lg overflow-hidden">
87
+ <div>
88
+ <Image :src="item.imageUrl" class="bg-text-50 w-[64px] h-[64px]" />
89
+ </div>
90
+ <div class="flex-1 p-3">
91
+ <strong>{{ item.name }}</strong>
92
+ </div>
93
+ </div>
94
+ </slot>
95
+ </template>
96
+ </VirtualGrid>
97
+
98
+ <PresetSelector ref="presetSelector" :config="config" @select="load" />
87
99
 
100
+ </div>
88
101
  </div>
102
+
89
103
  </template>
90
104
 
91
105
  <script>
@@ -95,20 +109,18 @@ import throttle from "lodash/throttle";
95
109
  import PresetSelector from "../widgets/PresetSelector.vue";
96
110
 
97
111
  export default{
98
- components: {PresetSelector, VirtualTable},
99
-
100
- inject: [ 'socket', 'toast' ],
101
112
 
102
113
  props: {
103
-
104
114
  config: {
105
115
  type: Object,
106
116
  default: {}
107
117
  },
108
-
109
118
  presetKey: String,
110
119
  subscribeKey: String,
111
120
  src: undefined,
121
+ title: String,
122
+ view: String,
123
+ gridColumn: [ Number, String ],
112
124
  },
113
125
 
114
126
  methods: {
@@ -153,6 +165,14 @@ export default{
153
165
  return new Promise(resolve => resolve())
154
166
  },
155
167
 
168
+ selectPreset(idx){
169
+ if(this.config.presets[idx]){
170
+ this.config.presetIdx = idx
171
+ this.load()
172
+ this.$refs.presetSelector.close()
173
+ }
174
+ },
175
+
156
176
  savePreset: throttle(function() {
157
177
  if(this.presetKey) {
158
178
  this.socket.send('user.preset',
@@ -160,6 +180,10 @@ export default{
160
180
  }
161
181
  }, 1000, { leading:true }),
162
182
 
183
+ openPresetSelector(){
184
+ this.$refs.presetSelector.open()
185
+ },
186
+
163
187
  onSignal(event, items){
164
188
 
165
189
  switch(event){
@@ -172,14 +196,21 @@ export default{
172
196
  this.socket.send(this.src, {
173
197
  id: items.map(item => item.id)
174
198
  })
175
- .then(({ items }) => items.forEach(item => this.$util.push(this.users.items, item)))
199
+ .then(({ items }) => items.forEach(item => this.$util.push(this.users.items, item)))
176
200
 
177
201
  }
178
202
  },
179
203
 
180
204
  },
181
205
 
206
+
207
+ components: {PresetSelector, VirtualTable},
208
+
209
+ inject: [ 'socket', 'toast' ],
210
+
182
211
  mounted() {
212
+ this.$addResizeListener(this.$el, () => this.compPrefix = this.$util.calculateMediaPrefix(this.$el.clientWidth))
213
+
183
214
  this.loadPreset()
184
215
  .then(() => {
185
216
 
@@ -206,6 +237,8 @@ export default{
206
237
  },
207
238
 
208
239
  unmounted() {
240
+ this.$removeResizeListener(this.$el)
241
+
209
242
  if(this.subscribeKey) {
210
243
  this.socket.send('user.unsubscribe', {name: this.subscribeKey})
211
244
  this.socket.off(this.subscribeKey, this.onSignal)
@@ -215,7 +248,7 @@ export default{
215
248
  computed: {
216
249
 
217
250
  columns(){
218
- return this.config.columns
251
+ return this.preset.columns ?? this.config.columns
219
252
  },
220
253
 
221
254
  contentSlots(){
@@ -227,10 +260,18 @@ export default{
227
260
  return slots
228
261
  },
229
262
 
263
+ computedGridColumn(){
264
+ return this.gridColumn ?? 3
265
+ },
266
+
230
267
  preset(){
231
268
  return ((this.config ?? {}).presets ?? [])[(this.config ?? {}).presetIdx ?? 0] ?? {}
232
269
  },
233
270
 
271
+ presetView(){
272
+ return this.view ?? this.preset.view
273
+ },
274
+
234
275
  },
235
276
 
236
277
  data(){
@@ -240,6 +281,8 @@ export default{
240
281
  users: {
241
282
  itemsPerPage: 15,
242
283
  },
284
+ observer: null,
285
+ compPrefix: '',
243
286
  }
244
287
  },
245
288
 
@@ -260,8 +303,5 @@ export default{
260
303
 
261
304
  <style module>
262
305
 
263
- .comp{
264
-
265
- }
266
306
 
267
307
  </style>
@@ -104,8 +104,6 @@ export default{
104
104
  this.dragItem = this.dragItem.parentNode
105
105
  }
106
106
 
107
- console.log()
108
-
109
107
  this.startIdx = [ ...this.$refs.container.children ].indexOf(this.dragItem)
110
108
  this.targetIdx = -1
111
109
 
@@ -34,7 +34,7 @@ export default{
34
34
 
35
35
  props: {
36
36
 
37
- valueKey: String,
37
+ valueKey: [ String, Number ],
38
38
  value: Object,
39
39
  store: Object,
40
40
 
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <div v-if="type === 'date'" class="flex flex-row gap-2">
3
+ <div class="flex-1 flex flex-row gap-2">
4
+ <Dropdown v-model="value.operator"
5
+ :class="value.operator !== 'between' && (value.operator ?? '').length >= 5 ? 'w-[200px]' : 'w-[100px]'">
6
+ <option value="=">=</option>
7
+ <option value=">">&gt;</option>
8
+ <option value=">=">&gt;=</option>
9
+ <option value="<">&lt;</option>
10
+ <option value="<=">&lt;=</option>
11
+ <option value="between">Between</option>
12
+ <option value="yesterday">Yesterday</option>
13
+ <option value="today">Today</option>
14
+ <option value="thisWeek">This Week</option>
15
+ <option value="thisMonth">This Month</option>
16
+ <option value="thisYear">This Year</option>
17
+ </Dropdown>
18
+ <Datepicker class="w-[150px]" mode="popup" v-model="value.value" />
19
+ <Datepicker v-if="value.operator === 'between'" class="w-[150px]" mode="popup" v-model="value.value2" />
20
+ <button v-if="index >= 1" type="button" class="p-1" @click="$emit('remove')">
21
+ <svg width="14" height="14" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z"/></svg>
22
+ </button>
23
+ </div>
24
+ </div>
25
+
26
+ <div v-else-if="type === 'number'" class="flex flex-row gap-2">
27
+ <Dropdown v-model="value.operator" class="w-[100px]">
28
+ <option value="=">=</option>
29
+ <option value=">">&gt;</option>
30
+ <option value=">=">&gt;=</option>
31
+ <option value="<">&lt;</option>
32
+ <option value="<=">&lt;=</option>
33
+ <option value="in">Multiple with comma</option>
34
+ <option value="notIn">Except with comma</option>
35
+ </Dropdown>
36
+ <Textbox v-model="value.value" />
37
+ </div>
38
+
39
+ <div v-else-if="type === 'boolean'" class="flex flex-row gap-2">
40
+ <Radio :name="value.key" :value="true" v-model="value.value">True</Radio>
41
+ <Radio :name="value.key" :value="false" v-model="value.value">False</Radio>
42
+ </div>
43
+
44
+ <div v-else class="flex flex-row gap-2">
45
+ <Dropdown v-model="value.operator" class="w-[100px]">
46
+ <option value="eq">Equal</option>
47
+ <option value="not">Not Equal</option>
48
+ <option value="startsWith">Starts With</option>
49
+ <option value="endsWith">Ends With</option>
50
+ <option value="contains">Contains</option>
51
+ <option value="notContains">Not Contains</option>
52
+ <option value="in">Multiple with comma</option>
53
+ <option value="notIn">Except with comma</option>
54
+ <option value="regex">Regex</option>
55
+ </Dropdown>
56
+ <Textbox v-model="value.value" />
57
+ </div>
58
+
59
+ </template>
60
+
61
+ <script>
62
+
63
+ export default{
64
+
65
+ emits: [ 'remove' ],
66
+
67
+ props: {
68
+
69
+ index: Number,
70
+ type: String,
71
+ value: Object,
72
+
73
+ }
74
+
75
+ }
76
+
77
+ </script>
78
+
79
+ <style module>
80
+
81
+ .comp{
82
+
83
+ }
84
+
85
+ </style>
@@ -189,13 +189,13 @@ export default{
189
189
  }
190
190
 
191
191
  .comp .tag{
192
- @apply bg-primary text-white p-1 rounded-lg whitespace-nowrap relative top-[-1px];
193
- @apply font-mono text-xs;
192
+ @apply bg-text-100 p-1 rounded-lg whitespace-nowrap relative top-[-1px];
193
+ @apply font-mono text-sm;
194
194
  }
195
195
 
196
196
  .tag2{
197
197
  @apply bg-text-50 p-1 rounded-lg px-2 cursor-pointer;
198
- @apply hover:bg-primary hover:text-white;
198
+ @apply hover:bg-text-100 hover:text-white;
199
199
  }
200
200
 
201
201
  .noScrollbar::-webkit-scrollbar{