@mixd-id/web-scaffold 0.2.240705 → 0.2.250801009

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 (220) hide show
  1. package/docs/components/Dashboard.md +56 -0
  2. package/log.txt +7 -0
  3. package/package.json +27 -19
  4. package/src/components/404.vue +61 -0
  5. package/src/components/AccountIcon.vue +19 -0
  6. package/src/components/Ahref.vue +1 -1
  7. package/src/components/Alert.vue +4 -13
  8. package/src/components/ArrayList.vue +49 -0
  9. package/src/components/Article.vue +24 -30
  10. package/src/components/Button.vue +79 -167
  11. package/src/components/Card.vue +235 -0
  12. package/src/components/Carousel.vue +61 -60
  13. package/src/components/Cart.vue +192 -0
  14. package/src/components/CartIcon.vue +89 -0
  15. package/src/components/ChartBar.vue +2 -3
  16. package/src/components/Checkbox.vue +20 -11
  17. package/src/components/Checkout.vue +373 -0
  18. package/src/components/CheckoutDelivery.vue +267 -0
  19. package/src/components/CodeEditor.vue +5 -16
  20. package/src/components/CollapsiblePanel.vue +70 -0
  21. package/src/components/ColorPicker.vue +8 -3
  22. package/src/components/ColorPicker2.vue +41 -19
  23. package/src/components/ColorPicker3.vue +100 -0
  24. package/src/components/Confirm.vue +9 -7
  25. package/src/components/ContextMenu.vue +122 -206
  26. package/src/components/ContextMenuItem.vue +53 -0
  27. package/src/components/Dashboard.vue +243 -0
  28. package/src/components/Dashboard2.vue +118 -0
  29. package/src/components/DashboardComponentSelector.vue +96 -0
  30. package/src/components/DashboardConfigs.vue +202 -0
  31. package/src/components/Datepicker.vue +102 -41
  32. package/src/components/DayTimeRange.vue +3 -2
  33. package/src/components/Dropdown.vue +7 -4
  34. package/src/components/Flex.vue +14 -40
  35. package/src/components/GHeatMaps.vue +2 -2
  36. package/src/components/Grid.vue +6 -6
  37. package/src/components/HTMLEditor.vue +27 -14
  38. package/src/components/Image.vue +62 -108
  39. package/src/components/ImagePreview.vue +14 -4
  40. package/src/components/ImageUploader.vue +114 -0
  41. package/src/components/ImportModal.vue +3 -3
  42. package/src/components/Link.vue +62 -6
  43. package/src/components/List.vue +524 -402
  44. package/src/components/ListContextMenu.vue +88 -0
  45. package/src/components/ListItem.vue +5 -3
  46. package/src/components/ListPage1.vue +14 -15
  47. package/src/components/ListView.vue +5 -6
  48. package/src/components/ListViewSettings.vue +2 -2
  49. package/src/components/LogViewerItem.vue +1 -1
  50. package/src/components/MarkdownEdit.vue +128 -0
  51. package/src/components/MarkdownPreview.vue +102 -0
  52. package/src/components/MenuItem1.vue +36 -0
  53. package/src/components/Modal.vue +95 -43
  54. package/src/components/MultiDropdown.vue +124 -0
  55. package/src/components/MultilineText.vue +1 -4
  56. package/src/components/OTPField.vue +11 -17
  57. package/src/components/ObjectTree.vue +1 -1
  58. package/src/components/PageBuilder.vue +3 -3
  59. package/src/components/Paragraph.vue +1 -2
  60. package/src/components/PresetSelectorFilterItem.vue +107 -95
  61. package/src/components/Radio.vue +1 -1
  62. package/src/components/SearchModal.vue +153 -0
  63. package/src/components/Slider.vue +1 -1
  64. package/src/components/Svg.vue +1 -1
  65. package/src/components/SvgEditor.vue +173 -0
  66. package/src/components/Switch.vue +4 -5
  67. package/src/components/Table.vue +2 -2
  68. package/src/components/TableView.vue +2 -3
  69. package/src/components/TableViewHead.vue +2 -2
  70. package/src/components/Tabs.vue +1 -1
  71. package/src/components/Testimonial.vue +2 -2
  72. package/src/components/Text.vue +7 -22
  73. package/src/components/TextEditor.vue +3 -3
  74. package/src/components/TextWithTag.vue +61 -30
  75. package/src/components/Textarea.vue +11 -16
  76. package/src/components/Textbox.vue +9 -19
  77. package/src/components/Timepicker.vue +25 -15
  78. package/src/components/Toast.vue +5 -3
  79. package/src/components/TreeMenu.vue +122 -0
  80. package/src/components/TreeView.vue +15 -10
  81. package/src/components/TreeView2.vue +38 -0
  82. package/src/components/TreeViewItem.vue +58 -29
  83. package/src/components/TreeViewItem2.vue +55 -0
  84. package/src/components/Uploader.vue +45 -0
  85. package/src/components/Video.vue +119 -0
  86. package/src/components/VirtualGrid.vue +24 -7
  87. package/src/components/VirtualTable.vue +363 -128
  88. package/src/configs/dashboard/data-table.js +9 -0
  89. package/src/configs/web-page-builder.js +118 -0
  90. package/src/directives/intersect.js +26 -0
  91. package/src/hooks/device.js +14 -0
  92. package/src/index.js +62 -107
  93. package/src/mixin/component.js +147 -67
  94. package/src/themes/default/index.js +83 -155
  95. package/src/utils/dashboard.js +22 -962
  96. package/src/utils/helpers.cjs +635 -0
  97. package/src/utils/helpers.js +91 -60
  98. package/src/utils/helpers.mjs +245 -12
  99. package/src/utils/importer.js +22 -3
  100. package/src/utils/list.mjs +1509 -0
  101. package/src/utils/preset-selector.cjs +1455 -0
  102. package/src/utils/preset-selector.js +489 -95
  103. package/src/utils/preset-selector.mjs +59 -20
  104. package/src/utils/queue.js +63 -0
  105. package/src/utils/web.mjs +120 -0
  106. package/src/utils/wss.js +37 -29
  107. package/src/utils/wss.mjs +24 -19
  108. package/src/widgets/AhrefSetting.vue +16 -13
  109. package/src/widgets/ArticleSetting.vue +15 -27
  110. package/src/widgets/BackgroundColorSetting.vue +153 -0
  111. package/src/widgets/BorderColorSetting.vue +57 -0
  112. package/src/widgets/BotEditor/BotEditorActions.vue +3 -2
  113. package/src/widgets/BotEditor/BotEditorSettings.vue +21 -0
  114. package/src/widgets/BotEditor.vue +35 -15
  115. package/src/widgets/ButtonSetting.vue +12 -13
  116. package/src/widgets/CarouselSetting.vue +33 -45
  117. package/src/widgets/CartSetting.vue +46 -0
  118. package/src/widgets/CheckoutSetting.vue +46 -0
  119. package/src/widgets/CollapsiblePanelSetting.vue +46 -0
  120. package/src/widgets/ColumnSelector.vue +29 -5
  121. package/src/widgets/ComponentSetting.vue +1 -1
  122. package/src/widgets/ComponentSetting2.vue +112 -234
  123. package/src/widgets/ComponentSetting3.vue +1 -1
  124. package/src/widgets/ContactForm.vue +3 -3
  125. package/src/widgets/ContactFormSetting.vue +41 -30
  126. package/src/widgets/Dashboard/BarChart.vue +47 -11
  127. package/src/widgets/Dashboard/BarChartSetting.vue +1 -1
  128. package/src/widgets/Dashboard/DataTable.vue +125 -0
  129. package/src/widgets/Dashboard/DataTableSetting.vue +243 -0
  130. package/src/widgets/Dashboard/DatasourceSelector.vue +1 -1
  131. package/src/widgets/Dashboard/Doughnut.vue +49 -7
  132. package/src/widgets/Dashboard/DoughnutSetting.vue +2 -2
  133. package/src/widgets/Dashboard/Metric.vue +78 -19
  134. package/src/widgets/Dashboard/MetricSetting.vue +81 -28
  135. package/src/widgets/Dashboard/Pie.vue +55 -6
  136. package/src/widgets/Dashboard/PieSetting.vue +1 -1
  137. package/src/widgets/Dashboard/PolarArea.vue +49 -7
  138. package/src/widgets/Dashboard/PolarAreaSetting.vue +1 -1
  139. package/src/widgets/Dashboard/SharingModal.vue +4 -5
  140. package/src/widgets/Dashboard/ViewSelector.vue +2 -2
  141. package/src/widgets/Dashboard/VirtualTableSetting.vue +121 -184
  142. package/src/widgets/{Dashboard.vue → Dashboard0.vue} +426 -343
  143. package/src/widgets/EmbeddedVideoSetting.vue +7 -5
  144. package/src/widgets/FAQ.vue +16 -3
  145. package/src/widgets/FAQSetting.vue +53 -47
  146. package/src/widgets/FeatureList.vue +3 -0
  147. package/src/widgets/FeatureListSetting.vue +112 -102
  148. package/src/widgets/FlexSetting.vue +83 -106
  149. package/src/widgets/GridSetting.vue +71 -196
  150. package/src/widgets/Header2.vue +34 -71
  151. package/src/widgets/Header2Setting.vue +95 -179
  152. package/src/widgets/HeaderSetting.vue +16 -18
  153. package/src/widgets/IconListSetting.vue +69 -65
  154. package/src/widgets/ImageSetting.vue +33 -60
  155. package/src/widgets/LinkSetting.vue +60 -37
  156. package/src/widgets/LinkSettingModal.vue +173 -0
  157. package/src/widgets/LogViewer.vue +1 -1
  158. package/src/widgets/MarginSetting.vue +2 -2
  159. package/src/widgets/MenuEditor.vue +1 -1
  160. package/src/widgets/MenuItem1Setting.vue +78 -0
  161. package/src/widgets/ModalSetting.vue +42 -44
  162. package/src/widgets/MultiValueSetting.vue +2 -2
  163. package/src/widgets/MultiValueSetting2.vue +78 -45
  164. package/src/widgets/OGSettingModal.vue +103 -0
  165. package/src/widgets/PaddingSetting.vue +2 -2
  166. package/src/widgets/ParagraphSetting.vue +16 -13
  167. package/src/widgets/PositionSetting.vue +209 -0
  168. package/src/widgets/PresetBar.vue +359 -210
  169. package/src/widgets/PresetBarPivot.vue +31 -19
  170. package/src/widgets/PresetSelector.vue +29 -17
  171. package/src/widgets/SearchModalSetting.vue +70 -0
  172. package/src/widgets/Share.vue +1 -2
  173. package/src/widgets/ShareSetting.vue +67 -60
  174. package/src/widgets/StyleSetting.vue +227 -116
  175. package/src/widgets/TestimonialSetting.vue +97 -88
  176. package/src/widgets/TextBlockSetting.vue +16 -13
  177. package/src/widgets/UserActionBuilder/UserActionConsole.vue +30 -10
  178. package/src/widgets/UserActionBuilder/UserActionOutput.vue +2 -2
  179. package/src/widgets/UserActionBuilder/UserActionOutputReply.vue +64 -87
  180. package/src/widgets/UserActionBuilder/UserActionProps.vue +3 -3
  181. package/src/widgets/UserActionBuilder.vue +4 -16
  182. package/src/widgets/WebComponentSelector.vue +15 -11
  183. package/src/widgets/WebLayoutSelector.vue +41 -270
  184. package/src/widgets/WebPageBuilder.vue +693 -704
  185. package/src/widgets/WebPageBuilder2.vue +7 -7
  186. package/src/widgets/WebPageBuilder4/ButtonSetting.vue +0 -8
  187. package/src/widgets/WebPageBuilder4/CarouselSetting.vue +63 -7
  188. package/src/widgets/WebPageBuilder4/FlexAlignSetting.vue +3 -3
  189. package/src/widgets/WebPageBuilder4/FlexSetting.vue +1 -10
  190. package/src/widgets/WebPageBuilder4/MultiValueSetting.vue +2 -2
  191. package/src/widgets/WebPageBuilder4/PropertySetting.vue +0 -7
  192. package/src/widgets/WebPageBuilder4/WebPageComponentSelector.vue +1 -7
  193. package/src/widgets/WebPageBuilder4.vue +289 -575
  194. package/src/widgets/WebPageSelector.vue +1 -1
  195. package/src/widgets/YoutubeVideoSetting.vue +16 -13
  196. package/tailwind.config.js +3 -35
  197. package/docs/schema/user-action.json +0 -266
  198. package/src/App.vue +0 -25
  199. package/src/components/SearchButton.vue +0 -57
  200. package/src/entry-client.js +0 -27
  201. package/src/entry-server.js +0 -73
  202. package/src/events/event.js +0 -2
  203. package/src/main.js +0 -29
  204. package/src/mixin/website.js +0 -121
  205. package/src/router.js +0 -57
  206. package/src/widgets/MobileMenu.vue +0 -182
  207. package/src/widgets/WebPageBuilder4/ActionSetting.vue +0 -158
  208. package/src/widgets/WebPageBuilder4/ColorSetting.vue +0 -63
  209. package/src/widgets/WebPageBuilder4/DataSetting.vue +0 -92
  210. package/src/widgets/WebPageBuilder4/FontSizeSetting.vue +0 -76
  211. package/src/widgets/WebPageBuilder4/LinkSetting.vue +0 -68
  212. package/src/widgets/WebPageBuilder4/MobileMenuSetting.vue +0 -106
  213. package/src/widgets/WebPageBuilder4/Setting.vue +0 -73
  214. package/src/widgets/WebPageBuilder4/StyleSetting.vue +0 -77
  215. package/src/widgets/WebPageBuilder4/SvgSetting.vue +0 -207
  216. package/src/widgets/WebPageBuilder4/TextTransformSetting.vue +0 -70
  217. package/src/widgets/WebPageBuilder4/WebPageDataEdit.vue +0 -121
  218. package/test.json +0 -22
  219. /package/src/widgets/{Header1.vue → Header0.vue} +0 -0
  220. /package/src/widgets/{Header1Setting.vue → Header0Setting.vue} +0 -0
