@mixd-id/web-scaffold 0.1.230406001

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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/package.json +71 -0
  4. package/public/images/mixd-logo2.png +0 -0
  5. package/src/App.vue +17 -0
  6. package/src/components/Ahref.vue +34 -0
  7. package/src/components/Alert.vue +160 -0
  8. package/src/components/Button.vue +253 -0
  9. package/src/components/ButtonGroup.vue +101 -0
  10. package/src/components/Carousel.vue +293 -0
  11. package/src/components/ChatTyping.vue +69 -0
  12. package/src/components/Checkbox.vue +152 -0
  13. package/src/components/ContextMenu.vue +261 -0
  14. package/src/components/CopyToClipboard.vue +59 -0
  15. package/src/components/Countdown.vue +213 -0
  16. package/src/components/Datepicker.vue +312 -0
  17. package/src/components/Dropdown.vue +198 -0
  18. package/src/components/DynamicTemplate.vue +44 -0
  19. package/src/components/ErrorText.vue +36 -0
  20. package/src/components/Feed.vue +118 -0
  21. package/src/components/Gmaps.vue +227 -0
  22. package/src/components/Grid.vue +29 -0
  23. package/src/components/GridColumn.vue +31 -0
  24. package/src/components/HTMLEditor.vue +396 -0
  25. package/src/components/Image.vue +207 -0
  26. package/src/components/Image360.vue +140 -0
  27. package/src/components/ImageFullScreen.vue +101 -0
  28. package/src/components/ImagePreview.vue +71 -0
  29. package/src/components/ImportModal.vue +247 -0
  30. package/src/components/ListItem.vue +147 -0
  31. package/src/components/ListPage1.vue +1331 -0
  32. package/src/components/ListPage1Filter.vue +170 -0
  33. package/src/components/Modal.vue +253 -0
  34. package/src/components/OTPField.vue +126 -0
  35. package/src/components/Radio.vue +134 -0
  36. package/src/components/SearchButton.vue +57 -0
  37. package/src/components/Slider.vue +285 -0
  38. package/src/components/SplitPane.vue +129 -0
  39. package/src/components/Switch.vue +89 -0
  40. package/src/components/TabView.vue +106 -0
  41. package/src/components/TableView.vue +201 -0
  42. package/src/components/TableViewHead.vue +159 -0
  43. package/src/components/Tabs.vue +74 -0
  44. package/src/components/TextEditor.vue +85 -0
  45. package/src/components/Textarea.vue +184 -0
  46. package/src/components/Textbox.vue +200 -0
  47. package/src/components/Timepicker.vue +108 -0
  48. package/src/components/Toast.vue +93 -0
  49. package/src/components/VirtualScroll.vue +215 -0
  50. package/src/components/VirtualTable.vue +497 -0
  51. package/src/entry-client.js +27 -0
  52. package/src/entry-server.js +73 -0
  53. package/src/index.css +3 -0
  54. package/src/index.js +255 -0
  55. package/src/main.js +38 -0
  56. package/src/router.js +57 -0
  57. package/src/themes/default/index.js +200 -0
  58. package/src/utils/helpers.js +185 -0
  59. package/src/utils/helpers.mjs +197 -0
  60. package/src/utils/importer.js +156 -0
  61. package/src/utils/listpage1.js +1371 -0
  62. package/src/utils/selection.js +64 -0
