@mixd-id/web-scaffold 0.1.230406246 → 0.1.230406248

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