@@ -2,86 +2,198 @@
2
2
  <div :class="$style.comp">
3
3
 
4
4
  <div :class="$style.header" v-if="visibleColumns.length > 0">
5
- <table :class="$style.table" ref="tableHead" :style="tableHeadStyle">
6
- <thead>
7
- <tr>
8
- <th v-for="column in visibleColumns" :style="thStyle(column)" :class="thClass(column)"
9
- v-tooltip="column.tooltip">
10
- <slot v-if="$slots['col-' + column.key]" :name="'col-' + column.key" :column="column"></slot>
11
- <div v-else :class="headerColumnClass(column)">
12
- <span>{{ column.label2 ? column.label2 : (column.label ?? column.key) }}</span>
13
- </div>
14
- <div :class="$style.separator" @mousedown="startResize($event, column)"></div>
15
- </th>
16
- <th :class="$style.spacer"></th>
17
- </tr>
18
- </thead>
19
- </table>
20
- </div>
21
-
22
- <div ref="cont">
23
- <div v-if="state === 3" ref="spinner" class="flex-1 flex items-center justify-center p-8">
24
- <svg class="animate-spin aspect-square w-[32px] h-[32px] text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
25
- </div>
26
- <div ref="scroller" v-else-if="visibleColumns.length > 0" :class="$style.scroller" :style="scrollerStyle">
27
- <div :class="$style.spacer" ref="spacer" :style="spacerStyle">
28
- <table :class="$style.table">
29
- <thead>
30
- <tr>
31
- <th v-for="column in visibleColumns" :style="thStyle(column)"></th>
32
- <th :class="$style.spacer"></th>
33
- </tr>
34
- </thead>
35
- <tbody ref="tbody">
36
- <tr v-for="(item, index) in visibleItems" :key="item"
37
- @click="select(item, index)"
38
- :class="trClass(item, index)">
39
- <td v-for="(column, columnIndex) in visibleColumns"
40
- :class="tdClass(item, column)"
41
- @click="$emit('item-click', item, column)">
42
-
43
- <div v-if="columnIndex === 0 && item._type === 'totalRow'" :class="$style.total">Total</div>
44
- <div v-else-if="item._type === 'totalRow' && !column.key.startsWith('_')"></div>
45
-
46
- <slot v-else-if="$slots[column.key]" :name="column.key" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
47
- <slot v-else-if="$slots.default" name="default" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
48
- <div v-else :class="columnClass(column, item)" v-html="formatColumn(item, column)"></div>
49
-
50
- </td>
51
- <td :class="$style.spacer"></td>
52
- </tr>
53
- </tbody>
54
- </table>
55
- <div v-if="state === 2" ref="spinner" class="h-[44px] relative">
56
- <div class="absolute top-0 left-0 w-screen h-[44px] flex items-center justify-center">
57
- <svg class="animate-spin aspect-square w-[16px] h-[16px] text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
58
- </div>
59
- </div>
60
- <slot name="end"></slot>
61
- </div>
62
- </div>
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">
64
- <h5 class="text-text-300">No active column</h5>
65
- </div>
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">
67
- <h5 class="text-text-300">No data available</h5>
68
- </div>
69
-
70
- <div :class="$style.calc" v-if="visibleColumns.length > 0 && cItems && cItems.length > 0" ref="calc">
71
- <table :class="$style.table">
72
- <tbody>
5
+ <table :class="$style.table">
6
+ <thead>
7
+ <tr>
8
+ <th v-for="column in freezeLeftColumns"
9
+ :ref="`column${column.key}`"
10
+ :style="thStyle(column)"
11
+ :class="`${$style.freezed} ${thClass(column)}`"
12
+ v-tooltip="column.tooltip">
13
+ <div :class="headerColumnClass(column)"
14
+ @click="$refs.columnMenu.open($refs[`column${column.key}`][0], { key:column.key, freeze:column.freeze })">
15
+ <slot v-if="$slots['col-' + column.key]" :name="'col-' + column.key" :column="column"></slot>
16
+ <span v-else>{{ column.label2 ? column.label2 : (column.label ?? column.key) }}</span>
17
+ </div>
18
+ <div :class="$style.separator" @mousedown="startResize($event, column)"></div>
19
+ </th>
20
+ <th :class="$style.spacer"></th>
21
+ </tr>
22
+ </thead>
23
+ </table>
24
+ <div class="overflow-hidden">
25
+ <table :class="$style.table" ref="tableHead" :style="tableHeadStyle">
26
+ <thead>
73
27
  <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>
