@vc-shell/framework 1.1.0-alpha.3 → 1.1.0-alpha.4

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 (156) hide show
  1. package/core/composables/index.ts +18 -17
  2. package/core/composables/useDashboard/index.ts +19 -0
  3. package/core/composables/{useGlobalSearch.ts → useGlobalSearch/index.ts} +3 -5
  4. package/core/composables/useWidgets/index.ts +19 -18
  5. package/core/plugins/modularity/loader.ts +2 -1
  6. package/core/services/dashboard-service.ts +121 -0
  7. package/core/services/widget-service.ts +1 -4
  8. package/dist/core/composables/index.d.ts +1 -0
  9. package/dist/core/composables/index.d.ts.map +1 -1
  10. package/dist/core/composables/useDashboard/index.d.ts +5 -0
  11. package/dist/core/composables/useDashboard/index.d.ts.map +1 -0
  12. package/dist/core/composables/{useGlobalSearch.d.ts → useGlobalSearch/index.d.ts} +1 -1
  13. package/dist/core/composables/useGlobalSearch/index.d.ts.map +1 -0
  14. package/dist/core/plugins/modularity/loader.d.ts.map +1 -1
  15. package/dist/core/services/dashboard-service.d.ts +33 -0
  16. package/dist/core/services/dashboard-service.d.ts.map +1 -0
  17. package/dist/core/services/widget-service.d.ts.map +1 -1
  18. package/dist/framework.js +235 -225
  19. package/dist/{index-Bu12RZTu.js → index-8LELHzw9.js} +1 -1
  20. package/dist/{index-Bwl2ND2Q.js → index-9lJxZE5w.js} +1 -1
  21. package/dist/{index-CJi-BbTb.js → index-B1YR_MYV.js} +1 -1
  22. package/dist/{index-BhdwVgUw.js → index-BA98L1jI.js} +1 -1
  23. package/dist/{index-NdrUF1u3.js → index-BAeTsi-X.js} +1 -1
  24. package/dist/{index-CbRqPQTw.js → index-BBYyHeYA.js} +1 -1
  25. package/dist/{index-CsaYfhir.js → index-BrUitdDo.js} +1 -1
  26. package/dist/{index-CZ_pj3nW.js → index-BuO5ByG9.js} +1 -1
  27. package/dist/{index-DFPb-jDP.js → index-CJ5I7vTn.js} +1 -1
  28. package/dist/{index-BdoAu2fz.js → index-CWKrD2Cd.js} +1 -1
  29. package/dist/{index-DVaMW7gL.js → index-Cf9Tz1ql.js} +1 -1
  30. package/dist/{index-B89uIUkS.js → index-CrxFDC2b.js} +1 -1
  31. package/dist/{index-BcQiBkO6.js → index-D1JchciU.js} +1 -1
  32. package/dist/{index-CEvuTGIu.js → index-DLtsQ_PJ.js} +31254 -31134
  33. package/dist/{index-COjjAS6v.js → index-DVljTjbf.js} +1 -1
  34. package/dist/{index-DjQ6Ffv8.js → index-RwX3kiZh.js} +28 -28
  35. package/dist/{index-S9Ht7s3i.js → index-xLYzNPa7.js} +1 -1
  36. package/dist/index.css +1 -1
  37. package/dist/injection-keys.d.ts +28 -0
  38. package/dist/injection-keys.d.ts.map +1 -1
  39. package/dist/shared/components/dashboard-widget-card/dashboard-widget-card.vue.d.ts +25 -0
  40. package/dist/shared/components/dashboard-widget-card/dashboard-widget-card.vue.d.ts.map +1 -0
  41. package/dist/shared/components/dashboard-widget-card/index.d.ts +2 -0
  42. package/dist/shared/components/dashboard-widget-card/index.d.ts.map +1 -0
  43. package/dist/shared/components/draggable-dashboard/DraggableDashboard.vue.d.ts +6 -0
  44. package/dist/shared/components/draggable-dashboard/DraggableDashboard.vue.d.ts.map +1 -0
  45. package/dist/shared/components/draggable-dashboard/_internal/DashboardWidget.vue.d.ts +20 -0
  46. package/dist/shared/components/draggable-dashboard/_internal/DashboardWidget.vue.d.ts.map +1 -0
  47. package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts +354 -0
  48. package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts.map +1 -0
  49. package/dist/shared/components/draggable-dashboard/composables/useDashboardGrid.d.ts +12 -0
  50. package/dist/shared/components/draggable-dashboard/composables/useDashboardGrid.d.ts.map +1 -0
  51. package/dist/shared/components/draggable-dashboard/index.d.ts +2 -0
  52. package/dist/shared/components/draggable-dashboard/index.d.ts.map +1 -0
  53. package/dist/shared/components/draggable-dashboard/types.d.ts +80 -0
  54. package/dist/shared/components/draggable-dashboard/types.d.ts.map +1 -0
  55. package/dist/shared/components/index.d.ts +2 -0
  56. package/dist/shared/components/index.d.ts.map +1 -1
  57. package/dist/shared/components/user-dropdown-button/_internal/user-info.vue.d.ts.map +1 -1
  58. package/dist/shared/components/user-dropdown-button/user-dropdown-button.vue.d.ts.map +1 -1
  59. package/dist/shared/composables/useMenuExpanded.d.ts +2 -0
  60. package/dist/shared/composables/useMenuExpanded.d.ts.map +1 -1
  61. package/dist/shared/modules/dynamic/components/fields/storybook/Button.stories.d.ts +0 -41
  62. package/dist/shared/modules/dynamic/components/fields/storybook/Button.stories.d.ts.map +1 -1
  63. package/dist/shared/modules/dynamic/components/fields/storybook/Card.stories.d.ts.map +1 -1
  64. package/dist/shared/modules/dynamic/components/fields/storybook/common/templates.d.ts +1 -1
  65. package/dist/shared/modules/dynamic/components/fields/storybook/common/templates.d.ts.map +1 -1
  66. package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts +2 -25
  67. package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts.map +1 -1
  68. package/dist/tailwind.config.d.ts +1 -81
  69. package/dist/tailwind.config.d.ts.map +1 -1
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/dist/ui/components/atoms/vc-button/vc-button.stories.d.ts +169 -734
  72. package/dist/ui/components/atoms/vc-button/vc-button.stories.d.ts.map +1 -1
  73. package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts +18 -2
  74. package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts.map +1 -1
  75. package/dist/ui/components/atoms/vc-card/index.d.ts +2 -0
  76. package/dist/ui/components/atoms/vc-card/index.d.ts.map +1 -1
  77. package/dist/ui/components/atoms/vc-card/vc-card.stories.d.ts +12 -0
  78. package/dist/ui/components/atoms/vc-card/vc-card.stories.d.ts.map +1 -1
  79. package/dist/ui/components/atoms/vc-card/vc-card.vue.d.ts +2 -0
  80. package/dist/ui/components/atoms/vc-card/vc-card.vue.d.ts.map +1 -1
  81. package/dist/ui/components/atoms/vc-icon/icons/GridDotsIcon.vue.d.ts +18 -0
  82. package/dist/ui/components/atoms/vc-icon/icons/GridDotsIcon.vue.d.ts.map +1 -0
  83. package/dist/ui/components/atoms/vc-icon/icons/ShoppingCardIcon.vue.d.ts +18 -0
  84. package/dist/ui/components/atoms/vc-icon/icons/ShoppingCardIcon.vue.d.ts.map +1 -0
  85. package/dist/ui/components/atoms/vc-icon/icons/index.d.ts +2 -0
  86. package/dist/ui/components/atoms/vc-icon/icons/index.d.ts.map +1 -1
  87. package/dist/ui/components/organisms/vc-app/_internal/composables/useAppMenuState.d.ts +2 -0
  88. package/dist/ui/components/organisms/vc-app/_internal/composables/useAppMenuState.d.ts.map +1 -1
  89. package/dist/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue.d.ts +0 -1
  90. package/dist/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue.d.ts.map +1 -1
  91. package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/_internal/vc-app-menu-link.vue.d.ts +2 -1
  92. package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/_internal/vc-app-menu-link.vue.d.ts.map +1 -1
  93. package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue.d.ts.map +1 -1
  94. package/dist/ui/components/organisms/vc-app/vc-app.stories.d.ts +13 -67
  95. package/dist/ui/components/organisms/vc-app/vc-app.stories.d.ts.map +1 -1
  96. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts +5 -65
  97. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
  98. package/dist/ui/components/organisms/vc-table/_internal/vc-table-base-header/vc-table-base-header.vue.d.ts.map +1 -1
  99. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/{vc-table-header/vc-table-header.vue.d.ts → vc-table-columns-header/vc-table-columns-header.vue.d.ts} +1 -1
  100. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-columns-header/vc-table-columns-header.vue.d.ts.map +1 -0
  101. package/dist/ui/components/organisms/vc-table/_internal/vc-table-header/vc-table-header.vue.d.ts.map +1 -1
  102. package/dist/ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue.d.ts +33 -3
  103. package/dist/ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue.d.ts.map +1 -1
  104. package/dist/ui/components/organisms/vc-table/composables/useTableRowReorder.d.ts.map +1 -1
  105. package/package.json +10 -5
  106. package/shared/components/dashboard-widget-card/dashboard-widget-card.vue +67 -0
  107. package/shared/components/dashboard-widget-card/index.ts +1 -0
  108. package/shared/components/draggable-dashboard/DraggableDashboard.vue +369 -0
  109. package/shared/components/draggable-dashboard/_internal/DashboardWidget.vue +133 -0
  110. package/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.ts +547 -0
  111. package/shared/components/draggable-dashboard/composables/useDashboardGrid.ts +250 -0
  112. package/shared/components/draggable-dashboard/index.ts +1 -0
  113. package/shared/components/draggable-dashboard/types.ts +91 -0
  114. package/shared/components/index.ts +2 -0
  115. package/shared/components/user-dropdown-button/_internal/user-info.vue +25 -12
  116. package/shared/components/user-dropdown-button/user-dropdown-button.vue +3 -3
  117. package/shared/composables/useMenuExpanded.ts +24 -0
  118. package/shared/modules/assets/components/assets-details/assets-details.vue +1 -1
  119. package/shared/modules/dynamic/components/fields/storybook/Button.stories.ts +186 -247
  120. package/shared/modules/dynamic/components/fields/storybook/Card.stories.ts +175 -176
  121. package/shared/modules/dynamic/components/fields/storybook/common/templates.ts +8 -8
  122. package/shared/modules/dynamic/pages/dynamic-blade-list.vue +153 -187
  123. package/tailwind.config.ts +127 -126
  124. package/ui/components/atoms/vc-button/vc-button.stories.ts +1 -16
  125. package/ui/components/atoms/vc-button/vc-button.vue +74 -63
  126. package/ui/components/atoms/vc-card/vc-card.stories.ts +102 -102
  127. package/ui/components/atoms/vc-card/vc-card.vue +164 -159
  128. package/ui/components/atoms/vc-icon/icons/GridDotsIcon.vue +22 -0
  129. package/ui/components/atoms/vc-icon/icons/ShoppingCardIcon.vue +16 -0
  130. package/ui/components/atoms/vc-icon/icons/index.ts +2 -0
  131. package/ui/components/molecules/vc-field/vc-field.vue +1 -1
  132. package/ui/components/organisms/vc-app/_internal/composables/useAppMenuState.ts +12 -1
  133. package/ui/components/organisms/vc-app/_internal/vc-app-bar/_internal/AppBarContent.vue +1 -2
  134. package/ui/components/organisms/vc-app/_internal/vc-app-bar/_internal/AppBarHeader.vue +1 -1
  135. package/ui/components/organisms/vc-app/_internal/vc-app-bar/_internal/AppBarOverlay.vue +0 -1
  136. package/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue +274 -112
  137. package/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/_internal/vc-app-menu-link.vue +81 -37
  138. package/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue +7 -5
  139. package/ui/components/organisms/vc-app/vc-app.vue +26 -15
  140. package/ui/components/organisms/vc-table/_internal/vc-table-base-header/vc-table-base-header.vue +5 -7
  141. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/{vc-table-header/vc-table-header.vue → vc-table-columns-header/vc-table-columns-header.vue} +23 -21
  142. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue +1 -0
  143. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue +1 -1
  144. package/ui/components/organisms/vc-table/_internal/vc-table-header/vc-table-header.vue +12 -1
  145. package/ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue +45 -2
  146. package/ui/components/organisms/vc-table/composables/useTableColumnReorder.ts +5 -5
  147. package/ui/components/organisms/vc-table/composables/useTableColumnResize.ts +1 -1
  148. package/ui/components/organisms/vc-table/composables/useTableRowReorder.ts +1 -0
  149. package/core/services/toolbarbus-service.ts +0 -34
  150. package/dist/core/composables/useGlobalSearch.d.ts.map +0 -1
  151. package/dist/core/services/toolbarbus-service.d.ts +0 -10
  152. package/dist/core/services/toolbarbus-service.d.ts.map +0 -1
  153. package/dist/ui/components/organisms/vc-app/composables/useToolbarSlots.d.ts +0 -5
  154. package/dist/ui/components/organisms/vc-app/composables/useToolbarSlots.d.ts.map +0 -1
  155. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-header/vc-table-header.vue.d.ts.map +0 -1
  156. package/ui/components/organisms/vc-app/composables/useToolbarSlots.ts +0 -37
