@mixd-id/web-scaffold 0.1.230406338 → 0.1.230406340

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.
Files changed (32) hide show
  1. package/package.json +2 -2
  2. package/src/components/Button.vue +105 -71
  3. package/src/components/Modal.vue +0 -2
  4. package/src/components/Switch.vue +3 -0
  5. package/src/components/VirtualTable.vue +46 -21
  6. package/src/index.js +6 -0
  7. package/src/stores/datasource.js +11 -0
  8. package/src/utils/helpers.mjs +15 -0
  9. package/src/widgets/Dashboard/BarChart.vue +167 -0
  10. package/src/widgets/Dashboard/BarChartSetting.vue +229 -0
  11. package/src/widgets/Dashboard/DatasourceCreator.vue +197 -0
  12. package/src/widgets/Dashboard/DatasourceSelector.vue +63 -20
  13. package/src/widgets/Dashboard/Doughnut.vue +13 -33
  14. package/src/widgets/Dashboard/DoughnutSetting.vue +39 -35
  15. package/src/widgets/Dashboard/Metric.vue +57 -0
  16. package/src/widgets/Dashboard/MetricSetting.vue +116 -0
  17. package/src/widgets/Dashboard/Pie.vue +79 -0
  18. package/src/widgets/Dashboard/PieSetting.vue +84 -0
  19. package/src/widgets/Dashboard/PolarArea.vue +84 -0
  20. package/src/widgets/Dashboard/PolarAreaSetting.vue +84 -0
  21. package/src/widgets/Dashboard/SharingModal.vue +112 -0
  22. package/src/widgets/Dashboard/ViewSelector.vue +25 -13
  23. package/src/widgets/Dashboard/VirtualTableSetting.vue +135 -15
  24. package/src/widgets/Dashboard.vue +870 -97
  25. package/src/widgets/WebPageBuilder4/GridSetting.vue +46 -9
  26. package/src/widgets/WebPageBuilder4/HeightSetting.vue +14 -11
  27. package/src/widgets/WebPageBuilder4/MarginSetting.vue +10 -1
  28. package/src/widgets/WebPageBuilder4/MultiValueSetting.vue +12 -4
  29. package/src/widgets/WebPageBuilder4/PaddingSetting.vue +4 -0
  30. package/src/widgets/WebPageBuilder4/TreeView.vue +5 -2
  31. package/src/widgets/WebPageBuilder4/TreeViewItem.vue +11 -6
  32. package/tailwind.config.js +2 -2
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.230406338",
4
+ "version": "0.1.230406340",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -53,7 +53,7 @@
53
53
  "lodash": "^4.17.21",
54
54
  "md5": "^2.3.0",
55
55
  "nprogress": "^0.2.0",
56
- "pinia": "^2.0.14",
56
+ "pinia": "^2.0.2",
57
57
  "prismjs": "^1.28.0",
58
58
  "redis": "^4.6.13",
59
59
  "serve-static": "^1.15.0",
@@ -45,9 +45,9 @@ export default{
45
45
 
46
46
  },
47
47
 