28
+ <th v-for="column in unfreezedColumns"
29
+ :ref="`column${column.key}`"
30
+ :style="thStyle(column)"
31
+ :class="thClass(column)"
32
+ v-tooltip="column.tooltip">
33
+ <div :class="headerColumnClass(column)"
34
+ @click="$refs.columnMenu.open($refs[`column${column.key}`][0], { key:column.key, freeze:column.freeze })">
35
+ <slot v-if="$slots['col-' + column.key]" :name="'col-' + column.key" :column="column"></slot>
36
+ <span v-else>{{ column.label2 ? column.label2 : (column.label ?? column.key) }}</span>
37
+ </div>
38
+ <div :class="$style.separator" @mousedown="startResize($event, column)"></div>
39
+ </th>
40
+ <th :class="$style.spacer"></th>
80
41
  </tr>
81
- </tbody>
82
- </table>
83
- </div>
42
+ </thead>
43
+ </table>
44
+ </div>
45
+
46
+ <ContextMenu ref="columnMenu" position="bottom-left" class="mt-2 rounded-md min-w-[240px] max-w-[240px]">
47
+ <template #default="{ context }">
48
+ <div class="flex flex-col min-h-[160px]">
49
+
50
+ <br />
51
+
52
+ <button v-if="!context?.freeze" class="w-full p-2 border-y-[1px] border-border-50 text-left flex flex-row px-3 items-center menu-item"
53
+ @click="freeze(context.key)">
54
+ <div class="w-[24px]">
55
+ <svg width="14" height="14" class="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="M105.4 182.6c12.5 12.49 32.76 12.5 45.25 .001L224 109.3V352c0 17.67 14.33 32 32 32c17.67 0 32-14.33 32-32V109.3l73.38 73.38c12.49 12.49 32.75 12.49 45.25-.001c12.49-12.49 12.49-32.75 0-45.25l-128-128C272.4 3.125 264.2 0 256 0S239.6 3.125 233.4 9.375L105.4 137.4C92.88 149.9 92.88 170.1 105.4 182.6zM480 352h-160c0 35.35-28.65 64-64 64s-64-28.65-64-64H32c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32v-96C512 366.3 497.7 352 480 352zM432 456c-13.2 0-24-10.8-24-24c0-13.2 10.8-24 24-24s24 10.8 24 24C456 445.2 445.2 456 432 456z"/></svg>
56
+ </div>
57
+ Freeze
58
+ </button>
59
+
60
+ <button v-else class="w-full p-2 border-y-[1px] border-border-50 text-left flex flex-row px-3 items-center menu-item"
61
+ @click="unfreeze(context.key)">
62
+ <div class="w-[24px]">
63
+ <svg width="14" height="14" class="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="M105.4 182.6c12.5 12.49 32.76 12.5 45.25 .001L224 109.3V352c0 17.67 14.33 32 32 32c17.67 0 32-14.33 32-32V109.3l73.38 73.38c12.49 12.49 32.75 12.49 45.25-.001c12.49-12.49 12.49-32.75 0-45.25l-128-128C272.4 3.125 264.2 0 256 0S239.6 3.125 233.4 9.375L105.4 137.4C92.88 149.9 92.88 170.1 105.4 182.6zM480 352h-160c0 35.35-28.65 64-64 64s-64-28.65-64-64H32c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32v-96C512 366.3 497.7 352 480 352zM432 456c-13.2 0-24-10.8-24-24c0-13.2 10.8-24 24-24s24 10.8 24 24C456 445.2 445.2 456 432 456z"/></svg>
64
+ </div>
65
+ Unfreeze
66
+ </button>
67
+
68
+ </div>
69
+ </template>
70
+ </ContextMenu>
84
71
  </div>