@@ -0,0 +1,497 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+ <div :class="$style.header" v-if="visibleColumns.length > 0">
4
+ <table :class="$style.table" ref="tableHead" :style="tableHeadStyle">
5
+ <thead>
6
+ <tr>
7
+ <th v-for="column in visibleColumns" :style="thStyle(column)">
8
+ <slot v-if="$slots['col-' + column.key]" :name="'col-' + column.key" :column="column"></slot>
9
+ <div v-else :class="headerColumnClass(column)">
10
+ <span v-if="column.label && !column.label.startsWith('(')">{{ column.label }}</span>
11
+ </div>
12
+ <div :class="$style.separator" @mousedown="startResize($event, column)"></div>
13
+ </th>
14
+ <th :class="$style.spacer"></th>
15
+ </tr>
16
+ </thead>
17
+ </table>
18
+ </div>
19
+
20
+ <div ref="cont">
21
+ <div ref="scroller" v-if="visibleColumns.length > 0" :class="$style.scroller" :style="scrollerStyle">
22
+ <div :class="$style.spacer" ref="spacer" :style="spacerStyle">
23
+ <table :class="$style.table">
24
+ <thead>
25
+ <tr>
26
+ <th v-for="column in visibleColumns" :style="thStyle(column)"></th>
27
+ <th :class="$style.spacer"></th>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ <tr v-for="(item, index) in visibleItems" :key="item"
32
+ @click="select(item, index)"
33
+ :class="[ selectedIndex === ((item && item.id) ? item.id : visibleStartIndex + index) ? $style.trSelected : '', item._highlight ? $style.highlight : '' ].join(' ')">
34
+ <td v-for="column in visibleColumns">
35
+ <slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
36
+ <div v-else :class="columnClass(column)" v-html="formatColumn(item[column.key ?? ''] ?? '', column)"></div>
37
+ </td>
38
+ <td :class="$style.spacer"></td>
39
+ </tr>
40
+ </tbody>
41
+ </table>
42
+ </div>
43
+ </div>
44
+ <div :class="$style.calc" v-if="visibleColumns.length > 0 && items && items.length > 0" ref="calc">
45
+ <table :class="$style.table">
46
+ <tbody>
47
+ <tr>
48
+ <td v-for="column in columns" :style="thStyle(column)">
49
+ <slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="items[0]"></slot>
50
+ <div v-else :class="columnClass(column)" v-html="formatColumn(items[0][column.key ?? ''] ?? '', column)"></div>
51
+ </td>
52
+ <td :class="$style.spacer"></td>
53
+ </tr>
54
+ </tbody>
55
+ </table>
56
+ </div>
57
+ <div v-else-if="visibleColumns.length <= 0" class="text-center p-3 flex-1 min-h-[100%] flex items-center justify-center">
58
+ <h5 class="text-text-300">No active column</h5>
59
+ </div>
60
+ <div v-else class="text-center p-3 flex-1 min-h-[100%] flex items-center justify-center">
61
+ <h5 class="text-text-300">No data available</h5>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script>
68
+
69
+ import throttle from "lodash/throttle";
70
+ import dayjs from "dayjs";
71
+
72
+ const _DEFAULT_COLUMN_WIDTH = '100px'
73
+
74
+ export default{
75
+
76
+ emits: [ 'scroll-end' ],
77
+
78
+ props:{
79
+ columns: Array,
80
+
81
+ items: Array,
82
+
83
+ pinned: Function,
84
+
85
+ defaultColumnWidth: {
86
+ type: String,
87
+ default: _DEFAULT_COLUMN_WIDTH
88
+ },
89
+
90
+ appearances: {
91
+ type: Object,
92
+ default: {}
93
+ }
94
+ },
95
+
96
+ data(){
97
+ return {
98
+ scrollTop: 0,
99
+ scrollLeft: 0,
100
+ itemHeight: 0,
101
+ maxVisibleItems: 0,
102
+ isOnEndScroll: false,
103
+ selectedIndex: -1
104
+ }
105
+ },
106
+
107
+ computed:{
108
+
109
+ visibleStartIndex(){
110
+ return Math.round(this.scrollTop / this.itemHeight)
111
+ },
112
+
113
+ sortedItems(){
114
+ if(!Array.isArray(this.items)) return []
115
+
116
+ if(typeof this.pinned === 'function'){
117
+ const pinnedItems = []
118
+ const unpinnedItems = []
119
+ this.items.forEach((item) => {
120
+ if(this.pinned(item))
121
+ pinnedItems.push(item)
122
+ else
123
+ unpinnedItems.push(item)
124
+ })
125
+
126
+ return [
127
+ ...pinnedItems,
128
+ ...unpinnedItems
129
+ ]
130
+ }
131
+ return this.items
132
+ },
133
+
134
+ visibleItems(){
135
+ if(this.itemHeight <= 0) return []
136
+ return this.sortedItems.slice(this.visibleStartIndex, this.visibleStartIndex + this.maxVisibleItems)
137
+ },
138
+
139
+ spacerStyle(){
140
+ return {
141
+ transform: "translateY(" + (this.visibleStartIndex * this.itemHeight) + "px)"
142
+ }
143
+ },
144
+
145
+ scrollerStyle(){
146
+ if(!this.items || this.items.length < 1)
147
+ return {}
148
+
149
+ const height = (this.items.length * this.itemHeight)
150
+ const width = this.visibleColumns.reduce((r, item) => r + parseInt(item.width ?? _DEFAULT_COLUMN_WIDTH), 0)
151
+
152
+ //console.log('scrollerStyle', { width, height, columns:this.columns })
153
+
154
+ return {
155
+ height: height + 'px',
156
+ width: width + 'px'
157
+ }
158
+ },
159
+
160
+ tableHeadStyle(){
161
+ return {
162
+ transform: "translate3d(" + (this.scrollLeft * -1) + "px, 0, 0)"
163
+ }
164
+ },
165
+
166
+ visibleColumns(){
167
+ const columns = this.columns.filter(_ => _.visible)
168
+ return columns
169
+ }
170
+
171
+ },
172
+
173
+ mounted(){
174
+
175
+ this.$refs.cont.addEventListener(
176
+ "scroll",
177
+ this.handleScroll,
178
+ this.passiveScrollSupported() ? { passive: true } : false
179
+ )
180
+
181
+ this.resize()
182
+
183
+ },
184
+
185
+ methods: {
186
+
187
+ select(item, index){
188
+ this.selectedIndex = (item && item.id) ? item.id : this.visibleStartIndex + index
189
+ if(item._highlight){
190
+ delete item._highlight
191
+ }
192
+ },
193
+
194
+ thStyle(column){
195
+ const width = parseInt(column.width ?? this.defaultColumnWidth)
196
+ return {
197
+ width: width + 'px'
198
+ }
199
+ },
200
+
201
+ async resize(){
202
+
203
+ this.$nextTick(() => {
204
+ if(this.$refs.calc){
205
+ const elHeight = parseInt(window.getComputedStyle(this.$el).height !== '0px' ?
206
+ window.getComputedStyle(this.$el).height :
207
+ window.getComputedStyle(this.$el).maxHeight)
208
+ this.itemHeight = parseInt(window.getComputedStyle(this.$refs.calc).height)
209
+ this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.items.length
210
+
211
+ //console.log('Virtual table scroll resize', { elHeight, itemHeight:this.itemHeight, maxVisibleItems:this.maxVisibleItems })
212
+
213
+ if(this.itemHeight <= 0){
214
+ console.error('[VirtualTable] Unable to calculate item height, make sure not async component.')
215
+ }
216
+ }
217
+ })
218
+
219
+ },
220
+
221
+ handleScroll: throttle(function(){
222
+ this.scrollTop = this.$refs.cont.scrollTop
223
+ this.scrollLeft = this.$refs.cont.scrollLeft
224
+
225
+ if(this.scrollTop > this.$refs.scroller.offsetHeight - this.$refs.cont.clientHeight - this.itemHeight){
226
+ if(!this.isOnEndScroll){
227
+ this.$emit('scroll-end')
228
+ this.isOnEndScroll = true
229
+ }
230
+ }
231
+ else{
232
+ if(this.isOnEndScroll){
233
+ this.isOnEndScroll = false
234
+ }
235
+ }
236
+ }, 10),
237
+
238
+ passiveScrollSupported() {
239
+ let passiveSupported = false;
240
+
241
+ try {
242
+ const options = {
243
+ get passive() {
244
+ passiveSupported = true;
245
+ return false;
246
+ }
247
+ };
248
+ window.addEventListener("test", null, options);
249
+ window.removeEventListener("test", null, options);
250
+ } catch (err) {
251
+ passiveSupported = false;
252
+ }
253
+ return passiveSupported;
254
+ },
255
+
256
+ startResize(e, column){
257
+
258
+ const idx = this.columns.findIndex((_) => _ === column)
259
+ let x1 = e.touches ? e.touches[0].clientX : e.clientX
260
+
261
+ const onMouseMove = (e) => {
262
+ const x2 = e.touches ? e.touches[0].clientX : e.clientX
263
+ const d = x2 - x1
264
+ x1 = x2
265
+
266
+ let width = parseInt(this.columns[idx].width ?? _DEFAULT_COLUMN_WIDTH) + d
267
+ if(width < 20) width = 20
268
+ this.columns[idx].width = width
269
+ }
270
+
271
+ const onMouseUp = (e) => {
272
+ window.removeEventListener('mousemove', onMouseMove)
273
+ window.removeEventListener('mouseup', onMouseUp)
274
+ }
275
+
276
+ window.addEventListener('mousemove', onMouseMove)
277
+ window.addEventListener('mouseup', onMouseUp)
278
+ },
279
+
280
+ columnClass(column){
281
+
282
+ let align
283
+ if(!column.align){
284
+ switch(column.type){
285
+ case 'currency':
286
+ align = 'right'
287
+ break
288
+ }
289
+ }
290
+
291
+ return [
292
+ this.$style.tdDiv,
293
+ this.$style['align-' + align]
294
+ ]
295
+ .join(' ')
296
+ },
297
+
298
+ headerColumnClass(column){
299
+
300
+ let align
301
+ if(!column.align){
302
+ switch(column.type){
303
+ case 'currency':
304
+ align = 'right'
305
+ break
306
+ }
307
+ }
308
+
309
+ return [
310
+ this.$style.headerCol,
311
+ this.$style['align-' + align]
312
+ ]
313
+ },
314
+
315
+ formatColumn(value, column){
316
+
317
+ if(this.appearances[column.key] && this.appearances[column.key].length){
318
+ const formatted = this.appearances[column.key].filter((appearance) => {
319
+ if(appearance.value === value){
320
+ return true
321
+ }
322
+ return false
323
+ }).pop()
324
+
325
+ if(formatted){
326
+ const fStyle = this.$style['style' + formatted.style]
327
+ const fColor = this.$style['color-' + formatted.color]
328
+ const fValue = formatted.text ?? value
329
+ return `<div class="${fStyle} ${fColor}">${fValue}</div>`
330
+ }
331
+ }
332
+
333
+ let text = value
334
+ let dateFormat, val
335
+ switch(column.type){
336
+
337
+ case 'date':
338
+ dateFormat = column.format ?? 'D MMM YY HH:mm:ss'
339
+ val = dayjs(value)
340
+ text = val.isValid() ? val.format(dateFormat) : value
341
+ break
342
+
343
+ case 'currency':
344
+ const num = parseInt(value)
345
+ text = !isNaN(num) ? num.toLocaleString() : ''
346
+ break
347
+
348
+ case 'enum':
349
+ const enumObj = column.typeParams.filter((_) => _.value === value).pop()
350
+ text = enumObj ? enumObj.text : value
351
+ break
352
+ }
353
+
354
+ return text
355
+ }
356
+
357
+ },
358
+
359
+ watch: {
360
+
361
+ items: {
362
+ deep: true,
363
+ handler(){
364
+ this.resize()
365
+ }
366
+ },
367
+
368
+ columns: {
369
+ deep: true,
370
+ handler(){
371
+ this.resize()
372
+ }
373
+ }
374
+
375
+ }
376
+
377
+ }
378
+
379
+ </script>
380
+
381
+ <style module>
382
+
383
+ .comp{
384
+ @apply flex flex-col overflow-hidden;
385
+ @apply border-[1px] border-text-50 rounded-sm bg-base-500;
386
+ }
387
+
388
+ .comp>*:last-child{
389
+ @apply flex-1 overflow-auto relative max-h-[100vh];
390
+ }
391
+
392
+ .header{
393
+ @apply border-b-[1px] border-text-50 bg-base-500;
394
+ }
395
+
396
+ .headerCol{
397
+ @apply p-2 overflow-hidden text-ellipsis whitespace-nowrap;
398
+ }
399
+
400
+ .scroller{
401
+ position: relative;
402
+ overflow: hidden;
403
+ will-change: auto;
404
+ min-width: 100%;
405
+ @apply bg-base-500;
406
+ }
407
+
408
+ .spacer{
409
+ will-change: auto;
410
+ position: relative;
411
+ height: 0;
412
+ }
413
+
414
+ .calc{
415
+ @apply absolute top-[-100vh] invisible;
416
+ }
417
+
418
+ .table{
419
+ @apply border-collapse;
420
+ table-layout: fixed;
421
+ width: 100%;
422
+ }
423
+
424
+ .table th{
425
+ @apply relative text-left;
426
+ }
427
+ .table th:nth-child(odd){
428
+ }
429
+
430
+ .table tbody td{
431
+ @apply border-b-[1px] border-text-50;
432
+ }
433
+ .table tbody td:nth-child(odd){
434
+ }
435
+
436
+ .table tbody tr:hover{
437
+ @apply bg-primary-50;
438
+ }
439
+
440
+ .table tbody tr.trSelected{
441
+ @apply bg-primary-200;
442
+ }
443
+
444
+ .table tbody tr.highlight{
445
+ animation: highlight 1s 1 forwards;
446
+ }
447
+ @keyframes highlight {
448
+ 0% {
449
+ @apply bg-transparent;
450
+ }
451
+
452
+ 100% {
453
+ @apply bg-primary-100;
454
+ }
455
+ }
456
+
457
+ .tdDiv{
458
+ @apply p-2 whitespace-nowrap text-ellipsis overflow-hidden;
459
+ }
460
+
461
+ .separator{
462
+ @apply w-[5px] absolute top-0 bottom-0 right-0 cursor-e-resize border-text-50;
463
+ @apply border-r-[1px];
464
+ }
465
+ .table th:hover .separator{
466
+ @apply border-text-100;
467
+ }
468
+
469
+ .spacer{
470
+ @apply w-full
471
+ }
472
+
473
+ .align-left{ @apply text-left; }
474
+ .align-center{ @apply text-center; }
475
+ .align-right{ @apply text-right; }
476
+
477
+ .style40{
478
+ @apply inline-block m-1 rounded-md px-2 text-sm;
479
+ }
480
+ .style40.color-red{ @apply bg-red-600 text-white; }
481
+ .style40.color-orange{ @apply bg-orange-600 text-white; }
482
+ .style40.color-yellow{ @apply bg-yellow-600 text-white; }
483
+ .style40.color-green{ @apply bg-green-600 text-white; }
484
+ .style40.color-teal{ @apply bg-teal-600 text-white; }
485
+ .style40.color-indigo{ @apply bg-indigo-600 text-white; }
486
+ .style40.color-purple{ @apply bg-purple-600 text-white; }
487
+ .style40.color-fuchsia{ @apply bg-fuchsia-600 text-white; }
488
+
489
+
490
+ .style41{
491
+ @apply inline-block m-1 rounded-md bg-red-600 border-red-400 text-white px-2 text-sm;
492
+ }
493
+ .style42{
494
+ @apply inline-block m-1 rounded-md bg-orange-600 text-white px-2 text-sm;
495
+ }
496
+
497
+ </style>
@@ -0,0 +1,27 @@
1
+ import { createApp } from './main'
2
+ import NProgress from "nprogress";
3
+ import 'nprogress/nprogress.css';
4
+
5
+ const { app, router, pinia } = createApp()
6
+
7
+ if(typeof window.__hydration !== 'undefined'){
8
+ pinia.state.value = window.__hydration ?? {}
9
+ document.getElementById('aHlj').remove()
10
+ document.getElementById('aHlk').remove()
11
+ }
12
+
13
+ NProgress.configure({ showSpinner: false });
14
+
15
+ router.beforeEach(async (to, from, next) => {
16
+ NProgress.start()
17
+ next()
18
+ })
19
+
20
+ router.afterEach(() => {
21
+ NProgress.done()
22
+ })
23
+
24
+ // wait until router is ready before mounting to ensure hydration match
25
+ router.isReady().then(() => {
26
+ app.mount(document.body.firstElementChild)
27
+ })
@@ -0,0 +1,73 @@
1
+ import { createApp } from './main'
2
+ import { renderToString } from 'vue/server-renderer'
3
+ import path, { basename } from 'path'
4
+
5
+ export async function render(req, manifest) {
6
+
7
+ let url = req.originalUrl
8
+ let redirect = undefined
9
+ let cookie = []
10
+
11
+ const { app, router, pinia } = createApp()
12
+
13
+ // set the router to the desired URL before rendering
14
+ router.push({ path:url })
15
+ await router.isReady()
16
+
17
+ const ctx = {}
18
+ const html = await renderToString(app, ctx)
19
+
20
+ const preloadLinks = renderPreloadLinks(ctx.modules, manifest)
21
+ const serializePinia = "null"
22
+ const modalOverlay = ctx.teleports ? ctx.teleports['.bW9k'] ?? '' : ''
23
+ const contextOverlay = ctx.teleports ? ctx.teleports['.Y29u'] ?? '' : ''
24
+ const alertOverlay = ctx.teleports ? ctx.teleports['.YWxl'] ?? '' : ''
25
+ const toastOverlay = ctx.teleports ? ctx.teleports['.dG9h'] ?? '' : ''
26
+
27
+ return [ html, preloadLinks, serializePinia, redirect, cookie, modalOverlay, alertOverlay, contextOverlay, toastOverlay ]
28
+ }
29
+
30
+ function renderPreloadLinks(modules, manifest) {
31
+ let links = ''
32
+ const seen = new Set()
33
+ modules.forEach((id) => {
34
+ const files = manifest[id]
35
+ if (files) {
36
+ files.forEach((file) => {
37
+ if (!seen.has(file)) {
38
+ seen.add(file)
39
+ const filename = basename(file)
40
+ if (manifest[filename]) {
41
+ for (const depFile of manifest[filename]) {
42
+ links += renderPreloadLink(depFile)
43
+ seen.add(depFile)
44
+ }
45
+ }
46
+ links += renderPreloadLink(file)
47
+ }
48
+ })
49
+ }
50
+ })
51
+ return links
52
+ }
53
+
54
+ function renderPreloadLink(file) {
55
+ if (file.endsWith('.js')) {
56
+ return `<link rel="modulepreload" crossorigin href="${file}">`
57
+ } else if (file.endsWith('.css')) {
58
+ return `<link rel="stylesheet" href="${file}">`
59
+ } else if (file.endsWith('.woff')) {
60
+ return ` <link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`
61
+ } else if (file.endsWith('.woff2')) {
62
+ return ` <link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`
63
+ } else if (file.endsWith('.gif')) {
64
+ return ` <link rel="preload" href="${file}" as="image" type="image/gif">`
65
+ } else if (file.endsWith('.jpg') || file.endsWith('.jpeg')) {
66
+ return ` <link rel="preload" href="${file}" as="image" type="image/jpeg">`
67
+ } else if (file.endsWith('.png')) {
68
+ return ` <link rel="preload" href="${file}" as="image" type="image/png">`
69
+ } else {
70
+ // TODO
71
+ return ''
72
+ }
73
+ }
package/src/index.css ADDED
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;