48
- computed:{
48
+ computed: {
49
49
 
50
- compClass(){
50
+ compClass() {
51
51
 
52
52
  return [
53
53
  this.$style.button,
@@ -60,20 +60,20 @@ export default{
60
60
  .join(' ')
61
61
  },
62
62
 
63
- isDisabled(){
63
+ isDisabled() {
64
64
  return parseInt(this.computedState) !== 1
65
65
  },
66
66
 
67
- isLoading(){
67
+ isLoading() {
68
68
  return parseInt(this.computedState) === 2
69
69
  },
70
70
 
71
- computedState(){
71
+ computedState() {
72
72
  return this._state ?? this.state
73
73
  },
74
74
 
75
- widths(){
76
- if(!Array.isArray(this.width)) return [ '', '' ]
75
+ widths() {
76
+ if (!Array.isArray(this.width)) return ['', '']
77
77
 
78
78
  return [
79
79
  this.width[0] ?? '',
@@ -83,59 +83,56 @@ export default{
83
83
 
84
84
  },
85
85
 
86
- data(){
86
+ data() {
87
87
  return {
88
88
  _state: null
89
89
  }
90
90
  },
91
91
 
92
- methods:{
92
+ methods: {
93
93
 
94
- focus(){
94
+ focus() {
95
95
  this.$el.focus()
96
96
  },
97
97
 
98
- setState(state, percentage){
98
+ setState(state, percentage) {
99
99
  this._state = state
100
100
  },
101
101
 
102
- resetState(){
102
+ resetState() {
103
103
  this._state = null
104
104
  },
105
105
 
106
- onClick(){
107
- if('edit-mode' in this.$route.query) return
106
+ onClick() {
107
+ if ('edit-mode' in this.$route.query) return
108
108
 
109
- if(this.isDisabled){
109
+ if (this.isDisabled) {
110
110
  this.$emit('disabled-click')
111
- }
112
- else{
113
- if(this.target){
114
- switch(this.targetType){
111
+ } else {
112
+ if (this.target) {
113
+ switch (this.targetType) {
115
114
 
116
115
  case 'section':
117
116
  this.scrollTo(this.target)
118
117
  break
119
118
 
120
119
  default:
121
- if(this.target.indexOf('://') >= 0){
120
+ if (this.target.indexOf('://') >= 0) {
122
121
  window.location = this.target
123
- }
124
- else{
122
+ } else {
125
123
  this.$router.push(this.target)
126
124
  }
127
125
  break
128
126
  }
129
- }
130
- else{
127
+ } else {
131
128
  this.$emit('click')
132
129
  }
133
130
  }
134
131
  },
135
132
 
136
- scrollTo(exp){
133
+ scrollTo(exp) {
137
134
  const el = document.querySelector('._' + exp.substring(0, 4))
138
- if(el){
135
+ if (el) {
139
136
  window.scrollTo({
140
137
  top: el.offsetTop - 100,
141
138
  behavior: 'smooth'
@@ -151,165 +148,202 @@ export default{
151
148
 
152
149
  <style module>
153
150
 
154
- .button{
151
+ .button {
155
152
  @apply p-2;
156
153
  @apply relative flex items-center justify-center;
157
154
  @apply whitespace-nowrap text-ellipsis overflow-hidden;
158
155
  @apply rounded-lg appearance-none;
159
156
  }
160
- .button>*:first-child{
157
+
158
+ .button > *:first-child {
161
159
  @apply flex items-center justify-center
162
160
  }
163
- .button-disabled{
161
+
162
+ .button-disabled {
164
163
  @apply text-opacity-50;
165
164
  }
166
- .button:active{
165
+
166
+ .button:active {
167
167
  @apply top-[1px] left-[1px] relative;
168
168
  }
169
169
 
170
- .button-primary{
170
+ .button-primary {
171
171
  @apply bg-primary-500 text-white rounded-lg;
172
172
  box-shadow: 0 2px 1px rgba(0, 0, 0, .05);
173
173
  border: solid 1px rgb(var(--primary-500));
174
174
  }
175
- .button-primary:focus{
175
+
176
+ .button-primary:focus {
176
177
  border-color: rgb(var(--primary-600));
177
178
  }
178
- .button-primary:hover{
179
+
180
+ .button-primary:hover {
179
181
  @apply bg-primary-600;
180
182
  }
183
+
181
184
  .button-primary-disabled,
182
- .button-primary-disabled:hover{
185
+ .button-primary-disabled:hover {
183
186
  @apply bg-primary-500 top-0 left-0 cursor-not-allowed text-opacity-50;
184
187
  @apply top-0 left-0;
185
188
  }
186
- .button-primary *{
189
+
190
+ .button-primary * {
187
191
  @apply text-white fill-white;
188
192
  }
189
- .button-primary.loading *{
193
+
194
+ .button-primary.loading * {
190
195
  @apply fill-transparent
191
196
  }
192
- .button-primary .svgBg{
197
+
198
+ .button-primary .svgBg {
193
199
  stroke: #fff;
194
200
  stroke-opacity: 25%;
195
201
  }
196
- .button-primary .svgHg{
202
+
203
+ .button-primary .svgHg {
197
204
  fill: #fff;
198
205
  fill-opacity: 75%;
199
206
  }
200
207
 
201
- .button-outline{
208
+ .button-outline {
202
209
  @apply bg-transparent text-primary-500 border-[1px] border-primary;
203
210
  }
204
- .button-outline:hover{
211
+
212
+ .button-outline:hover {
205
213
  }
214
+
206
215
  .button-outline-disabled,
207
- .button-outline-disabled:hover{
216
+ .button-outline-disabled:hover {
208
217
  @apply top-0 left-0 cursor-not-allowed;
209
218
  @apply text-text border-primary-500 text-opacity-50;
210
219
  }
211
- .button-outline *{
220
+
221
+ .button-outline * {
212
222
  @apply text-primary-500 fill-primary-500;
213
223
  }
214
- .button-outline.loading *{
224
+
225
+ .button-outline.loading * {
215
226
  @apply fill-transparent
216
227
  }
217
- .button-outline .svgBg{
228
+
229
+ .button-outline .svgBg {
218
230
  stroke: rgb(var(--primary-600));
219
231
  stroke-opacity: 50%;
220
232
  }
221
- .button-outline .svgHg{
233
+
234
+ .button-outline .svgHg {
222
235
  fill: rgb(var(--primary-500));
223
236
  fill-opacity: 100%;
224
237
  }
225
238
 
226
- .button-secondary{
239
+ .button-secondary {
227
240
  @apply bg-secondary-500 border-secondary-500 text-primary-700 rounded-lg text-white;
228
241
  border: solid 1px rgb(var(--secondary-500));
229
242
  }
230
- .button-secondary:hover{
243
+
244
+ .button-secondary:hover {
231
245
  @apply bg-secondary-600 border-secondary-600;
232
246
  }
247
+
233
248
  .button-secondary-disabled,
234
- .button-secondary-disabled:hover{
249
+ .button-secondary-disabled:hover {
235
250
  @apply bg-secondary-400 border-secondary-400 cursor-not-allowed text-opacity-50;
236
251
  }
237
- .button-secondary *{
252
+
253
+ .button-secondary * {
238
254
  @apply text-text-500 fill-white;
239
255
  }
240
- .button-secondary.loading *{
256
+
257
+ .button-secondary.loading * {
241
258
  @apply fill-transparent
242
259
  }
243
- .button-secondary .svgBg{
260
+
261
+ .button-secondary .svgBg {
244
262
  stroke: rgb(var(--text-400));
245
263
  stroke-opacity: 25%;
246
264
  }
247
- .button-secondary .svgHg{
265
+
266
+ .button-secondary .svgHg {
248
267
  fill: rgb(var(--text-500));
249
268
  fill-opacity: 75%;
250
269
  }
251
270
 
252
- .button-red{
271
+ .button-red {
253
272
  @apply bg-red-500 text-white rounded-md border-[2px] border-red-500;
254
273
  }
255
- .button-red:hover{
274
+
275
+ .button-red:hover {
256
276
  @apply bg-red-600 border-red-600;
257
277
  }
278
+
258
279
  .button-red-disabled,
259
- .button-red-disabled:hover{
280
+ .button-red-disabled:hover {
260
281
  @apply bg-red-500 border-red-500 top-0 left-0 cursor-not-allowed text-opacity-50;
261
282
  }
262
- .button-red *{
283
+
284
+ .button-red * {
263
285
  @apply text-white fill-white;
264
286
  }
265
- .button-red.loading *{
287
+
288
+ .button-red.loading * {
266
289
  @apply fill-transparent
267
290
  }
268
- .button-red .svgBg{
291
+
292
+ .button-red .svgBg {
269
293
  @apply stroke-red-400;
270
294
  stroke-opacity: 50%;
271
295
  }
272
- .button-red .svgHg{
296
+
297
+ .button-red .svgHg {
273
298
  @apply fill-text-500;
274
299
  fill-opacity: 100%;
275
300
  }
276
301
 
277
- .button-minimal{
302
+ .button-minimal {
278
303
  @apply border-[2px] border-transparent;
279
304
  }
280
- .button-minimal:hover{
305
+
306
+ .button-minimal:hover {
281
307
  }
282
- .button-minimal .svgBg{
308
+
309
+ .button-minimal .svgBg {
283
310
  stroke: rgb(var(--text-500));
284
311
  stroke-opacity: 25%;
285
312
  }
286
- .button-minimal .svgHg{
313
+
314
+ .button-minimal .svgHg {
287
315
  fill: rgb(var(--text));
288
316
  fill-opacity: 75%;
289
317
  }
290
318
 
291
- .loadingPane{
319
+ .loadingPane {
292
320
  @apply absolute left-0 top-0 right-0 bottom-0 flex items-center justify-center pl-1;
293
321
  }
294
- .loading{
322
+
323
+ .loading {
295
324
  color: transparent;
296
325
  }
297
- .loading>*:first-child{
326
+
327
+ .loading > *:first-child {
298
328
  @apply opacity-0
299
329
  }
300
- .loading:hover{
330
+
331
+ .loading:hover {
301
332
  }
302
- .loading:active{
333
+
334
+ .loading:active {
303
335
  @apply top-0 left-0;
304
336
  }
305
- .loading>*{
337
+
338
+ .loading > * {
306
339
  opacity: 0;
307
340
  }
308
- .loading .loadingPane{
341
+
342
+ .loading .loadingPane {
309
343
  opacity: 1;
310
344
  }
311
345
 
312
- .spinner{
346
+ .spinner {
313
347
  @apply animate-spin h-5 w-5;
314
348
  }
315
349
 
@@ -331,10 +331,8 @@ export default{
331
331
  @apply panel-400;
332
332
  @apply border-[1px] border-text-50 z-20 flex max-h-[90vh];
333
333
  @apply rounded-xl overflow-hidden transition-all;
334
- background-color: rgba(255, 255, 255, .6)
335
334
  }
336
335
  html[data-theme='dark'] .modal{
337
- background-color: rgba(0, 0, 0, .6)
338
336
  }
339
337
 
340
338
  .modal.v-show{
@@ -91,6 +91,9 @@ export default{
91
91
  .switch>input:checked + label>span{
92
92
  @apply ml-[1.3rem] border-base bg-white
93
93
  }
94
+ .switch>input:checked:disabled + label{
95
+ @apply bg-text-50;
96
+ }
94
97
 
95
98
  .switch>input:checked + label + *,
96
99
  .switch>input:not(:checked) + label + * + *{
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <div :class="$style.comp">
3
+
3
4
  <div :class="$style.header" v-if="visibleColumns.length > 0">
4
5
  <table :class="$style.table" ref="tableHead" :style="tableHeadStyle">
5
6
  <thead>
@@ -62,21 +63,21 @@
62
63
  <div v-else-if="visibleColumns.length <= 0 && Array.isArray(columns)" class="text-center p-3 flex-1 min-h-[100%] flex items-center justify-center">
63
64
  <h5 class="text-text-300">No active column</h5>
64
65
  </div>
65
- <div v-else-if="Array.isArray(items) && items.length <= 0" class="text-center p-3 flex-1 min-h-[100%] flex items-center justify-center">
66
+ <div v-else-if="Array.isArray(cItems) && cItems.length <= 0" class="text-center p-3 flex-1 min-h-[100%] flex items-center justify-center">
66
67
  <h5 class="text-text-300">No data available</h5>
67
68
  </div>
68
69
 
69
- <div :class="$style.calc" v-if="visibleColumns.length > 0 && items && items.length > 0" ref="calc">
70
+ <div :class="$style.calc" v-if="visibleColumns.length > 0 && cItems && cItems.length > 0" ref="calc">
70
71
  <table :class="$style.table">
71
72
  <tbody>
72
- <tr>
73
- <td v-for="column in columns" :style="thStyle(column)" :class="thClass(column)">
74
- <slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="items[0]"></slot>
75
- <slot v-else-if="$slots.default" name="default" :column="column" :item="items[0]"></slot>
76
- <div v-else :class="columnClass(column)" v-html="formatColumn(items[0] ?? {}, column)"></div>
77
- </td>
78
- <td :class="$style.spacer"></td>
79
- </tr>
73
+ <tr>
74
+ <td v-for="column in cColumns" :style="thStyle(column)" :class="thClass(column)">
75
+ <slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="cItems[0]"></slot>
76
+ <slot v-else-if="$slots.default" name="default" :column="column" :item="cItems[0]"></slot>
77
+ <div v-else :class="columnClass(column)" v-html="formatColumn(cItems[0] ?? {}, column)"></div>
78
+ </td>
79
+ <td :class="$style.spacer"></td>
80
+ </tr>
80
81
  </tbody>
81
82
  </table>
82
83
  </div>
@@ -89,11 +90,19 @@
89
90
  import throttle from "lodash/throttle";
90
91
  import dayjs from "dayjs";
91
92
  import {accessNestedObject} from "../utils/helpers.mjs";
93
+ import {useDatasource} from "../stores/datasource";
92
94
 
93
95
  const _DEFAULT_COLUMN_WIDTH = '100px'
94
96
 
95
97
  export default{
96
98
 
99
+ setup(){
100
+ const datasource = useDatasource()
101
+ return {
102
+ datasource
103
+ }
104
+ },
105
+
97
106
  inject: [ 'listStyle' ],
98
107
 
99
108
  emits: [ 'scroll-end', 'item-click' ],
@@ -109,6 +118,10 @@ export default{
109
118
 
110
119
  pinned: Function,
111
120
 
121
+ datasourceColumns: Array,
122
+
123
+ datasourceUid: String,
124
+
112
125
  defaultColumnWidth: {
113
126
  type: String,
114
127
  default: _DEFAULT_COLUMN_WIDTH
@@ -118,6 +131,10 @@ export default{
118
131
  type: Object,
119
132
  default: {}
120
133
  },
134
+
135
+ type: String,
136
+
137
+ value: Object,
121
138
  },
122
139
 
123
140
  data(){
@@ -134,17 +151,25 @@ export default{
134
151
 
135
152
  computed:{
136
153
 
154
+ cColumns(){
155
+ return this.datasourceColumns ?? this.columns
156
+ },
157
+
158
+ cItems(){
159
+ return this.value?.items ?? this.items
160
+ },
161
+
137
162
  visibleStartIndex(){
138
163
  return Math.floor((this.scrollTop < 0 ? 0 : this.scrollTop) / this.itemHeight)
139
164
  },
140
165
 
141
166
  sortedItems(){
142
- if(!Array.isArray(this.items)) return []
167
+ if(!Array.isArray(this.cItems)) return []
143
168
 
144
169
  if(typeof this.pinned === 'function'){
145
170
  const pinnedItems = []
146
171
  const unpinnedItems = []
147
- this.items.forEach((item) => {
172
+ this.cItems.forEach((item) => {
148
173
  if(this.pinned(item))
149
174
  pinnedItems.push(item)
150
175
  else
@@ -156,7 +181,7 @@ export default{
156
181
  ...unpinnedItems
157
182
  ]
158
183
  }
159
- return this.items
184
+ return this.cItems
160
185
  },
161
186
 
162
187
  visibleItems(){
@@ -171,10 +196,10 @@ export default{
171
196
  },
172
197
 
173
198
  scrollerStyle(){
174
- if(!this.items || this.items.length < 1)
199
+ if(!this.cItems || this.cItems.length < 1)
175
200
  return {}
176
201
 
177
- const height = (this.items.length * this.itemHeight) + (this.state === 2 ? 48 : 0)
202
+ const height = (this.cItems.length * this.itemHeight) + (this.state === 2 ? 48 : 0)
178
203
  const width = this.visibleColumns.reduce((r, item) => r + parseInt(item.width ?? _DEFAULT_COLUMN_WIDTH), 0)
179
204
 
180
205
  return {
@@ -190,7 +215,7 @@ export default{
190
215
  },
191
216
 
192
217
  visibleColumns(){
193
- return (this.columns ?? []).filter(_ => !('visible' in _) || _.visible)
218
+ return (this.cColumns ?? []).filter(_ => !('visible' in _) || _.visible)
194
219
  },
195
220
 
196
221
  visibleColumnKeys(){
@@ -270,7 +295,7 @@ export default{
270
295
  window.getComputedStyle(this.$el).height :
271
296
  window.getComputedStyle(this.$el).maxHeight)
272
297
  this.itemHeight = Math.ceil(parseFloat(window.getComputedStyle(this.$refs.calc).height))
273
- this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.items.length
298
+ this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.cItems.length
274
299
 
275
300
  if(this.itemHeight <= 0 && import.meta.env.DEV){
276
301
  console.error('[VirtualTable] Unable to calculate item height, make sure not async component.')
@@ -319,7 +344,7 @@ export default{
319
344
 
320
345
  startResize(e, column){
321
346
 
322
- const idx = this.columns.findIndex((_) => _ === column)
347
+ const idx = this.cColumns.findIndex((_) => _ === column)
323
348
  let x1 = e.touches ? e.touches[0].clientX : e.clientX
324
349
 
325
350
  const onMouseMove = (e) => {
@@ -327,9 +352,9 @@ export default{
327
352
  const d = x2 - x1
328
353
  x1 = x2
329
354
 
330
- let width = parseInt(this.columns[idx].width ?? _DEFAULT_COLUMN_WIDTH) + d
355
+ let width = parseInt(this.cColumns[idx].width ?? _DEFAULT_COLUMN_WIDTH) + d
331
356
  if(width < 20) width = 20
332
- this.columns[idx].width = width
357
+ this.cColumns[idx].width = width
333
358
  }
334
359
 
335
360
  const onMouseUp = (e) => {
@@ -563,7 +588,7 @@ export default{
563
588
 
564
589
  watch: {
565
590
 
566
- items: {
591
+ cItems: {
567
592
  deep: true,
568
593
  handler(to, from){
569
594
  if((to ?? []).length !== (from ?? []).length){
package/src/index.js CHANGED
@@ -671,6 +671,12 @@ export default{
671
671
  app.component('MenuEditor', defineAsyncComponent(() => import("./widgets/MenuEditor.vue")))
672
672
  app.component('Dashboard', defineAsyncComponent(() => import("./widgets/Dashboard.vue")))
673
673
  app.component('Text', defineAsyncComponent(() => import("./components/Text.vue")))
674
+
675
+ app.component('Doughnut', defineAsyncComponent(() => import("./widgets/Dashboard/Doughnut.vue")))
676
+ app.component('Pie', defineAsyncComponent(() => import("./widgets/Dashboard/Pie.vue")))
677
+ app.component('PolarArea', defineAsyncComponent(() => import("./widgets/Dashboard/PolarArea.vue")))
678
+ app.component('Metric', defineAsyncComponent(() => import("./widgets/Dashboard/Metric.vue")))
679
+ app.component('BarChart', defineAsyncComponent(() => import("./widgets/Dashboard/BarChart.vue")))
674
680
  }
675
681
 
676
682
  }
@@ -0,0 +1,11 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ export const useDatasource = defineStore('datasource', {
4
+
5
+ state: () => ({
6
+ keys: {}
7
+ }),
8
+
9
+ actions: {}
10
+
11
+ })
@@ -360,7 +360,22 @@ function applyDatasourceReplacer(value, datasource){
360
360
  return value
361
361
  }
362
362
 
363
+ function capitalize(str) {
364
+ return str.replace(/\b\w/g, function(char) {
365
+ return char.toUpperCase();
366
+ });
367
+ }
368
+
369
+ const round = (num, precision = 0) => {
370
+ var p = Math.pow(10, precision)
371
+ var n = (num * p) * (1 + Number.EPSILON)
372
+ return Math.round(n) / p
373
+ }
374
+
375
+
363
376
  export {
377
+ capitalize,
378
+ round,
364
379
  downsizeImage,
365
380
  hexToRgb,
366
381
  rgbToHex,