@mixd-id/web-scaffold 0.1.230406133 → 0.1.230406135

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.230406133",
4
+ "version": "0.1.230406135",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -0,0 +1,193 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+ <pre class="hidden whitespace-nowrap text-xs overflow-x-auto">{{ options }}</pre>
4
+ <Bar :class="$style.chart" :data="chartData" :options="chartOptions" />
5
+ </div>
6
+ </template>
7
+
8
+ <script>
9
+
10
+ import { Bar } from 'vue-chartjs';
11
+ import Chart from 'chart.js/auto'
12
+ import dayjs from "dayjs";
13
+ import groupBy from "lodash/groupBy";
14
+
15
+ export default{
16
+
17
+ name: 'BarChart',
18
+
19
+ components: { Bar },
20
+
21
+ props: {
22
+
23
+ items: Array,
24
+
25
+ options: Object,
26
+
27
+ },
28
+
29
+ methods: {
30
+
31
+ setInitialData(){
32
+
33
+ const items = []
34
+ const end = new Date();
35
+ const start = new Date(end);
36
+ start.setMinutes(end.getMinutes() - 2);
37
+
38
+ let currentTime = new Date(start);
39
+ while (currentTime <= end) {
40
+
41
+ const count = Math.round(Math.random() * 100)
42
+ for(let i = 0 ; i < count ; i++){
43
+ items.push({
44
+ createdAt: currentTime.toISOString()
45
+ })
46
+ }
47
+
48
+ currentTime.setSeconds(currentTime.getSeconds() + 1);
49
+ }
50
+
51
+ this.items = items
52
+ },
53
+
54
+ play(){
55
+
56
+ const arr = []
57
+ const end = new Date();
58
+ //end.setHours(16, 7, 0, 0)
59
+ const start = new Date(end);
60
+ start.setHours(end.getHours() - 2);
61
+
62
+ let currentTime = new Date(start);
63
+ while (currentTime <= end) {
64
+ arr.push(dayjs(currentTime).format('YYYYMMDDHHmm'))
65
+ currentTime.setMinutes(currentTime.getMinutes() + 1);
66
+ }
67
+
68
+ this.labels = arr
69
+
70
+ /*let count = Math.round(Math.random() * 100)
71
+ if(count < 10) count = 0
72
+ const newItems = []
73
+ for(let i = 0 ; i < count ; i++){
74
+ newItems.push({
75
+ createdAt: currentTime.toISOString()
76
+ })
77
+ }
78
+ this.items.push(...newItems)*/
79
+
80
+ /*window.setTimeout(() => {
81
+ this.play()
82
+ }, 1000)*/
83
+ },
84
+
85
+ },
86
+
87
+ data(){
88
+ return {
89
+ labels: [],
90
+ groupedData: {},
91
+ // items: []
92
+ }
93
+ },
94
+
95
+ mounted() {
96
+
97
+ //this.setInitialData()
98
+
99
+ this.play()
100
+ },
101
+
102
+ computed: {
103
+
104
+ columnKey(){
105
+ return this.options.bar.rows[0].key
106
+ },
107
+
108
+ interval(){
109
+ return this.options.bar.rows[0].format
110
+ },
111
+
112
+ groupedItems(){
113
+ console.log('#1', this.columnKey)
114
+ return groupBy(this.items, (item) => {
115
+ return dayjs(item[this.columnKey]).format('YYYYMMDDHHmm')
116
+ })
117
+ },
118
+
119
+ data(){
120
+ const arr = []
121
+ for(let i = 0 ; i < this.labels.length ; i++){
122
+ arr.push((this.groupedItems[this.labels[i]] ?? []).length)
123
+ }
124
+
125
+ /*if(Array.isArray(this.labels))
126
+ console.log(this.labels[0], this.labels[this.labels.length - 1], Object.keys(this.groupedItems), arr)*/
127
+
128
+ return arr
129
+ },
130
+
131
+ chartData() {
132
+ return {
133
+ labels: this.labels,
134
+ datasets: [ { data: this.data } ],
135
+ }
136
+ },
137
+
138
+ chartOptions() {
139
+
140
+ var style = getComputedStyle(document.body)
141
+ var gridColor = style.getPropertyValue('--text-50')
142
+ var gridColor2 = style.getPropertyValue('--text-200')
143
+
144
+ return {
145
+ responsive: true,
146
+ maintainAspectRatio: false,
147
+ animation: false,
148
+ plugins: {
149
+ legend: {
150
+ display: false, // Disable the legend
151
+ },
152
+ },
153
+ scales: {
154
+ x: {
155
+ display: false, // Disable x-axis labels
156
+ grid: {
157
+ display: true,
158
+ color: function(context){
159
+ return `rgb(${gridColor2})`
160
+ }
161
+ },
162
+ },
163
+ y: {
164
+ beginAtZero: true, // Adjust y-axis as needed
165
+ grid: {
166
+ display: true,
167
+ color: function(context){
168
+ return `rgb(${gridColor})`
169
+ }
170
+ },
171
+ },
172
+ },
173
+ }
174
+ }
175
+
176
+ },
177
+
178
+ }
179
+
180
+ </script>
181
+
182
+ <style module>
183
+
184
+ .comp{
185
+ @apply flex-1;
186
+ }
187
+
188
+ .chart{
189
+ position: relative;
190
+ width: 100%;
191
+ }
192
+
193
+ </style>
@@ -65,6 +65,10 @@ export default{
65
65
 
66
66
  computed:{
67
67
 
68
+ actualSrc(){
69
+ return this.mediaSrc[this.$screenPrefix]
70
+ },
71
+
68
72
  compClass(){
69
73
  return [
70
74
  this.$style.comp,
@@ -89,21 +93,31 @@ export default{
89
93
  data(){
90
94
  return {
91
95
  status: 0, // 0:empty, 1:loading, 2:image, 3:error
92
- actualSrc: 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
93
- moved: false
96
+ moved: false,
97
+ mediaSrc: {},
98
+ visibled: false
94
99
  }
95
100
  },
96
101
 
97
102
  mounted(){
98
103
  this.$observe.once(this.$el, () => {
104
+ this.visibled = true
99
105
  this.loadSrc()
100
106
  })
101
107
 
102
- this.$resize(() => this.loadSrc())
108
+ this.$resize(this.onResize)
103
109
  },
104
110
 
111
+ unmounted() {
112
+ this.$unresize(this.onResize)
113
+ },
114
+
105
115
  methods:{
106
116
 
117
+ onResize(){
118
+ this.loadSrc()
119
+ },
120
+
107
121
  onChange(e){
108
122
  if(e.target.files.length > 0){
109
123
  var reader = new FileReader();
@@ -122,10 +136,20 @@ export default{
122
136
 
123
137
  async loadSrc(){
124
138
 
139
+ // src: String | Array | File
140
+
141
+ if(!this.visibled){
142
+ return
143
+ }
144
+
145
+ if(this.$screenPrefix in this.mediaSrc){
146
+ return
147
+ }
148
+
125
149
  if(typeof this.src === 'string') {
126
150
 
127
151
  if (this.src.startsWith('data:image')) {
128
- this.actualSrc = this.src
152
+ this.mediaSrc[this.$screenPrefix] = this.src
129
153
  this.status = 2
130
154
  }
131
155
  else{
@@ -156,12 +180,12 @@ export default{
156
180
  img.addEventListener('load', () => {
157
181
  if(img.getAttribute('data-src') !== this.src) return
158
182
  this.status = 2
159
- this.actualSrc = img.src
183
+ this.mediaSrc[this.$screenPrefix] = img.src
160
184
  })
161
185
  img.addEventListener('error', (err) => {
162
186
  if(img.getAttribute('data-src') !== this.src) return
163
187
  this.status = 3
164
- this.actualSrc = this.defaultSrc
188
+ this.mediaSrc[this.$screenPrefix] = this.defaultSrc
165
189
  })
166
190
  img.src = imgSrc
167
191
  img.setAttribute('data-src', this.src)
@@ -188,11 +212,11 @@ export default{
188
212
  var img = new Image()
189
213
  img.addEventListener('load', () => {
190
214
  this.status = 2
191
- this.actualSrc = img.src
215
+ this.mediaSrc[this.$screenPrefix] = img.src
192
216
  })
193
217
  img.addEventListener('error', (err) => {
194
218
  this.status = 3
195
- this.actualSrc = this.defaultSrc
219
+ this.mediaSrc[this.$screenPrefix] = this.defaultSrc
196
220
  })
197
221
  img.src = imgSrc
198
222
  this.status = 1
@@ -203,18 +227,17 @@ export default{
203
227
 
204
228
  reader.addEventListener('load', () => {
205
229
  this.status = 2
206
- this.actualSrc = reader.result
230
+ this.mediaSrc[this.$screenPrefix] = reader.result
207
231
  }, false)
208
232
 
209
233
  reader.addEventListener('error', () => {
210
234
  this.status = 3
211
- this.actualSrc = this.defaultSrc
235
+ this.mediaSrc[this.$screenPrefix] = this.defaultSrc
212
236
  })
213
237
 
214
238
  reader.readAsDataURL(this.src)
215
239
  this.status = 1
216
240
  }
217
-
218
241
  },
219
242
 
220
243
  onClick(){
@@ -88,8 +88,9 @@
88
88
  </Textbox>
89
89
  </div>
90
90
 
91
- <div v-if="presetSummary && summary" class="h-[300px] max-h-[30vh] flex">
91
+ <div v-if="presetSummary" class="h-[300px] flex" :class="presetSummary.mode === 'liveBar' ? 'max-h-[20vh]' : 'max-h-[30vh]'">
92
92
  <Bar v-if="presetSummary.mode === 'bar'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
93
+ <ChartBar v-else-if="presetSummary.mode === 'liveBar'" :items="items" :options="presetSummary" class="flex-1"/>
93
94
  <Line v-else-if="presetSummary.mode === 'line'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
94
95
  <VirtualTable v-else-if="presetSummary.mode === 'table'" :items="summaryItems" :columns="summaryColumns" class="flex-1"></VirtualTable>
95
96
  <Gmaps v-else-if="presetSummary.mode === 'map'" :data="summary.items" :config="presetSummary.map"
@@ -345,6 +346,8 @@ export default{
345
346
  break
346
347
  }
347
348
 
349
+ itemsPerPage = 300
350
+
348
351
  this.socketEmit2(this.src, { columns:this.config.columns, preset:this.preset, itemsPerPage })
349
352
  .then((res) => {
350
353
  Object.assign(this.$data, res)
@@ -411,6 +414,7 @@ export default{
411
414
  switch(event){
412
415
 
413
416
  case 'create':
417
+ case 'bulk-create':
414
418
  case 'update':
415
419
  if(items[0] && Object.keys(items[0]).length <= 1 && Object.keys(items[0])[0] === 'uid'){
416
420
  this.socketEmit2(this.src, {
@@ -596,6 +600,7 @@ export default{
596
600
  },
597
601
 
598
602
  chartOptions(){
603
+ if(!this.summary) return {}
599
604
 
600
605
  var style = getComputedStyle(document.body)
601
606
  var gridColor = style.getPropertyValue('--text-50')
@@ -10,6 +10,7 @@
10
10
  </Dropdown>
11
11
  <Dropdown v-model="summary.bar.rows[0].format" class="w-[100px]">
12
12
  <option value="">{{ $t('Default') }}</option>
13
+ <option value="hour">{{ $t('Hour') }}</option>
13
14
  <option value="date">{{ $t('Date') }}</option>
14
15
  <option value="month">{{ $t('Month') }}</option>
15
16
  <option value="quarter">{{ $t('Quarterly') }}</option>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+
4
+ <div class="p-3">
5
+ <label class="text-text-400 flex-1">{{ $t('X-axis') }}</label>
6
+ <div class="flex flex-row mt-2 gap-2">
7
+ <Dropdown v-model="summary.bar.rows[0].key" class="flex-1">
8
+ <option value="" disabled selected>{{ $t('Add Column') }}</option>
9
+ <option v-for="column in columns" :value="column.key">{{ column.label ?? column.key }}</option>
10
+ </Dropdown>
11
+ <Dropdown v-model="summary.bar.rows[0].format" class="w-[100px]">
12
+ <option value="">{{ $t('Default') }}</option>
13
+ <option value="second">{{ $t('Second') }}</option>
14
+ <option value="minute">{{ $t('Minute') }}</option>
15
+ <option value="hour">{{ $t('Hour') }}</option>
16
+ <option value="date">{{ $t('Date') }}</option>
17
+ <option value="month">{{ $t('Month') }}</option>
18
+ <option value="quarter">{{ $t('Quarterly') }}</option>
19
+ <option value="year">{{ $t('Year') }}</option>
20
+ </Dropdown>
21
+ </div>
22
+ </div>
23
+
24
+ </div>
25
+ </template>
26
+
27
+ <script>
28
+
29
+ export default{
30
+
31
+ props: {
32
+
33
+ columns: Array,
34
+
35
+ summary: {
36
+ type: Object,
37
+ required: true
38
+ }
39
+
40
+ }
41
+
42
+ }
43
+
44
+ </script>
45
+
46
+ <style module>
47
+
48
+ .comp{
49
+
50
+ }
51
+
52
+ </style>
@@ -210,6 +210,7 @@
210
210
  <Dropdown v-model="openedPresetSummary.mode" class="flex-1">
211
211
  <option value="table">{{ $t('Table') }}</option>
212
212
  <option value="bar">{{ $t('Bar Chart') }}</option>
213
+ <option value="liveBar">{{ $t('Live Bar Chart') }}</option>
213
214
  <option value="line">{{ $t('Line Chart') }}</option>
214
215
  <option value="map">{{ $t('Maps') }}</option>
215
216
  </Dropdown>
@@ -225,6 +226,9 @@
225
226
  <ListViewBarSummary v-else-if="openedPresetSummary.mode === 'bar'"
226
227
  :summary="openedPresetSummary" :columns="filterableColumns" />
227
228
 
229
+ <ListViewLiveBarSummary v-else-if="openedPresetSummary.mode === 'liveBar'"
230
+ :summary="openedPresetSummary" :columns="filterableColumns" />
231
+
228
232
  <ListViewLineSummary v-else-if="openedPresetSummary.mode === 'line'"
229
233
  :summary="openedPresetSummary" :columns="filterableColumns" />
230
234
 
@@ -280,7 +280,7 @@ export default{
280
280
 
281
281
  .slider>div:nth-child(3),
282
282
  .slider>div:nth-child(4){
283
- @apply absolute w-[2.1rem] h-[2.1rem] rounded-full bg-white shadow-sm border-[1px] border-text-200;
283
+ @apply absolute w-[2.3rem] h-[2.3rem] rounded-full bg-white shadow-sm border-[1px] border-text-200;
284
284
  @apply flex;
285
285
  top: 50%;
286
286
  transform: translate3d(0, -50%, 0);
package/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import {defineAsyncComponent, ref} from "vue"
1
+ import {defineAsyncComponent, reactive, ref} from "vue"
2
2
  import {accessNestedObject, observeInit} from './utils/helpers.mjs'
3
3
  import throttle from "lodash/throttle"
4
4
 
@@ -273,11 +273,12 @@ export default{
273
273
  app.config.globalProperties.$observe = observeInit()
274
274
  }
275
275
 
276
- app.config.globalProperties.$screenPrefix = ref(util.calculateMediaPrefix(window.innerWidth))
276
+ app.config.globalProperties.$screenPrefix = reactive(util.calculateMediaPrefix(window.innerWidth))
277
277
  const onWindowResize = throttle(() => {
278
- app.config.globalProperties.$screenPrefix.value = util.calculateMediaPrefix(window.innerWidth)
278
+ app.config.globalProperties.$screenPrefix = util.calculateMediaPrefix(window.innerWidth)
279
279
  resizeEvents.forEach((fn) => fn())
280
- }, 300, { leading:true })
280
+ console.log('1')
281
+ }, 500, { leading:true })
281
282
 
282
283
  window.addEventListener('resize', onWindowResize)
283
284
  }
@@ -337,6 +338,7 @@ export default{
337
338
  app.component('Block', defineAsyncComponent(() => import("./components/Block.vue")))
338
339
  app.component('Button', defineAsyncComponent(() => import("./components/Button.vue")))
339
340
  app.component('Box', defineAsyncComponent(() => import("./components/Box.vue")))
341
+ app.component('ChartBar', defineAsyncComponent(() => import("./components/ChartBar.vue")))
340
342
  app.component('ColorPicker', defineAsyncComponent(() => import("./components/ColorPicker.vue")))
341
343
  app.component('SearchButton', defineAsyncComponent(() => import("./components/SearchButton.vue")))
342
344
  app.component('ChatTyping', defineAsyncComponent(() => import("./components/ChatTyping.vue")))
@@ -367,6 +369,7 @@ export default{
367
369
  app.component('ListView', defineAsyncComponent(() => import("./components/ListView.vue")))
368
370
  app.component('ListViewSettings', defineAsyncComponent(() => import("./components/ListViewSettings.vue")))
369
371
  app.component('ListViewBarSummary', defineAsyncComponent(() => import("./components/ListViewBarSummary.vue")))
372
+ app.component('ListViewLiveBarSummary', defineAsyncComponent(() => import("./components/ListViewLiveBarSummary.vue")))
370
373
  app.component('ListViewTableSummary', defineAsyncComponent(() => import("./components/ListViewTableSummary.vue")))
371
374
  app.component('ListViewLineSummary', defineAsyncComponent(() => import("./components/ListViewLineSummary.vue")))
372
375
  app.component('ListViewMapSummary', defineAsyncComponent(() => import("./components/ListViewMapSummary.vue")))
@@ -423,6 +423,12 @@ let ListView = {
423
423
  const rowKey = row.key
424
424
  const rowLabel = this.columns.find((_) => _.key === row.key).label
425
425
  switch(row.format){
426
+ case 'minute':
427
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d %H:%i:00') as dfDate`)
428
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d %H:%i:00')`)
429
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"HH:mm" })
430
+ break
431
+
426
432
  case 'date':
427
433
  attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d') as dfDate`)
428
434
  group.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d')`)
@@ -1,17 +1,16 @@
1
1
  <template>
2
2
  <div :class="$style.comp" v-if="Array.isArray(items) && items.length > 0">
3
- <pre></pre>
4
3
  <div v-if="id" :id="id" :class="$style.anchor"></div>
5
4
  <h3>{{ title ?? '' }}</h3>
6
5
  <p v-if="description" class="mt-2 text-lg">{{ description }}</p>
7
6
  <div :class="computedContainerClass">
8
7
  <div v-for="item in items" class="flex gap-4" :class="computedItemClass">
9
8
  <div>
10
- <Image :src="imageUrl(item.imageUrl)" class="bg-gray-200 rounded-xl w-full aspect-square object-contain" />
9
+ <Image :src="imageUrl(item.imageUrl)" :class="`object-contain ${item.sizeClass}`" />
11
10
  </div>
12
- <div class="flex-1 flex flex-col gap-1">
13
- <h5>{{ item.title ?? 'Untitled' }}</h5>
14
- <p>{{ item.description ?? '' }}</p>
11
+ <div class="flex-1 flex flex-col gap-1" v-if="item.title || item.description">
12
+ <h5 v-if="item.title">{{ item.title }}</h5>
13
+ <p v-if="item.description">{{ item.description }}</p>
15
14
  </div>
16
15
  </div>
17
16
  </div>
@@ -36,7 +35,7 @@ export default{
36
35
  type: Array,
37
36
  default: [ 2, 4 ]
38
37
  },
39
- variant: Array
38
+ variant: Array,
40
39
 
41
40
  },
42
41
 
@@ -82,7 +81,7 @@ export default{
82
81
  }
83
82
 
84
83
  .container{
85
- @apply grid gap-6 mt-8;
84
+ @apply grid gap-6 mt-4;
86
85
  }
87
86
 
88
87
  .item{
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="flex-1 flex flex-row items-center gap-2">
3
- {{ item.props.name ?? 'Feature List' }}
3
+ {{ item.props.name ?? (item.props.title ?? 'Feature List') }}
4
4
  </div>
5
5
  </template>
6
6
 
@@ -139,6 +139,27 @@
139
139
  <Textarea v-model="context.image.description" rows="3" placeholder="Description" />
140
140
  </div>
141
141
 
142
+ <div class="flex flex-col gap-1">
143
+ <label class="flex-1 text-text-400">Size</label>
144
+ <Dropdown v-model="context.image.sizeClass" class="w-[100px]">
145
+ <option value="">Unset</option>
146
+ <option value="w-1">1</option>
147
+ <option value="w-2">2</option>
148
+ <option value="w-3">3</option>
149
+ <option value="w-4">4</option>
150
+ <option value="w-5">5</option>
151
+ <option value="w-6">6</option>
152
+ <option value="w-8">8</option>
153
+ <option value="w-12">12</option>
154
+ <option value="w-16">16</option>
155
+ <option value="w-20">20</option>
156
+ <option value="w-28">28</option>
157
+ <option value="w-32">32</option>
158
+ <option value="w-36">36</option>
159
+ <option value="w-48">48</option>
160
+ </Dropdown>
161
+ </div>
162
+
142
163
  </div>
143
164
  </template>
144
165
  </Modal>