72
+
73
+ <div ref="cont" class="flex-1 overflow-y-auto" @scroll.passive="handleScroll">
74
+ <div v-if="state === 3" class="flex items-center justify-center p-8">
75
+ <svg class="animate-spin aspect-square w-[32px] h-[32px] text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
76
+ </div>
77
+
78
+ <div v-else class="flex-1 flex flex-row">
79
+
80
+ <div v-if="state !== 2" :style="freezeLeftScrollerStyle">
81
+ <div :class="$style.spacer" :style="spacerStyle">
82
+ <table :class="$style.table" class="flex-1 overflow-x-auto">
83
+ <thead>
84
+ <tr>
85
+ <th v-for="column in freezeLeftColumns" :style="thStyle(column)"></th>
86
+ <th :class="$style.spacer"></th>
87
+ </tr>
88
+ </thead>
89
+ <tbody>
90
+ <tr v-for="(item, index) in visibleItems"
91
+ :key="item"
92
+ @dragover="(e) => $emit('dragover', e, item)"
93
+ @mouseover="hover(item, index)" @mouseout="hoverIndex = -1"
94
+ @click="select(item, index)"
95
+ :class="trClass(item, index)">
96
+ <td v-for="(column, columnIndex) in freezeLeftColumns"
97
+ :class="tdClass(item, column)"
98
+ @click="$emit('item-click', item, column)">
99
+
100
+ <div v-if="columnIndex === 0 && item._type === 'totalRow'" :class="$style.total">Total</div>
101
+ <div v-else-if="item._type === 'totalRow' && !column.key.startsWith('_')"></div>
102
+
103
+ <slot v-else-if="$slots[column.key]" :name="column.key" :column="column" :item="item"
104
+ :index="visibleStartIndex + index" :selected="selectedIndex === item.id">
105
+ <div :class="columnClass(column, item)">&nbsp;</div>
106
+ </slot>
107
+ <slot v-else-if="$slots.default" name="default" :column="column" :item="item"
108
+ :index="visibleStartIndex + index" :selected="selectedIndex === item.id">
109
+ <div :class="columnClass(column, item)">&nbsp;</div>
110
+ </slot>
111
+ <div v-else :class="columnClass(column, item)" v-html="formatColumn(item, column)"></div>
112
+
113
+ </td>
114
+ <td class="w-full"></td>
115
+ </tr>
116
+ </tbody>
117
+ </table>
118
+ </div>
119
+ </div>
120
+
121
+ <div ref="xcont" class="flex-1 overflow-x-auto overflow-y-hidden" @scroll.passive="handleScrollX">
122
+ <div ref="scroller" v-if="visibleColumns.length > 0" :class="$style.scroller" :style="scrollerStyle">
123
+ <div :class="$style.spacer" ref="spacer" :style="spacerStyle">
124
+
125
+ <table :class="$style.table" class="flex-1 overflow-x-auto">
126
+ <thead>
127
+ <tr>
128
+ <th v-for="column in unfreezedColumns" :style="thStyle(column)"></th>
129
+ <th :class="$style.spacer"></th>
130
+ </tr>
131
+ </thead>
132
+ <tbody ref="tbody">
133
+ <tr v-for="(item, index) in visibleItems"
134
+ :key="item"
135
+ @dragover="(e) => $emit('dragover', e, item)"
136
+ @mouseover="hover(item, index)" @mouseout="hoverIndex = -1"
137
+ @click="select(item, index)"
138
+ :class="trClass(item, index)">
139
+ <td v-for="(column, columnIndex) in unfreezedColumns"
140
+ :class="tdClass(item, column)"
141
+ @click="$emit('item-click', item, column)">
142
+
143
+ <div v-if="columnIndex === 0 && item._type === 'totalRow'" :class="$style.total">Total</div>
144
+ <div v-else-if="item._type === 'totalRow' && !column.key.startsWith('_')"></div>
145
+
146
+ <slot v-else-if="$slots[column.key]" :name="column.key" :column="column" :item="item"
147
+ :index="visibleStartIndex + index" :selected="selectedIndex === item.id">
148
+ <div :class="columnClass(column, item)">&nbsp;</div>
149
+ </slot>
150
+ <slot v-else-if="$slots.default" name="default" :column="column" :item="item"
151
+ :index="visibleStartIndex + index" :selected="selectedIndex === item.id">
152
+ <div :class="columnClass(column, item)">&nbsp;</div>
153
+ </slot>
154
+ <div v-else :class="columnClass(column, item)" v-html="formatColumn(item, column)"></div>
155
+
156
+ </td>
157
+ <td class="w-full"></td>
158
+ </tr>
159
+ </tbody>
160
+ </table>
161
+
162
+ <div v-if="state === 2" class="h-[44px] relative">
163
+ <div class="absolute top-0 left-0 w-screen h-[44px] flex items-center justify-center">
164
+ <svg class="animate-spin aspect-square w-[16px] h-[16px] text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ <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">
170
+ <h5 class="text-text-300">No active column</h5>
171
+ </div>
172
+ <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">
173
+ <h5 class="text-text-300">No data available</h5>
174
+ </div>
175
+ </div>
176
+
177
+ </div>
178
+
179
+ <slot name="end"></slot>
180
+
181
+ <div :class="$style.calc" v-if="visibleColumns.length > 0 && cItems && cItems.length > 0" ref="calc">
182
+ <table :class="$style.table">
183
+ <tbody>
184
+ <tr>
185
+ <td v-for="column in cColumns" :style="thStyle(column)" :class="thClass(column)">
186
+ <slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="cItems[0]"></slot>
187
+ <slot v-else-if="$slots.default" name="default" :column="column" :item="cItems[0]"></slot>
188
+ <div v-else :class="columnClass(column)" v-html="formatColumn(cItems[0] ?? {}, column)"></div>
189
+ </td>
190
+ <td :class="$style.spacer"></td>
191
+ </tr>
192
+ </tbody>
193
+ </table>
194
+ </div>
195
+ </div>
196
+
85
197
  </div>