@@ -35,7 +35,17 @@ declare const _default: <T extends string | TableItem>(__VLS_props: {
35
35
  index: number;
36
36
  }) => any>> & Partial<Record<`item_${string}`, (_: {
37
37
  item: T;
38
- cell: ITableColumns;
38
+ cell: import("../../../../../../core/types").ITableColumnsBase | (import("../../../../../../core/types").ITableColumnsBase & {
39
+ type: "image";
40
+ emptyIcon?: string | undefined;
41
+ });
42
+ index: number;
43
+ }) => any>> & Partial<Record<`item_${string}`, (_: {
44
+ item: T;
45
+ cell: import("../../../../../../core/types").ITableColumnsBase | (import("../../../../../../core/types").ITableColumnsBase & {
46
+ type: "money";
47
+ currencyField: string;
48
+ });
39
49
  index: number;
40
50
  }) => any>> & Partial<Record<`item_${string}`, (_: {
41
51
  item: T;
@@ -99,7 +109,17 @@ declare const _default: <T extends string | TableItem>(__VLS_props: {
99
109
  index: number;
100
110
  }) => any>> & Partial<Record<`item_${string}`, (_: {
101
111
  item: T;
102
- cell: ITableColumns;
112
+ cell: import("../../../../../../core/types").ITableColumnsBase | (import("../../../../../../core/types").ITableColumnsBase & {
113
+ type: "image";
114
+ emptyIcon?: string | undefined;
115
+ });
116
+ index: number;
117
+ }) => any>> & Partial<Record<`item_${string}`, (_: {
118
+ item: T;
119
+ cell: import("../../../../../../core/types").ITableColumnsBase | (import("../../../../../../core/types").ITableColumnsBase & {
120
+ type: "money";
121
+ currencyField: string;
122
+ });
103
123
  index: number;
104
124
  }) => any>> & Partial<Record<`item_${string}`, (_: {
105
125
  item: T;
@@ -166,7 +186,17 @@ declare const _default: <T extends string | TableItem>(__VLS_props: {
166
186
  index: number;
167
187
  }) => any>> & Partial<Record<`item_${string}`, (_: {
168
188
  item: T;
169
- cell: ITableColumns;
189
+ cell: import("../../../../../../core/types").ITableColumnsBase | (import("../../../../../../core/types").ITableColumnsBase & {
190
+ type: "image";
191
+ emptyIcon?: string | undefined;
192
+ });
193
+ index: number;
194
+ }) => any>> & Partial<Record<`item_${string}`, (_: {
195
+ item: T;
196
+ cell: import("../../../../../../core/types").ITableColumnsBase | (import("../../../../../../core/types").ITableColumnsBase & {
197
+ type: "money";
198
+ currencyField: string;
199
+ });
170
200
  index: number;
171
201
  }) => any>> & Partial<Record<`item_${string}`, (_: {
172
202
  item: T;
@@ -1 +1 @@
1
- {"version":3,"file":"vc-table-mobile-view.vue.d.ts","sourceRoot":"","sources":["../../../../../../../ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;;;;;;eA6B5C;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE;eAAS,MAAM;;;aAC9D,MAAM,GAAG,SAAS;eAAS,MAAM;;aA6evD,aAAa,EAAE;;;;;;;;iBAQX,OAAO;;6BAHK,OAAO;8BACN,IAAI;;WAczB,GAAG;;;;;UAhD4E,GAAG;;;;UACpB,GAAG;;;;UACH,GAAG;;;YAEpC,GAAG;0BACP,GAAG;uBACN,GAAG;;;YAzd1B,WAAW,YAAY,IAAI;YAC3B,gBAAgB,QAAQ;YAAE,OAAO;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;YAClG,YAAY,QAAQ;YAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;;yCAggB3D,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,KAAG,IAAI;;;;;;mBAjgBlB;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE;mBAAS,MAAM;;;iBAC9D,MAAM,GAAG,SAAS;mBAAS,MAAM;;iBA6evD,aAAa,EAAE;;;;;;;;qBAQX,OAAO;;iCAHK,OAAO;kCACN,IAAI;;oBAahB,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;WAClD,GAAG;;;;;UAhD4E,GAAG;;;;UACpB,GAAG;;;;UACH,GAAG;;;YAEpC,GAAG;0BACP,GAAG;uBACN,GAAG;;;YAzd1B,WAAW,YAAY,IAAI;YAC3B,gBAAgB,QAAQ;YAAE,OAAO;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;YAClG,YAAY,QAAQ;YAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;;;;;;;;;;;uBADpC;oBAAE,KAAK,EAAE,MAAM,CAAC;oBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;iBAAE;uBAAS,MAAM;;;qBAC9D,MAAM,GAAG,SAAS;uBAAS,MAAM;;qBA6evD,aAAa,EAAE;;;;;;;;yBAQX,OAAO;;qCAHK,OAAO;sCACN,IAAI;;wBAahB,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;eAClD,GAAG;;;;;cAhD4E,GAAG;;;;cACpB,GAAG;;;;cACH,GAAG;;;gBAEpC,GAAG;8BACP,GAAG;2BACN,GAAG;;;gBAzd1B,WAAW,YAAY,IAAI;gBAC3B,gBAAgB,QAAQ;gBAAE,OAAO;oBAAE,KAAK,EAAE,MAAM,CAAC;oBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;iBAAE,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI;gBAClG,YAAY,QAAQ;gBAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI;;;;AA1B3E,wBAgiB2E"}
1
+ {"version":3,"file":"vc-table-mobile-view.vue.d.ts","sourceRoot":"","sources":["../../../../../../../ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;;;;;;eA6B5C;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE;eAAS,MAAM;;;aAC9D,MAAM,GAAG,SAAS;eAAS,MAAM;;aAsjBvD,aAAa,EAAE;;;;;;;;iBAQX,OAAO;;6BAHK,OAAO;8BACN,IAAI;;WAczB,GAAG;;;;;UAjD4E,GAAG;;;;;;;UACpB,GAAG;;;;;;;UACH,GAAG;;;;UACD,GAAG;;;YAEtC,GAAG;0BACP,GAAG;uBACN,GAAG;;;YAliB1B,WAAW,YAAY,IAAI;YAC3B,gBAAgB,QAAQ;YAAE,OAAO;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;YAClG,YAAY,QAAQ;YAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;;yCAykB3D,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,KAAG,IAAI;;;;;;mBA1kBlB;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE;mBAAS,MAAM;;;iBAC9D,MAAM,GAAG,SAAS;mBAAS,MAAM;;iBAsjBvD,aAAa,EAAE;;;;;;;;qBAQX,OAAO;;iCAHK,OAAO;kCACN,IAAI;;oBAahB,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;WAClD,GAAG;;;;;UAjD4E,GAAG;;;;;;;UACpB,GAAG;;;;;;;UACH,GAAG;;;;UACD,GAAG;;;YAEtC,GAAG;0BACP,GAAG;uBACN,GAAG;;;YAliB1B,WAAW,YAAY,IAAI;YAC3B,gBAAgB,QAAQ;YAAE,OAAO;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;YAClG,YAAY,QAAQ;YAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI;;;;;;;;;;;uBADpC;oBAAE,KAAK,EAAE,MAAM,CAAC;oBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;iBAAE;uBAAS,MAAM;;;qBAC9D,MAAM,GAAG,SAAS;uBAAS,MAAM;;qBAsjBvD,aAAa,EAAE;;;;;;;;yBAQX,OAAO;;qCAHK,OAAO;sCACN,IAAI;;wBAahB,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;eAClD,GAAG;;;;;cAjD4E,GAAG;;;;;;;cACpB,GAAG;;;;;;;cACH,GAAG;;;;cACD,GAAG;;;gBAEtC,GAAG;8BACP,GAAG;2BACN,GAAG;;;gBAliB1B,WAAW,YAAY,IAAI;gBAC3B,gBAAgB,QAAQ;gBAAE,OAAO;oBAAE,KAAK,EAAE,MAAM,CAAC;oBAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;iBAAE,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI;gBAClG,YAAY,QAAQ;gBAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI;;;;AA1B3E,wBAymB2E"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTableRowReorder.d.ts","sourceRoot":"","sources":["../../../../../../ui/components/organisms/vc-table/composables/useTableRowReorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,GAAG,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,GAAG,MAAM,EAC7D,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EACf,SAAS,EAAE,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,EAAE,CAAA;CAAE,KAAK,IAAI;;4BAqBhD,UAAU;4BA6BV,SAAS,QAAQ,CAAC;2BAoBnB,SAAS,QAAQ,CAAC;4BAqDjB,SAAS;0BAMX,SAAS;uBAaZ,SAAS;EA0BpC"}
1
+ {"version":3,"file":"useTableRowReorder.d.ts","sourceRoot":"","sources":["../../../../../../ui/components/organisms/vc-table/composables/useTableRowReorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,GAAG,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,GAAG,MAAM,EAC7D,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EACf,SAAS,EAAE,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,EAAE,CAAA;CAAE,KAAK,IAAI;;4BAqBhD,UAAU;4BA6BV,SAAS,QAAQ,CAAC;2BAqBnB,SAAS,QAAQ,CAAC;4BAqDjB,SAAS;0BAMX,SAAS;uBAaZ,SAAS;EA0BpC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vc-shell/framework",
3
- "version": "1.1.0-alpha.3",
3
+ "version": "1.1.0-alpha.4",
4
4
  "type": "module",
5
5
  "main": "./dist/framework.js",
6
6
  "types": "./dist/index.d.ts",
@@ -29,7 +29,10 @@
29
29
  "build:types": "vue-tsc --declaration --emitDeclarationOnly --outDir dist",
30
30
  "type-check": "vue-tsc --noEmit",
31
31
  "generate-icons": "tsx scripts/generate-icons.mts",
32
- "check-locales": "tsx scripts/check-locales.mts"
32
+ "check-locales": "tsx scripts/check-locales.mts",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "test:coverage": "vitest run --coverage"
33
36
  },
34
37
  "dependencies": {
35
38
  "@floating-ui/vue": "^1.0.6",
@@ -62,10 +65,11 @@
62
65
  },
63
66
  "devDependencies": {
64
67
  "@types/dompurify": "^3.0.5",
65
- "@vc-shell/api-client-generator": "^1.1.0-alpha.3",
66
- "@vc-shell/config-generator": "^1.1.0-alpha.3",
67
- "@vc-shell/ts-config": "^1.1.0-alpha.3",
68
+ "@vc-shell/api-client-generator": "^1.1.0-alpha.4",
69
+ "@vc-shell/config-generator": "^1.1.0-alpha.4",
70
+ "@vc-shell/ts-config": "^1.1.0-alpha.4",
68
71
  "@vitejs/plugin-vue": "5.0.3",
72
+ "@vue/test-utils": "^2.4.5",
69
73
  "cypress-signalr-mock": "^1.5.0",
70
74
  "sass": "^1.69.6",
71
75
  "shx": "^0.3.4",
@@ -73,6 +77,7 @@
73
77
  "tsx": "^4.7.1",
74
78
  "typescript": "~5.3.3",
75
79
  "vite": "5.3.6",
80
+ "vitest": "^1.3.1",
76
81
  "vue-component-type-helpers": "^1.8.27",
77
82
  "vue-tsc": "^1.8.27"
78
83
  },
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <div class="dashboard-widget-card">
3
+ <div class="dashboard-widget-card__header-wrapper">
4
+ <div class="dashboard-widget-card__header">
5
+ <slot name="header">
6
+ <div class="dashboard-widget-card__header-content">
7
+ <VcIcon
8
+ v-if="icon"
9
+ class="dashboard-widget-card__icon"
10
+ :icon="icon"
11
+ size="xl"
12
+ ></VcIcon>
13
+ <div class="dashboard-widget-card__header">{{ props.header }}</div>
14
+ </div>
15
+ </slot>
16
+ </div>
17
+ <div class="dashboard-widget-card__actions">
18
+ <slot name="actions"></slot>
19
+ </div>
20
+ </div>
21
+ <div class="dashboard-widget-card__body">
22
+ <slot></slot>
23
+ </div>
24
+ </div>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ export interface Props {
29
+ header?: string;
30
+ icon?: string;
31
+ }
32
+
33
+ const props = defineProps<Props>();
34
+ </script>
35
+
36
+ <style lang="scss">
37
+ :root {
38
+ --dashboard-widget-card-header-color: var(--additional-50);
39
+ --dashboard-widget-card-header-text-color: var(--neutrals-950);
40
+ --dashboard-widget-card-icon-color: var(--neutrals-950);
41
+ --dashboard-widget-card-header-border-color: var(--base-border-color, var(--neutrals-200));
42
+ }
43
+
44
+ .dashboard-widget-card {
45
+ @apply tw-rounded-md tw-overflow-hidden tw-h-full tw-bg-[var(--dashboard-widget-card-header-color)];
46
+
47
+ &__header-wrapper {
48
+ @apply tw-p-6 tw-bg-[var(--dashboard-widget-card-header-color)] tw-rounded-t-md tw-border tw-border-[color:var(--dashboard-widget-card-header-border-color)] tw-border-solid tw-flex tw-justify-between tw-items-center tw-text-xl tw-font-bold tw-text-[var(--dashboard-widget-card-header-text-color)];
49
+ }
50
+
51
+ &__actions {
52
+ @apply tw-flex tw-items-center tw-gap-[14px];
53
+ }
54
+
55
+ &__header {
56
+ @apply tw-flex;
57
+ }
58
+
59
+ &__icon {
60
+ @apply tw-text-[var(--dashboard-widget-card-icon-color)];
61
+ }
62
+
63
+ &__header-content {
64
+ @apply tw-flex tw-items-center tw-gap-[14px];
65
+ }
66
+ }
67
+ </style>
@@ -0,0 +1 @@
1
+ export { default as DashboardWidgetCard } from "./dashboard-widget-card.vue";
@@ -0,0 +1,369 @@
1
+ <template>
2
+ <VcContainer
3
+ no-padding
4
+ class="vc-dashboard-grid"
5
+ >
6
+ <div
7
+ ref="gridContainerRef"
8
+ class="vc-dashboard-grid__container"
9
+ >
10
+ <!-- Position indicator with smooth animation -->
11
+ <div
12
+ v-if="draggedWidget && previewPosition"
13
+ class="vc-dashboard-grid__position-preview"
14
+ :class="{
15
+ 'is-animating': isDragging,
16
+ }"
17
+ :style="getPreviewStyles(draggedWidget, previewPosition)"
18
+ ></div>
19
+
20
+ <!-- Widgets -->
21
+ <DashboardWidget
22
+ v-for="widget in widgets"
23
+ :key="widget.id"
24
+ :widget="widget"
25
+ :style="getWidgetStyles(widget)"
26
+ :is-dragging="draggedWidget?.id === widget.id"
27
+ :class="{
28
+ 'is-dragging': draggedWidget?.id === widget.id,
29
+ 'is-displaced': isWidgetDisplaced(widget.id),
30
+ 'is-animating': isDragging && (draggedWidget?.id === widget.id || isWidgetDisplaced(widget.id)),
31
+ }"
32
+ :data-id="widget.id"
33
+ @drag="(e: MouseEvent | TouchEvent) => handleMouseDown(e, widget, e.target as HTMLElement)"
34
+ />
35
+ </div>
36
+ </VcContainer>
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ import { ref, onMounted, onUnmounted, defineExpose, computed, watch, onUpdated } from "vue";
41
+ import type { Ref, Component } from "vue";
42
+ import type { IDashboardWidget } from "./types";
43
+ import { useDashboardGrid } from "./composables/useDashboardGrid";
44
+ import { useDashboardDragAndDrop } from "./composables/useDashboardDragAndDrop";
45
+ import { useDashboard } from "../../../core/composables/useDashboard";
46
+ import VcContainer from "../../../ui/components/atoms/vc-container/vc-container.vue";
47
+ import DashboardWidget from "./_internal/DashboardWidget.vue";
48
+
49
+ // Reference to the grid container for coordinate calculations
50
+ const gridContainerRef = ref<HTMLElement | null>(null);
51
+
52
+ // Initialize Grid
53
+ const dashboard = useDashboard();
54
+ const {
55
+ widgets,
56
+ layout,
57
+
58
+ arrangeWidgetsInRows,
59
+ initializeLayout,
60
+ getGridRows,
61
+ } = useDashboardGrid();
62
+
63
+ // Initialize Drag & Drop
64
+ const { draggedWidget, previewPosition, displacedWidgets, isDragging, handleMouseDown, setGridContainer } =
65
+ useDashboardDragAndDrop(dashboard.updateWidgetPosition, getGridRows);
66
+
67
+ // Pass grid container reference to the dragging composable
68
+ watch(gridContainerRef, (container) => {
69
+ if (container) {
70
+ setGridContainer(container);
71
+ }
72
+ });
73
+
74
+ // Cached cell size
75
+ const cellSizeCache = ref<{ width: number; height: number } | null>(null);
76
+ // Previous container width
77
+ const previousContainerWidth = ref<number>(0);
78
+ // ResizeObserver instance
79
+ const resizeObserver = ref<ResizeObserver | null>(null);
80
+ // Debounce timer
81
+ const resizeDebounceTimer = ref<number | null>(null);
82
+
83
+ // Function to get cell size with caching
84
+ const getCellSize = () => {
85
+ if (cellSizeCache.value) return cellSizeCache.value;
86
+ if (!gridContainerRef.value) return { width: 0, height: 0 };
87
+
88
+ const rect = gridContainerRef.value.getBoundingClientRect();
89
+ const availableWidth = rect.width - 2 * 18; // Subtract horizontal padding (18px on each side)
90
+ const cellWidthWithGap = availableWidth / 12; // Total width including gap
91
+
92
+ const size = {
93
+ width: Math.max(cellWidthWithGap, 0), // Protection from negative values
94
+ height: 80, // Cell height remains the same
95
+ };
96
+
97
+ cellSizeCache.value = size;
98
+ previousContainerWidth.value = rect.width;
99
+ return size;
100
+ };
101
+
102
+ // Clear cache when window is resized
103
+ const clearCellSizeCache = () => {
104
+ cellSizeCache.value = null;
105
+ };
106
+
107
+ // Recalculate widget positions based on new container size
108
+ const recalculateWidgetPositions = () => {
109
+ // First recalculate cell size to get updated dimensions
110
+ getCellSize();
111
+
112
+ // Update previous width
113
+ if (gridContainerRef.value) {
114
+ previousContainerWidth.value = gridContainerRef.value.getBoundingClientRect().width;
115
+ }
116
+ };
117
+
118
+ // Handle container resize with debounce
119
+ const handleContainerResize = (entries: ResizeObserverEntry[]) => {
120
+ if (!entries.length || isDragging.value) return;
121
+
122
+ const entry = entries[0];
123
+ const newWidth = entry.contentRect.width;
124
+
125
+ // Clear cache to force recalculation of sizes
126
+ clearCellSizeCache();
127
+
128
+ // If width changed significantly (more than 5% or 50px), reposition widgets
129
+ const widthChange = Math.abs(newWidth - previousContainerWidth.value);
130
+ const widthChangePercent = previousContainerWidth.value ? (widthChange / previousContainerWidth.value) * 100 : 0;
131
+
132
+ if (widthChangePercent > 5 || widthChange > 50) {
133
+ recalculateWidgetPositions();
134
+ }
135
+ }; // 300ms debounce
136
+
137
+ // Get styles for preview position indicator
138
+ const getPreviewStyles = (widget: IDashboardWidget, position: { x: number; y: number }) => {
139
+ const cellSize = getCellSize();
140
+ if (!position || !widget?.size) return {};
141
+
142
+ const widgetGap = 20; // Widget gap in pixels
143
+
144
+ return {
145
+ width: `${widget.size.width * cellSize.width - widgetGap}px`,
146
+ height: `${widget.size.height * cellSize.height - widgetGap}px`,
147
+ transform: `translate(${position.x * cellSize.width + widgetGap / 2}px, ${position.y * cellSize.height + widgetGap / 2}px)`,
148
+ };
149
+ };
150
+
151
+ // Helper to check if widget is being displaced
152
+ const isWidgetDisplaced = (widgetId: string) => {
153
+ return displacedWidgets.value.has(widgetId);
154
+ };
155
+
156
+ // Get combined widget styles for absolute positioning
157
+ const getWidgetStyles = computed(() => (widget: IDashboardWidget) => {
158
+ const position = layout.value.get(widget.id);
159
+ if (!position) return { display: "none" };
160
+
161
+ const cellSize = getCellSize();
162
+ const widgetGap = 20; // Widget gap in pixels
163
+
164
+ // Calculate actual dimensions with gaps
165
+ const width = widget.size.width * cellSize.width - widgetGap;
166
+ const height = widget.size.height * cellSize.height - widgetGap;
167
+
168
+ // Calculate position with gaps
169
+ const left = position.x * cellSize.width + widgetGap / 2;
170
+ const top = position.y * cellSize.height + widgetGap / 2;
171
+
172
+ // Base styles for all widgets
173
+ const baseStyles = {
174
+ position: "absolute",
175
+ width: `${width}px`,
176
+ height: `${height}px`,
177
+ };
178
+
179
+ // If widget is being displaced by another widget
180
+ if (isWidgetDisplaced(widget.id)) {
181
+ const newPos = displacedWidgets.value.get(widget.id)!;
182
+ return {
183
+ ...baseStyles,
184
+ transform: `translate(${newPos.x * cellSize.width + widgetGap / 2}px, ${newPos.y * cellSize.height + widgetGap / 2}px)`,
185
+ transition: "transform var(--dashboard-transition-duration) var(--dashboard-transition-timing)",
186
+ zIndex: "10",
187
+ } as Record<string, string>;
188
+ }
189
+
190
+ // If widget is currently being dragged
191
+ if (draggedWidget.value?.id === widget.id) {
192
+ return {
193
+ ...baseStyles,
194
+ transform: `translate(${left}px, ${top}px)`,
195
+ opacity: "0", // Hide original since clone is displayed
196
+ pointerEvents: "none",
197
+ zIndex: "1",
198
+ transition: "none", // Disable animations for the source widget
199
+ } as Record<string, string>;
200
+ }
201
+
202
+ // Regular widget
203
+ return {
204
+ ...baseStyles,
205
+ transform: `translate(${left}px, ${top}px)`,
206
+ transition: "transform var(--dashboard-transition-duration) var(--dashboard-transition-timing)",
207
+ } as Record<string, string>;
208
+ });
209
+
210
+ // Public method for rearranging widgets
211
+ const rearrangeWidgets = () => {
212
+ arrangeWidgetsInRows(widgets.value);
213
+ };
214
+
215
+ // Public method to manually trigger a layout recalculation
216
+ const recalculateLayout = () => {
217
+ clearCellSizeCache();
218
+ recalculateWidgetPositions();
219
+ };
220
+
221
+ // Add cleanup on component unmount
222
+ onMounted(() => {
223
+ initializeLayout();
224
+ // Initial size calculation
225
+ getCellSize();
226
+
227
+ // Initialize resize observer for the container
228
+ if (gridContainerRef.value && window.ResizeObserver) {
229
+ resizeObserver.value = new ResizeObserver(handleContainerResize);
230
+ resizeObserver.value.observe(gridContainerRef.value);
231
+ }
232
+
233
+ // Also keep the window resize listener for fallback compatibility
234
+ window.addEventListener("resize", clearCellSizeCache);
235
+ });
236
+
237
+ onUnmounted(() => {
238
+ // Cleanup resize observer
239
+ if (resizeObserver.value) {
240
+ resizeObserver.value.disconnect();
241
+ resizeObserver.value = null;
242
+ }
243
+
244
+ // Clear debounce timer if any
245
+ if (resizeDebounceTimer.value !== null) {
246
+ window.clearTimeout(resizeDebounceTimer.value);
247
+ resizeDebounceTimer.value = null;
248
+ }
249
+
250
+ window.removeEventListener("resize", clearCellSizeCache);
251
+ });
252
+
253
+ // Export public methods
254
+ defineExpose({
255
+ rearrangeWidgets,
256
+ recalculateLayout,
257
+ });
258
+ </script>
259
+
260
+ <style lang="scss">
261
+ :root {
262
+ --dashboard-background: var(--additional-50);
263
+ --dashboard-grid-line: var(--neutrals-200);
264
+ --dashboard-grid-line-active: var(--neutrals-300);
265
+ --dashboard-grid-border: var(--neutrals-300);
266
+ --dashboard-preview-bg: var(--primary-100);
267
+ --dashboard-preview-border: var(--primary-500);
268
+ --dashboard-valid-bg: var(--secondary-100);
269
+ --dashboard-valid-border: var(--secondary-500);
270
+ --dashboard-cell-height: 80px;
271
+ --dashboard-cell-gap-vertical: 24px;
272
+ --dashboard-cell-gap-horizontal: 18px;
273
+ --dashboard-widget-gap: 20px;
274
+ --dashboard-animation-duration: 200ms;
275
+ --dashboard-animation-timing: cubic-bezier(0.4, 0, 0.2, 1);
276
+ --dashboard-transition-duration: 0.35s;
277
+ --dashboard-transition-timing: cubic-bezier(0.25, 0.1, 0.25, 1);
278
+ --dashboard-drag-scale: 1.02;
279
+ --dashboard-gap: 20px;
280
+ --dashboard-widget-shadow-base: 0px 0px 6px -2px rgb(from var(--neutrals-950) r g b / 0.1);
281
+ --dashboard-widget-shadow-elevated: 3px 9px 15px -3px rgb(from var(--neutrals-950) r g b / 0.08);
282
+ --dashboard-position-preview-color: rgb(from var(--primary-500) r g b / 0.15);
283
+ --dashboard-position-preview-border-color: rgb(from var(--primary-500) r g b / 0.5);
284
+ }
285
+
286
+ .vc-dashboard-grid {
287
+ @apply tw-w-full tw-h-full;
288
+ background-color: var(--dashboard-background);
289
+ touch-action: none;
290
+
291
+ &__container {
292
+ @apply tw-w-full tw-h-full tw-relative;
293
+ padding: var(--dashboard-cell-gap-vertical) var(--dashboard-cell-gap-horizontal);
294
+ position: relative;
295
+ overflow: auto;
296
+ min-height: calc(var(--dashboard-cell-height) * 12 + var(--dashboard-cell-gap-vertical) * 2);
297
+ }
298
+
299
+ &__position-preview {
300
+ position: absolute;
301
+ background-color: var(--dashboard-position-preview-color);
302
+ border: 2px dashed var(--dashboard-position-preview-border-color);
303
+ border-radius: 8px;
304
+ z-index: 100;
305
+ pointer-events: none;
306
+ opacity: 0.8;
307
+ transition: transform var(--dashboard-transition-duration) var(--dashboard-transition-timing);
308
+
309
+ &.is-animating {
310
+ transition: transform var(--dashboard-transition-duration) var(--dashboard-transition-timing);
311
+ }
312
+ }
313
+ }
314
+
315
+ // Widget styles
316
+ .dashboard-widget {
317
+ position: absolute;
318
+ transition:
319
+ transform var(--dashboard-transition-duration) var(--dashboard-transition-timing),
320
+ opacity 0.2s ease;
321
+ touch-action: none;
322
+ will-change: transform;
323
+ backface-visibility: hidden;
324
+
325
+ &:hover {
326
+ cursor: move;
327
+ }
328
+
329
+ &.is-dragging {
330
+ z-index: 1000;
331
+ opacity: 0;
332
+ transition: none !important; /* Turn off all animations when dragging */
333
+ pointer-events: none;
334
+ }
335
+
336
+ &.is-displaced {
337
+ z-index: 10;
338
+ transition: transform var(--dashboard-transition-duration) var(--dashboard-transition-timing);
339
+ }
340
+
341
+ &.is-animating {
342
+ transition: transform var(--dashboard-transition-duration) var(--dashboard-transition-timing);
343
+ }
344
+ }
345
+
346
+ @keyframes collision-pulse {
347
+ 0% {
348
+ box-shadow: 0 0 0 0 rgba(var(--danger-500), 0.4);
349
+ }
350
+ 70% {
351
+ box-shadow: 0 0 0 10px rgba(var(--danger-500), 0);
352
+ }
353
+ 100% {
354
+ box-shadow: 0 0 0 0 rgba(var(--danger-500), 0);
355
+ }
356
+ }
357
+
358
+ @keyframes valid-pulse {
359
+ 0% {
360
+ opacity: 0.5;
361
+ }
362
+ 50% {
363
+ opacity: 0.7;
364
+ }
365
+ 100% {
366
+ opacity: 0.5;
367
+ }
368
+ }
369
+ </style>
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <div
3
+ class="dashboard-widget"
4
+ data-test="dashboard-widget"
5
+ @mousedown="handleWidgetMouseDown"
6
+ @touchstart.passive="handleWidgetTouchStart"
7
+ >
8
+ <component
9
+ :is="widget.component"
10
+ v-bind="widget.props || {}"
11
+ class="dashboard-widget__content"
12
+ />
13
+ </div>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import type { IDashboardWidget } from "../types";
18
+
19
+ interface Props {
20
+ widget: IDashboardWidget;
21
+ }
22
+
23
+ defineProps<Props>();
24
+
25
+ // Список селекторов интерактивных элементов, на которых не должно срабатывать перетаскивание
26
+ const interactiveSelectors = [
27
+ "button",
28
+ "a",
29
+ "input",
30
+ "select",
31
+ "textarea",
32
+ "label",
33
+ '[role="button"]',
34
+ '[role="checkbox"]',
35
+ '[role="radio"]',
36
+ '[role="switch"]',
37
+ '[role="tab"]',
38
+ '[role="link"]',
39
+ ];
40
+
41
+ // Проверяем, был ли клик на интерактивном элементе
42
+ const isInteractiveElement = (target: EventTarget | null): boolean => {
43
+ if (!target || !(target instanceof Element)) return false;
44
+
45
+ // Проверяем, соответствует ли элемент или его родители селектору интерактивного элемента
46
+ return interactiveSelectors.some((selector) => {
47
+ return target.matches(selector) || !!target.closest(selector);
48
+ });
49
+ };
50
+
51
+ // Обработчик mousedown
52
+ const handleWidgetMouseDown = (event: MouseEvent) => {
53
+ // Если клик был на интерактивном элементе, не начинаем перетаскивание
54
+ if (isInteractiveElement(event.target)) {
55
+ return;
56
+ }
57
+
58
+ // Если клик был на пустой области, запускаем перетаскивание
59
+ event.preventDefault();
60
+ event.stopPropagation();
61
+
62
+ // Эмитим событие drag
63
+ emit("drag", event);
64
+ };
65
+
66
+ // Обработчик touchstart
67
+ const handleWidgetTouchStart = (event: TouchEvent) => {
68
+ // Если касание было на интерактивном элементе, не начинаем перетаскивание
69
+ if (isInteractiveElement(event.target)) {
70
+ return;
71
+ }
72
+
73
+ // Если касание было на пустой области, запускаем перетаскивание
74
+ // Не используем preventDefault здесь, так как уже используем .passive
75
+ emit("drag", event);
76
+ };
77
+
78
+ const emit = defineEmits<{
79
+ (e: "drag", event: MouseEvent | TouchEvent): void;
80
+ }>();
81
+ </script>
82
+
83
+ <style lang="scss">
84
+ :root {
85
+ --dashboard-transition-duration: 0.35s;
86
+ --dashboard-transition-timing: cubic-bezier(0.25, 0.1, 0.25, 1);
87
+ --dashboard-widget-shadow-color: rgb(from var(--additional-950) r g b / 0.08);
88
+ --dashboard-widget-shadow-color-secondary: rgb(from var(--additional-950) r g b / 0.06);
89
+ --dashboard-widget-shadow-active: 0px 6px 16px -2px rgb(from var(--additional-950) r g b / 0.12);
90
+ --dashboard-widget-border-radius: 12px;
91
+ }
92
+
93
+ .dashboard-widget {
94
+ @apply tw-rounded-md;
95
+ border-radius: var(--dashboard-widget-border-radius);
96
+ will-change: transform;
97
+ touch-action: none; /* Prevent default browser touch actions */
98
+ -webkit-tap-highlight-color: transparent; /* Remove tap highlight on mobile */
99
+ user-select: none; /* Prevent text selection on drag */
100
+ -webkit-user-select: none;
101
+ -moz-user-select: none;
102
+ -ms-user-select: none;
103
+ box-shadow:
104
+ 0px 1px 4px -1px var(--dashboard-widget-shadow-color),
105
+ 0px 4px 10px -2px var(--dashboard-widget-shadow-color-secondary);
106
+ transition:
107
+ transform var(--dashboard-transition-duration) var(--dashboard-transition-timing),
108
+ box-shadow 0.2s ease;
109
+
110
+ &:hover {
111
+ @apply tw-cursor-move;
112
+ transform: translateY(-2px);
113
+ box-shadow: var(--dashboard-widget-shadow-active);
114
+ }
115
+
116
+ /* Активное состояние для касаний - более выраженный эффект */
117
+ &:active {
118
+ @apply tw-cursor-grabbing;
119
+ transform: scale(1.02);
120
+ box-shadow: var(--dashboard-widget-shadow-active);
121
+ }
122
+
123
+ &__content {
124
+ @apply tw-w-full tw-h-full tw-rounded-md;
125
+ border-radius: var(--dashboard-widget-border-radius);
126
+ overflow: hidden; /* Ensure nothing breaks out of the widget */
127
+ position: relative;
128
+ z-index: 1;
129
+ height: 100%;
130
+ pointer-events: all; /* Ensure content receives events */
131
+ }
132
+ }
133
+ </style>