86
198
  </template>
87
199
 
@@ -95,15 +207,22 @@ const _DEFAULT_COLUMN_WIDTH = '100px'
95
207
 
96
208
  export default{
97
209
 
98
- inject: [ 'emitRoot', 'listStyle' ],
210
+ inject: [ 'emitRoot' ],
99
211
 
100
- emits: [ 'scroll-end', 'item-click' ],
212
+ emits: [ 'dragover', 'freeze', 'unfreeze', 'scroll-end', 'item-click' ],
101
213
 
102
214
  props:{
215
+
103
216
  columns: Array,
104
217
 
218
+ datasource: Object,
219
+
105
220
  enumCache: Object,
106
221
 
222
+ freezeLeft: Number,
223
+
224
+ freezeRight: Number,
225
+
107
226
  itemClass: String,
108
227
 
109
228
  uid: String,
@@ -114,8 +233,6 @@ export default{
114
233
 
115
234
  datasourceColumns: Array,
116
235
 
117
- datasourceUid: String,
118
-
119
236
  defaultColumnWidth: {
120
237
  type: String,
121
238
  default: _DEFAULT_COLUMN_WIDTH
@@ -129,6 +246,7 @@ export default{
129
246
  type: String,
130
247
 
131
248
  value: Object,
249
+
132
250
  },
133
251
 
134
252
  data(){
@@ -139,14 +257,19 @@ export default{
139
257
  maxVisibleItems: 0,
140
258
  isOnEndScroll: false,
141
259
  selectedIndex: -1,
142
- state: 1
260
+ hoverIndex: -1,
261
+ state: 1,
262
+ scrolled: false,
263
+ scrollerCache: {},
264
+ observer1: null,
265
+ observer2: null,
143
266
  }
144
267
  },
145
268
 
146
269
  computed:{
147
270
 
148
271
  cColumns(){
149
- return this.datasourceColumns ?? this.columns
272
+ return this.columns ?? []
150
273
  },
151
274
 
152
275
  cItems(){
@@ -194,7 +317,7 @@ export default{
194
317
  return {}
195
318
 
196
319
  const height = (this.cItems.length * this.itemHeight) + (this.state === 2 ? 48 : 0)
197
- const width = this.visibleColumns.reduce((r, item) => r + parseInt(item.width ?? _DEFAULT_COLUMN_WIDTH), 0)
320
+ const width = this.unfreezedColumns.reduce((r, item) => r + parseInt(item.width ?? _DEFAULT_COLUMN_WIDTH), 0)
198
321
 
199
322
  return {
200
323
  height: height + 'px',
@@ -202,40 +325,77 @@ export default{
202
325
  }
203
326
  },
204
327
 
328
+ freezeLeftScrollerStyle(){
329
+ if(!this.cItems || this.cItems.length < 1)
330
+ return {}
331
+
332
+ const height = (this.cItems.length * this.itemHeight) + (this.state === 2 ? 48 : 0)
333
+ const width = this.freezeLeftColumns.reduce((r, item) => r + parseInt(item.width ?? _DEFAULT_COLUMN_WIDTH), 0)
334
+
335
+ return {
336
+ height: height + 'px',
337
+ width: width + 'px'
338
+ }
339
+ },
340
+
205
341
  tableHeadStyle(){
206
342
  return {
207
343
  transform: "translate3d(" + (this.scrollLeft * -1) + "px, 0, 0)"
208
344
  }
209
345
  },
210
346
 
347
+ freezeLeftColumns(){
348
+ const columns = []
349
+ for(let i = 0 ; i < (this.freezeLeft ?? 0) && i < this.visibleColumns.length ; i++){
350
+ const column = this.visibleColumns[i]
351
+ if(!('visible' in column) || column.visible){
352
+ columns.push(column)
353
+ }
354
+ }
355
+ return columns
356
+ },
357
+
358
+ unfreezedColumns(){
359
+ const columns = []
360
+ for(let i = this.freezeLeft ?? 0 ; i < this.visibleColumns.length ; i++){
361
+ const column = this.visibleColumns[i]
362
+ if(!('visible' in column) || column.visible){
363
+ columns.push(column)
364
+ }
365
+ }
366
+ return columns
367
+ },
368
+
211
369
  visibleColumns(){
212
- return (this.cColumns ?? []).filter(_ => !('visible' in _) || _.visible)
213
- },
370
+ const columns = []
371
+ for(let i = 0 ; i < this.cColumns.length ; i++){
372
+ const column = this.cColumns[i]
214
373
 
215
- visibleColumnKeys(){
216
- return this.visibleColumns.map(_ => _.key)
374
+ if(!('visible' in column) || column.visible){
375
+ columns.push(column)
376
+ }
377
+ }
378
+ return columns
217
379
  },
218
380
 
219
381
  },
220
382
 
221
383
  mounted(){
384
+ this.observer1 = new MutationObserver(_ => this.resize());
385
+ this.observer1.observe(this.$el, { attributes: true });
222
386
 
223
- this.$refs.cont.addEventListener(
224
- "scroll",
225
- this.handleScroll,
226
- this.passiveScrollSupported() ? { passive: true } : false
227
- )
228
-
229
- this.resize()
387
+ this.observer2 = new ResizeObserver(_ => this.resize());
388
+ this.observer2.observe(this.$refs.cont)
230
389
 
231
- const observer = new MutationObserver((mutationsList) => {
232
- this.resize()
233
- });
234
- observer.observe(this.$el, { attributes: true });
235
390
 
236
391
  },
237
392
 
238
- methods: {
393
+ unmounted() {
394
+ this.observer1.disconnect()
395
+ this.observer2.disconnect()
396
+ },
397
+
398
+ methods: {
239
399
 
240
400
  resetState(){
241
401
  this.state = 1
@@ -246,7 +406,8 @@ export default{
246
406
  this.visibleColumns.filter((_) => item._highlight.includes(_.key)).length <= 0)
247
407
 
248
408
  return [
249
- this.selectedIndex === ((item && item.id) ? item.id : this.visibleStartIndex + index) ? this.$style.trSelected : '',
409
+ this.selectedIndex === ((item && item.id) ? item.id : this.visibleStartIndex + index) ? `${this.$style.trSelected} selected` : '',
410
+ this.hoverIndex === ((item && item.id) ? item.id : this.visibleStartIndex + index) ? this.$style.trHover : '',
250
411
  highlight ? this.$style.highlight : ''
251
412
  ].join(' ')
252
413
  },
@@ -264,6 +425,10 @@ export default{
264
425
  }
265
426
  },
266
427
 
428
+ hover(item, index){
429
+ this.hoverIndex = (item && item.id) ? item.id : this.visibleStartIndex + index
430
+ },
431
+
267
432
  thStyle(column){
268
433
  const width = parseInt(column.width ?? this.defaultColumnWidth)
269
434
  return {
@@ -274,9 +439,24 @@ export default{
274
439
  thClass(column){
275
440
  let classNames = []
276
441
 
442
+ let align
277
443
  if(column.align){
278
- classNames.push(`text-${column.align}`)
444
+ align = column.align
279
445
  }
446
+ else{
447
+ switch(column.type){
448
+ case 'currency':
449
+ case 'number':
450
+ align = 'right'
451
+ break
452
+
453
+ default:
454
+ if(column.key.startsWith('_'))
455
+ align = 'center'
456
+ break
457
+ }
458
+ }
459
+ classNames.push(`text-${align}`)
280
460
 
281
461
  return classNames.join(' ')
282
462
  },
@@ -284,6 +464,10 @@ export default{
284
464
  async resize(){
285
465
 
286
466
  this.$nextTick(() => {
467
+ if(this.$refs.xcont){
468
+ this.$refs.xcont.style.minHeight = `${this.$refs.cont.clientHeight}px`
469
+ }
470
+
287
471
  if(this.$refs.calc){
288
472
  const elHeight = parseInt(window.getComputedStyle(this.$el).height !== '0px' ?
289
473
  window.getComputedStyle(this.$el).height :
@@ -299,11 +483,18 @@ export default{
299
483
 
300
484
  },
301
485
 
486
+ handleScrollX: throttle(function(){
487
+ if(!this.$refs.scroller || !this.$refs.xcont) return
488
+
489
+ this.scrollLeft = this.$refs.xcont.scrollLeft
490
+
491
+ this.scrolled = this.scrollTop > 0
492
+ }, 16),
493
+
302
494
  handleScroll: throttle(function(){
303
495
  if(!this.$refs.scroller || !this.$refs.cont) return
304
496
 
305
497
  this.scrollTop = this.$refs.cont.scrollTop
306
- this.scrollLeft = this.$refs.cont.scrollLeft
307
498
 
308
499
  if(this.scrollTop > this.$refs.scroller.offsetHeight - this.$refs.cont.clientHeight - this.itemHeight){
309
500
  if(!this.isOnEndScroll){
@@ -318,6 +509,8 @@ export default{
318
509
  this.isOnEndScroll = false
319
510
  }
320
511
  }
512
+
513
+ this.scrolled = this.scrollTop > 0
321
514
  }, 16),
322
515
 
323
516
  passiveScrollSupported() {
@@ -492,8 +685,7 @@ export default{
492
685
 
493
686
  return [
494
687
  this.$style.tdDiv,
495
- this.$style['align-' + align],
496
- this.listStyle ? this.listStyle[appearanceClass] : ''
688
+ this.$style['align-' + align]
497
689
  ]
498
690
  .join(' ')
499
691
  },
@@ -547,11 +739,18 @@ export default{
547
739
  switch(column.type){
548
740
 
549
741
  case 'date':
742
+ case 'datetime':
550
743
  dateFormat = column.format ?? 'D MMM YY HH:mm:ss'
551
744
  val = dayjs(value)
552
745
  text = val.isValid() ? val.format(dateFormat) : value
553
746
  break
554
747
 
748
+ case 'time':
749
+ dateFormat = column.format ?? ' HH:mm:ss'
750
+ val = dayjs(value)
751
+ text = val.isValid() ? val.format(dateFormat) : value
752
+ break
753
+
555
754
  case 'currency':
556
755
  const num = parseInt(value)
557
756
  text = !isNaN(num) ? num.toLocaleString() : ''
@@ -573,12 +772,27 @@ export default{
573
772
  break
574
773
  }
575
774
 
576
- return text ? text : (value === null ? '' : '-')
775
+ const res = text ? text : (value === null ? '' : '-')
776
+
777
+ return `${res}`
778
+ .replace(/&/g, "&amp;")
779
+ .replace(/</g, "&lt;")
780
+ .replace(/>/g, "&gt;")
781
+ .replace(/"/g, "&quot;")
782
+ .replace(/'/g, "&#039;")
577
783
  },
578
784
 
579
785
  setState(state){
580
786
  this.state = state
581
- }
787
+ },
788
+
789
+ freeze(key){
790
+ this.$emit('freeze', key)
791
+ },
792
+
793
+ unfreeze(key){
794
+ this.$emit('unfreeze', key)
795
+ }
582
796
 
583
797
  },
584
798
 
@@ -587,9 +801,9 @@ export default{
587
801
  cItems: {
588
802
  deep: true,
589
803
  handler(to, from){
590
- if((to ?? []).length !== (from ?? []).length){
804
+ /*if((to ?? []).length !== (from ?? []).length){
591
805
  this.scrollTop = 0
592
- }
806
+ }*/
593
807
 
594
808
  this.resize()
595
809
  }
@@ -600,7 +814,26 @@ export default{
600
814
  handler(){
601
815
  this.resize()
602
816
  }
603
- }
817
+ },
818
+
819
+ scrollerStyle(to){
820
+ if(this.scrolled && this.scrollerCache?.id){
821
+ const index = this.items.findIndex(_ => _.id === this.scrollerCache.id)
822
+ const addToScroll = (index - this.scrollerCache.index) * this.itemHeight
823
+ this.scrollTop = this.$refs.cont.scrollTop = this.scrollTop + addToScroll
824
+ }
825
+
826
+ this.scrollerCache = {
827
+ id: (this.items ?? [])[this.visibleStartIndex]?.id,
828
+ index: this.visibleStartIndex
829
+ }
830
+ },
831
+
832
+ state(to){
833
+ if(to === 1){
834
+ this.$nextTick(() => this.resize())
835
+ }
836
+ }
604
837
 
605
838
  }
606
839
 
@@ -611,16 +844,17 @@ export default{
611
844
  <style module>
612
845
 
613
846
  .comp{
614
- @apply flex flex-col overflow-hidden bg-base-500;
615
- @apply border-[1px] border-text-50 rounded-sm;
847
+ @apply flex flex-col overflow-hidden;
848
+ @apply border-[1px] border-border-50 rounded-md bg-base-400;
616
849
  }
617
850
 
618
851
  .comp>*:last-child{
619
- @apply flex-1 overflow-auto relative max-h-[100vh];
852
+ @apply flex-1 relative max-h-[100vh];
620
853
  }
621
854
 
622
855
  .header{
623
- @apply border-b-[1px] border-text-50;
856
+ @apply border-b-[1px] border-border-50;
857
+ @apply flex flex-row;
624
858
  }
625
859
 
626
860
  .headerCol{
@@ -635,6 +869,7 @@ export default{
635
869
  }
636
870
 
637
871
  .spacer{
872
+ @apply w-full flex flex-row;
638
873
  will-change: auto;
639
874
  position: relative;
640
875
  height: 0;
@@ -653,25 +888,25 @@ export default{
653
888
  .table th{
654
889
  @apply relative text-left;
655
890
  }
656
- .table th:nth-child(odd){
657
- }
658
891
 
659
892
  .table tbody td{
660
- @apply border-b-[1px] border-text-50;
893
+ @apply border-b-[1px] border-border-50;
661
894
  }
662
- .table tbody td:nth-child(odd){
895
+
896
+ .table tbody tr{
897
+ @apply h-[2.4rem];
663
898
  }
664
899
 
665
- .table tbody tr:hover{
666
- @apply bg-primary-50;
900
+ .table tbody tr.trHover{
901
+ @apply bg-border-50;
667
902
  }
668
903
 
669
904
  .table tbody tr.trSelected{
670
- @apply bg-primary-100;
905
+ @apply bg-border-50;
671
906
  }
672
907
 
673
908
  .highlight{
674
- @apply bg-primary-50 transition-all;
909
+ @apply bg-text-50 transition-all;
675
910
  }
676
911
 
677
912
  .tdDiv{
@@ -679,15 +914,11 @@ export default{
679
914
  }
680
915
 
681
916
  .separator{
682
- @apply w-[5px] absolute top-0 bottom-0 right-0 cursor-e-resize border-text-50;
917
+ @apply w-[5px] absolute top-0 bottom-0 right-0 cursor-e-resize border-border-50;
683
918
  @apply border-r-[1px];
684
919
  }
685
920
  .table th:hover .separator{
686
- @apply border-text-50;
687
- }
688
-
689
- .spacer{
690
- @apply w-full
921
+ @apply border-border-50;
691
922
  }
692
923
 
693
924
  .align-left{ @apply text-left; }
@@ -718,4 +949,8 @@ export default{
718
949
  @apply px-3 uppercase font-bold;
719
950
  }
720
951
 
952
+ .freezed{
953
+ @apply bg-base-500;
954
+ }
955
+
721
956
  </style>