@vc-shell/framework 1.0.290 → 1.0.291

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 (175) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/core/composables/index.ts +1 -0
  3. package/core/composables/useTheme/index.ts +60 -0
  4. package/core/directives/loading/styles.css +6 -1
  5. package/dist/core/composables/index.d.ts +1 -0
  6. package/dist/core/composables/index.d.ts.map +1 -1
  7. package/dist/core/composables/useTheme/index.d.ts +11 -0
  8. package/dist/core/composables/useTheme/index.d.ts.map +1 -0
  9. package/dist/framework.js +27885 -27365
  10. package/dist/index.css +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/locales/en.json +6 -0
  13. package/dist/shared/components/app-bar-button/app-bar-button.vue.d.ts +56 -0
  14. package/dist/shared/components/app-bar-button/app-bar-button.vue.d.ts.map +1 -0
  15. package/dist/shared/components/app-bar-button/index.d.ts +2 -0
  16. package/dist/shared/components/app-bar-button/index.d.ts.map +1 -0
  17. package/dist/shared/components/app-switcher/components/vc-app-switcher/vc-app-switcher.vue.d.ts.map +1 -1
  18. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
  19. package/dist/shared/components/index.d.ts +3 -0
  20. package/dist/shared/components/index.d.ts.map +1 -1
  21. package/dist/shared/components/language-selector/language-selector.vue.d.ts.map +1 -1
  22. package/dist/shared/components/notification-dropdown/notification-dropdown.vue.d.ts.map +1 -1
  23. package/dist/shared/components/notification-template/notification-template.vue.d.ts.map +1 -1
  24. package/dist/shared/components/sidebar/index.d.ts +2 -0
  25. package/dist/shared/components/sidebar/index.d.ts.map +1 -0
  26. package/dist/shared/components/sidebar/sidebar.vue.d.ts +49 -0
  27. package/dist/shared/components/sidebar/sidebar.vue.d.ts.map +1 -0
  28. package/dist/shared/components/theme-selector/index.d.ts +2 -0
  29. package/dist/shared/components/theme-selector/index.d.ts.map +1 -0
  30. package/dist/shared/components/theme-selector/theme-selector.vue.d.ts +3 -0
  31. package/dist/shared/components/theme-selector/theme-selector.vue.d.ts.map +1 -0
  32. package/dist/shared/components/user-dropdown-button/user-dropdown-button.vue.d.ts.map +1 -1
  33. package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts.map +1 -1
  34. package/dist/shared/modules/dynamic/types/index.d.ts +3 -0
  35. package/dist/shared/modules/dynamic/types/index.d.ts.map +1 -1
  36. package/dist/shared/pages/ChangePasswordPage/components/change-password/ChangePassword.vue.d.ts +16 -3
  37. package/dist/shared/pages/ChangePasswordPage/components/change-password/ChangePassword.vue.d.ts.map +1 -1
  38. package/dist/shared/pages/ChangePasswordPage/components/change-password/index.d.ts +7 -7
  39. package/dist/shared/pages/ChangePasswordPage/components/change-password/index.d.ts.map +1 -1
  40. package/dist/shared/pages/InvitePage/components/invite/Invite.vue.d.ts +24 -3
  41. package/dist/shared/pages/InvitePage/components/invite/Invite.vue.d.ts.map +1 -1
  42. package/dist/shared/pages/InvitePage/components/invite/index.d.ts +24 -1
  43. package/dist/shared/pages/InvitePage/components/invite/index.d.ts.map +1 -1
  44. package/dist/shared/pages/ResetPasswordPage/components/reset-password/ResetPassword.vue.d.ts +24 -3
  45. package/dist/shared/pages/ResetPasswordPage/components/reset-password/ResetPassword.vue.d.ts.map +1 -1
  46. package/dist/shared/pages/ResetPasswordPage/components/reset-password/index.d.ts +24 -1
  47. package/dist/shared/pages/ResetPasswordPage/components/reset-password/index.d.ts.map +1 -1
  48. package/dist/tailwind.config.d.ts +42 -15
  49. package/dist/tailwind.config.d.ts.map +1 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/dist/ui/components/atoms/vc-badge/vc-badge.vue.d.ts.map +1 -1
  52. package/dist/ui/components/atoms/vc-link/vc-link.vue.d.ts.map +1 -1
  53. package/dist/ui/components/atoms/vc-progress/vc-progress.vue.d.ts.map +1 -1
  54. package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts.map +1 -1
  55. package/dist/ui/components/atoms/vc-tooltip/vc-tooltip.vue.d.ts.map +1 -1
  56. package/dist/ui/components/atoms/vc-video/vc-video.vue.d.ts.map +1 -1
  57. package/dist/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue.d.ts.map +1 -1
  58. package/dist/ui/components/molecules/vc-checkbox/vc-checkbox.vue.d.ts.map +1 -1
  59. package/dist/ui/components/molecules/vc-field/_internal/vc-field-type/vc-field-type.vue.d.ts.map +1 -1
  60. package/dist/ui/components/molecules/vc-field/vc-field.vue.d.ts.map +1 -1
  61. package/dist/ui/components/molecules/vc-file-upload/vc-file-upload.vue.d.ts.map +1 -1
  62. package/dist/ui/components/molecules/vc-input/vc-input.vue.d.ts.map +1 -1
  63. package/dist/ui/components/molecules/vc-slider/vc-slider.vue.d.ts.map +1 -1
  64. 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
  65. package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue.d.ts.map +1 -1
  66. package/dist/ui/components/organisms/vc-app/vc-app.stories.d.ts +2 -0
  67. package/dist/ui/components/organisms/vc-app/vc-app.stories.d.ts.map +1 -1
  68. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts +2 -0
  69. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
  70. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-header/vc-blade-header.vue.d.ts.map +1 -1
  71. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue.d.ts.map +1 -1
  72. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/vc-blade-toolbar.vue.d.ts.map +1 -1
  73. package/dist/ui/components/organisms/vc-gallery/_internal/vc-gallery-preview/vc-gallery-preview.vue.d.ts.map +1 -1
  74. package/dist/ui/components/organisms/vc-table/_internal/vc-table-add-new/vc-table-add-new.vue.d.ts.map +1 -1
  75. package/dist/ui/components/organisms/vc-table/_internal/vc-table-base-header/vc-table-base-header.vue.d.ts +1 -0
  76. package/dist/ui/components/organisms/vc-table/_internal/vc-table-base-header/vc-table-base-header.vue.d.ts.map +1 -1
  77. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
  78. package/dist/ui/components/organisms/vc-table/_internal/vc-table-empty/vc-table-empty.vue.d.ts.map +1 -1
  79. package/dist/ui/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue.d.ts +1 -0
  80. package/dist/ui/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue.d.ts.map +1 -1
  81. package/dist/ui/components/organisms/vc-table/_internal/vc-table-mobile-item/vc-table-mobile-item.vue.d.ts.map +1 -1
  82. package/dist/ui/components/organisms/vc-table/vc-table.stories.d.ts +15 -0
  83. package/dist/ui/components/organisms/vc-table/vc-table.stories.d.ts.map +1 -1
  84. package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts +3 -0
  85. package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
  86. package/package.json +4 -4
  87. package/shared/components/app-bar-button/app-bar-button.vue +169 -0
  88. package/shared/components/app-bar-button/index.ts +1 -0
  89. package/shared/components/app-switcher/components/vc-app-switcher/vc-app-switcher.vue +138 -38
  90. package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +10 -1
  91. package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +55 -30
  92. package/shared/components/change-password/change-password.vue +7 -1
  93. package/shared/components/common/popup/vc-popup-error.vue +1 -1
  94. package/shared/components/common/popup/vc-popup-warning.vue +1 -1
  95. package/shared/components/index.ts +3 -0
  96. package/shared/components/language-selector/language-selector.vue +55 -39
  97. package/shared/components/notification-dropdown/_internal/notification/notification.vue +7 -1
  98. package/shared/components/notification-dropdown/notification-dropdown.vue +96 -83
  99. package/shared/components/notification-template/notification-template.vue +66 -22
  100. package/shared/components/notifications/styles/index.scss +1 -0
  101. package/shared/components/sidebar/index.ts +1 -0
  102. package/shared/components/sidebar/sidebar.vue +96 -0
  103. package/shared/components/theme-selector/index.ts +1 -0
  104. package/shared/components/theme-selector/theme-selector.vue +95 -0
  105. package/shared/components/user-dropdown-button/user-dropdown-button.vue +139 -86
  106. package/shared/modules/assets/components/assets-details/assets-details.vue +9 -2
  107. package/shared/modules/assets-manager/components/assets-manager/assets-manager.vue +16 -6
  108. package/shared/modules/dynamic/composables/useFilterBuilder/index.ts +1 -1
  109. package/shared/modules/dynamic/helpers/nodeBuilder.ts +1 -1
  110. package/shared/modules/dynamic/pages/dynamic-blade-form.vue +6 -2
  111. package/shared/modules/dynamic/pages/dynamic-blade-list.vue +16 -2
  112. package/shared/modules/dynamic/types/index.ts +3 -0
  113. package/shared/pages/ChangePasswordPage/components/change-password/ChangePassword.vue +14 -9
  114. package/shared/pages/InvitePage/components/invite/Invite.vue +59 -15
  115. package/shared/pages/LoginPage/components/login/Login.vue +78 -22
  116. package/shared/pages/ResetPasswordPage/components/reset-password/ResetPassword.vue +67 -15
  117. package/tailwind.config.ts +281 -15
  118. package/ui/components/atoms/vc-badge/vc-badge.vue +38 -23
  119. package/ui/components/atoms/vc-button/vc-button.vue +37 -34
  120. package/ui/components/atoms/vc-card/vc-card.vue +17 -11
  121. package/ui/components/atoms/vc-col/vc-col.vue +4 -6
  122. package/ui/components/atoms/vc-container/vc-container.vue +26 -8
  123. package/ui/components/atoms/vc-hint/vc-hint.vue +8 -2
  124. package/ui/components/atoms/vc-icon/vc-icon.vue +3 -3
  125. package/ui/components/atoms/vc-image/vc-image.vue +33 -9
  126. package/ui/components/atoms/vc-label/vc-label.vue +38 -9
  127. package/ui/components/atoms/vc-link/vc-link.vue +15 -8
  128. package/ui/components/atoms/vc-loading/vc-loading.vue +37 -8
  129. package/ui/components/atoms/vc-progress/vc-progress.vue +29 -21
  130. package/ui/components/atoms/vc-row/vc-row.vue +4 -2
  131. package/ui/components/atoms/vc-status/vc-status.vue +29 -20
  132. package/ui/components/atoms/vc-status-icon/vc-status-icon.vue +20 -3
  133. package/ui/components/atoms/vc-switch/vc-switch.vue +41 -17
  134. package/ui/components/atoms/vc-tooltip/vc-tooltip.vue +35 -9
  135. package/ui/components/atoms/vc-video/vc-video.vue +28 -6
  136. package/ui/components/atoms/vc-widget/vc-widget.vue +59 -28
  137. package/ui/components/molecules/vc-breadcrumbs/_internal/vc-breadcrumbs-item/vc-breadcrumbs-item.vue +29 -27
  138. package/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue +34 -11
  139. package/ui/components/molecules/vc-checkbox/vc-checkbox.vue +43 -21
  140. package/ui/components/molecules/vc-editor/vc-editor.vue +70 -32
  141. package/ui/components/molecules/vc-field/_internal/vc-field-type/vc-field-type.vue +32 -16
  142. package/ui/components/molecules/vc-field/vc-field.vue +36 -13
  143. package/ui/components/molecules/vc-file-upload/vc-file-upload.vue +75 -25
  144. package/ui/components/molecules/vc-input/vc-input.vue +279 -218
  145. package/ui/components/molecules/vc-input-currency/vc-input-currency.vue +24 -2
  146. package/ui/components/molecules/vc-multivalue/vc-multivalue.vue +102 -64
  147. package/ui/components/molecules/vc-notification/vc-notification.vue +40 -15
  148. package/ui/components/molecules/vc-pagination/vc-pagination.vue +19 -15
  149. package/ui/components/molecules/vc-radio-button/vc-radio-button.vue +18 -23
  150. package/ui/components/molecules/vc-rating/vc-rating.vue +9 -5
  151. package/ui/components/molecules/vc-select/vc-select.vue +211 -65
  152. package/ui/components/molecules/vc-slider/vc-slider.vue +32 -13
  153. package/ui/components/molecules/vc-textarea/vc-textarea.vue +17 -12
  154. package/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue +68 -14
  155. package/ui/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/_internal/vc-app-menu-link.vue +112 -122
  156. package/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue +213 -96
  157. package/ui/components/organisms/vc-app/vc-app.vue +41 -15
  158. package/ui/components/organisms/vc-blade/_internal/vc-blade-header/vc-blade-header.vue +78 -30
  159. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue +81 -59
  160. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/vc-blade-toolbar.vue +27 -13
  161. package/ui/components/organisms/vc-blade/vc-blade.vue +177 -46
  162. package/ui/components/organisms/vc-gallery/_internal/vc-gallery-item/vc-gallery-item.vue +40 -11
  163. package/ui/components/organisms/vc-gallery/_internal/vc-gallery-preview/vc-gallery-preview.vue +52 -18
  164. package/ui/components/organisms/vc-gallery/vc-gallery.vue +38 -6
  165. package/ui/components/organisms/vc-login-form/vc-login-form.vue +40 -14
  166. package/ui/components/organisms/vc-popup/vc-popup.vue +186 -44
  167. package/ui/components/organisms/vc-table/_internal/vc-table-add-new/vc-table-add-new.vue +25 -6
  168. package/ui/components/organisms/vc-table/_internal/vc-table-base-header/vc-table-base-header.vue +48 -12
  169. package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +130 -60
  170. package/ui/components/organisms/vc-table/_internal/vc-table-column-switcher/vc-table-column-switcher.vue +55 -7
  171. package/ui/components/organisms/vc-table/_internal/vc-table-counter/vc-table-counter.vue +17 -5
  172. package/ui/components/organisms/vc-table/_internal/vc-table-empty/vc-table-empty.vue +38 -6
  173. package/ui/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue +111 -62
  174. package/ui/components/organisms/vc-table/_internal/vc-table-mobile-item/vc-table-mobile-item.vue +139 -46
  175. package/ui/components/organisms/vc-table/vc-table.vue +370 -128
@@ -0,0 +1,169 @@
1
+ <template>
2
+ <div class="app-bar-button">
3
+ <VcTooltip
4
+ placement="bottom"
5
+ :offset="{ crossAxis: 0, mainAxis: -10 }"
6
+ class="tw-w-full"
7
+ >
8
+ <template
9
+ v-if="!isDropdownVisible && !!title"
10
+ #tooltip
11
+ >{{ title }}</template
12
+ >
13
+ <button
14
+ ref="referenceButton"
15
+ class="app-bar-button__button"
16
+ @click.stop="toggleNotificationsDrop"
17
+ >
18
+ <div
19
+ :class="[
20
+ 'app-bar-button__button-container',
21
+ { 'app-bar-button__button-container--active': isDropdownVisible && $slots['dropdown-content'] },
22
+ ]"
23
+ >
24
+ <slot
25
+ name="button"
26
+ :opened="isDropdownVisible"
27
+ :toggle="toggleNotificationsDrop"
28
+ >
29
+ <div class="app-bar-button__button-wrap">
30
+ <VcIcon
31
+ :icon="icon"
32
+ size="xl"
33
+ ></VcIcon>
34
+ </div>
35
+ </slot>
36
+ </div>
37
+ </button>
38
+
39
+ <div
40
+ v-if="isDropdownVisible"
41
+ ref="floatingDrop"
42
+ v-on-click-outside="[
43
+ () => {
44
+ isDropdownVisible = false;
45
+ },
46
+ { ignore: [referenceButton] },
47
+ ]"
48
+ :style="floatingDropStyle"
49
+ :class="['app-bar-button__dropdown']"
50
+ >
51
+ <slot
52
+ name="dropdown-content"
53
+ :opened="isDropdownVisible"
54
+ :toggle="toggleNotificationsDrop"
55
+ ></slot>
56
+ </div>
57
+ </VcTooltip>
58
+ </div>
59
+ </template>
60
+
61
+ <script lang="ts" setup>
62
+ import { ref, computed } from "vue";
63
+ import { vOnClickOutside } from "@vueuse/components";
64
+ import { useFloating, shift, autoUpdate } from "@floating-ui/vue";
65
+
66
+ export interface Props {
67
+ title?: string;
68
+ icon?: string;
69
+ position: "bottom" | "bottom-end" | "bottom-start";
70
+ beforeOpen?: () => boolean;
71
+ }
72
+
73
+ export interface Emits {
74
+ (event: "toggle", state: boolean): void;
75
+ }
76
+
77
+ const props = withDefaults(defineProps<Props>(), {
78
+ position: "bottom",
79
+ });
80
+
81
+ const emit = defineEmits<Emits>();
82
+
83
+ defineSlots<{
84
+ "dropdown-content": (props: { opened: boolean; toggle: () => void }) => void;
85
+ button: void;
86
+ }>();
87
+
88
+ const isDropdownVisible = ref(false);
89
+
90
+ const referenceButton = ref<HTMLDivElement | null>(null);
91
+ const floatingDrop = ref<HTMLDivElement | null>(null);
92
+
93
+ const floater = useFloating(referenceButton, floatingDrop, {
94
+ placement: props.position,
95
+ whileElementsMounted: autoUpdate,
96
+ middleware: [shift({ mainAxis: false })],
97
+ });
98
+
99
+ const floatingDropStyle = computed(() => {
100
+ return {
101
+ top: `${floater.y.value ?? 0}px`,
102
+ left: `${floater.x.value ?? 0}px`,
103
+ };
104
+ });
105
+
106
+ function toggleNotificationsDrop() {
107
+ if (props.beforeOpen && typeof props.beforeOpen === "function" && props.beforeOpen() === false) {
108
+ return;
109
+ }
110
+ isDropdownVisible.value = !isDropdownVisible.value;
111
+
112
+ emit("toggle", isDropdownVisible.value);
113
+ }
114
+ </script>
115
+
116
+ <style lang="scss">
117
+ :root {
118
+ --app-bar-button-shadow-color: var(--additional-950);
119
+ --app-bar-button-shadow: 0 -6px 6px var(--additional-50),
120
+ 1px 1px 22px rgb(from var(--app-bar-button-shadow-color) r g b / 7%);
121
+ --app-bar-button-height: var(--app-bar-height);
122
+ --app-bar-button-bg-color: var(--additional-50);
123
+ --app-bar-button-dropdown-bg-color: var(--additional-50);
124
+ --app-bar-button-dropdown-button-width: var(--app-bar-button-width);
125
+ --app-bar-button-dropdown-button-border: var(--app-bar-button-border-color);
126
+ --app-bar-button-dropdown-button-color: var(--app-bar-button-color);
127
+ --app-bar-button-dropdown-button-background-color: var(--app-bar-button-background-color);
128
+ --app-bar-button-dropdown-button-color-hover: var(--app-bar-button-color-hover);
129
+ --app-bar-button-dropdown-button-background-color-hover: var(--app-bar-button-background-color-hover);
130
+ --app-bar-button-mobile-bg-color: var(--neutral-500);
131
+ }
132
+
133
+ .app-bar-button {
134
+ @apply tw-relative tw-flex;
135
+
136
+ &__button {
137
+ @apply tw-flex tw-text-left tw-w-full;
138
+ }
139
+
140
+ &__button-container {
141
+ @apply tw-w-full tw-relative tw-h-full tw-flex tw-items-center tw-justify-center
142
+ tw-border-l tw-border-solid
143
+ tw-border-l-[color:var(--app-bar-button-dropdown-button-border)] tw-cursor-pointer
144
+ tw-text-[color:var(--app-bar-button-dropdown-button-color)] tw-bg-[color:var(--app-bar-button-dropdown-button-background-color)]
145
+ tw-transition-colors tw-duration-200;
146
+
147
+ &:hover {
148
+ @apply tw-text-[color:var(--app-bar-button-dropdown-button-color-hover)]
149
+ tw-bg-[color:var(--app-bar-button-dropdown-button-background-color-hover)];
150
+ }
151
+
152
+ &--active {
153
+ box-shadow: var(--app-bar-button-shadow);
154
+ clip-path: inset(0px -20px 0px -20px);
155
+ background-color: var(--app-bar-button-dropdown-bg-color);
156
+ z-index: 9999;
157
+ }
158
+ }
159
+
160
+ &__button-wrap {
161
+ @apply tw-w-[var(--app-bar-button-dropdown-button-width)] tw-flex tw-justify-center;
162
+ }
163
+
164
+ &__dropdown {
165
+ @apply tw-absolute tw-top-[var(--app-bar-button-height)] tw-z-[10000] tw-min-w-[100%];
166
+ box-shadow: var(--app-bar-button-shadow);
167
+ }
168
+ }
169
+ </style>
@@ -0,0 +1 @@
1
+ export { default as AppBarButtonTemplate } from "./app-bar-button.vue";
@@ -1,49 +1,70 @@
1
1
  <template>
2
- <div
3
- v-on-click-outside="onClose"
4
- class="tw-relative tw-h-full tw-flex tw-items-center tw-justify-center tw-mx-3 tw-shrink-0"
2
+ <button
3
+ class="vc-app-switcher__button"
4
+ @click.stop="toggleAppSwitch"
5
5
  >
6
- <button
7
- class="hover:[&>img] hover:[&_div]:tw-bg-[color:var(--app-bar-button-color-hover)]"
8
- @click.stop="toggleAppSwitch"
9
- >
6
+ <div class="vc-app-switcher__icon"></div>
7
+ </button>
8
+ <Sidebar
9
+ :is-expanded="isVisible"
10
+ render="always"
11
+ position="left"
12
+ @close="onClose"
13
+ >
14
+ <template #header>
10
15
  <div
11
- class="tw-h-[22px] tw-w-[22px] [mask:url(/assets/app-select.svg)] tw-bg-[color:var(--app-bar-button-color)] tw-duration-200"
12
- />
13
- </button>
14
-
15
- <div
16
- v-if="isVisible && appsList && appsList.length"
17
- class="tw-px-4 tw-py-3.5 tw-bg-white tw-drop-shadow-[4px_4px_20px_rgba(47,86,108,0.25)] tw-absolute tw-z-[1002] tw-rounded tw-top-[var(--app-bar-height)] tw-left-0 tw-w-max tw-max-w-[200px]"
18
- >
19
- <ul class="tw-flex tw-flex-col tw-gap-3 tw-overflow-hidden">
20
- <li
21
- v-for="item in appsList"
22
- :key="item.id"
23
- class="tw-flex tw-flex-row tw-items-center tw-cursor-pointer tw-group"
24
- :class="{
25
- '[&>p]:tw-font-extrabold': locationHandler(item.relativeUrl ?? ''),
26
- }"
27
- @click="switchApp(item)"
16
+ class="vc-app-switcher__button-wrap"
17
+ :class="{
18
+ 'vc-app-switcher__button-wrap--mobile': $isMobile.value,
19
+ }"
20
+ >
21
+ <button
22
+ class="vc-app-switcher__button vc-app-switcher__button--header"
23
+ @click.stop="isVisible = false"
28
24
  >
29
- <img
30
- :src="imageUrl(item.iconUrl ?? '')"
31
- :alt="`icon_${item.id}`"
32
- class="tw-w-5 tw-h-5 tw-mr-2 tw-shrink-0"
33
- />
34
- <p class="tw-font-normal tw-text-sm tw-text-[#727C87] tw-truncate group-hover:tw-opacity-80">
35
- {{ item.title }}
36
- </p>
37
- </li>
38
- </ul>
39
- </div>
40
- </div>
25
+ <div class="vc-app-switcher__icon"></div>
26
+ </button>
27
+ <p class="vc-app-switcher__title">{{ $t("COMPONENTS.APP_SWITCHER.TITLE") }}</p>
28
+ </div>
29
+ </template>
30
+ <template #content>
31
+ <div
32
+ v-if="isVisible && appsList && appsList.length"
33
+ ref="container"
34
+ class="vc-app-switcher"
35
+ @contextmenu.prevent
36
+ >
37
+ <div class="vc-app-switcher__dropdown">
38
+ <ul class="vc-app-switcher__list">
39
+ <li
40
+ v-for="item in appsList"
41
+ :key="item.id"
42
+ class="vc-app-switcher__list-item"
43
+ :class="{
44
+ 'vc-app-switcher__list-item--active': locationHandler(item.relativeUrl ?? ''),
45
+ }"
46
+ @click="switchApp(item)"
47
+ >
48
+ <img
49
+ :src="imageUrl(item.iconUrl ?? '')"
50
+ :alt="`icon_${item.id}`"
51
+ class="vc-app-switcher__item-icon"
52
+ />
53
+ <p class="vc-app-switcher__item-title">
54
+ {{ item.title }}
55
+ </p>
56
+ </li>
57
+ </ul>
58
+ </div>
59
+ </div>
60
+ </template>
61
+ </Sidebar>
41
62
  </template>
42
63
 
43
64
  <script lang="ts" setup>
44
65
  import { inject, ref } from "vue";
45
66
  import { AppDescriptor } from "../../../../../core/api/platform";
46
- import { vOnClickOutside } from "@vueuse/components";
67
+ import { Sidebar } from "./../../../sidebar";
47
68
 
48
69
  export interface Props {
49
70
  appsList: AppDescriptor[];
@@ -89,4 +110,83 @@ const onClose = () => {
89
110
  };
90
111
  </script>
91
112
 
92
- <style lang="less" scoped></style>
113
+ <style lang="scss">
114
+ :root {
115
+ --app-switcher-button-color: var(--neutrals-400);
116
+ --app-switcher-button-color-hover: var(--neutrals-500);
117
+ --app-switcher-item-text-color: var(--additional-950);
118
+ --app-switcher-dropdown-bg-color: var(--additional-50);
119
+ --app-switcher-dropdown-shadow: 4px 4px 20px rgba(47, 86, 108, 0.25);
120
+ --app-switcher-height: var(--app-bar-height);
121
+ --app-switcher-item-bg-hover: var(--primary-50);
122
+ }
123
+
124
+ .vc-app-switcher {
125
+ @apply tw-relative tw-flex tw-mx-3 tw-shrink-0 tw-mt-4;
126
+
127
+ &__button {
128
+ @apply hover:tw-relative tw-p-0 tw-border-0 tw-bg-transparent tw-relative tw-h-full tw-flex tw-items-center tw-justify-center tw-shrink-0 tw-mx-3;
129
+
130
+ &:hover .vc-app-switcher__icon {
131
+ @apply tw-bg-[color:var(--app-switcher-button-color-hover)];
132
+ }
133
+
134
+ &--header {
135
+ @apply tw-h-auto tw-block tw-mx-0 #{!important};
136
+ }
137
+ }
138
+
139
+ &__button-wrap {
140
+ @apply tw-min-h-[--app-switcher-height] tw-px-4 tw-flex tw-items-center tw-justify-between tw-h-[var(--app-switcher-height)] tw-mx-3;
141
+
142
+ &--mobile {
143
+ @apply tw-mx-2 #{!important};
144
+ }
145
+ }
146
+
147
+ &__title {
148
+ @apply tw-text-lg tw-font-bold tw-text-[color:var(--app-switcher-item-text-color)];
149
+ }
150
+
151
+ &__icon {
152
+ @apply tw-h-[22px] tw-w-[22px] tw-bg-[color:var(--app-switcher-button-color)] tw-duration-200;
153
+ mask: url(/assets/app-select.svg) no-repeat center;
154
+ mask-size: contain;
155
+ }
156
+
157
+ &__dropdown {
158
+ @apply tw-bg-[color:var(--app-switcher-dropdown-bg-color)] tw-w-full;
159
+ }
160
+
161
+ &__list {
162
+ @apply tw-flex tw-flex-col tw-gap-3 tw-overflow-hidden;
163
+ }
164
+
165
+ &__list-item {
166
+ @apply tw-p-3 tw-text-sm tw-text-[color:var(--app-switcher-item-text-color)] tw-flex tw-flex-row tw-items-center tw-cursor-pointer tw-w-full;
167
+ transition: background-color 0.2s;
168
+
169
+ &--active {
170
+ @apply tw-font-extrabold;
171
+ }
172
+
173
+ &:hover .vc-app-switcher__item-title {
174
+ @apply tw-opacity-80;
175
+ }
176
+
177
+ &:hover {
178
+ @apply tw-bg-[color:var(--app-switcher-item-bg-hover)];
179
+ }
180
+ }
181
+
182
+ &__item-icon {
183
+ @apply tw-w-5 tw-h-5 tw-mr-2 tw-shrink-0;
184
+ }
185
+
186
+ &__item-title {
187
+ @apply tw-font-normal tw-text-sm tw-truncate;
188
+ color: var(--app-switcher-item-text-color);
189
+ transition: opacity 0.3s ease;
190
+ }
191
+ }
192
+ </style>
@@ -3,7 +3,7 @@
3
3
  <VcBreadcrumbs
4
4
  v-if="blades && blades.length > 2"
5
5
  :items="breadcrumbs"
6
- class="tw-bg-white tw-p-2 tw-shadow-[2px_2px_8px_rgba(54,84,117,0.14)] tw-rounded-[var(--blade-border-radius)]"
6
+ class="tw-bg-[--blade-navigation-bg-color] tw-p-2 [box-shadow:var(--blade-navigation-shadow)] tw-rounded-[var(--blade-navigation-border-radius)]"
7
7
  :class="[
8
8
  {
9
9
  'tw-mt-4 tw-mx-2': !$isMobile.value,
@@ -141,3 +141,12 @@ const render = () => {
141
141
  ]);
142
142
  };
143
143
  </script>
144
+
145
+ <style lang="scss">
146
+ :root {
147
+ --blade-navigation-bg-color: var(--additional-50);
148
+ --blade-navigation-shadow-color: var(--additional-950);
149
+ --blade-navigation-shadow: 2px 2px 8px rgb(from var(--blade-navigation-shadow-color) r g b / 7%);
150
+ --blade-navigation-border-radius: var(--blade-border-radius);
151
+ }
152
+ </style>
@@ -104,7 +104,10 @@ const utils = (router: Router) => {
104
104
 
105
105
  function getURLQuery() {
106
106
  if (route.query && Object.keys(route.query).length) {
107
- return { params: new URLSearchParams(route.query as Record<string, string>).toString(), obj: route.query };
107
+ return {
108
+ params: new URLSearchParams(route.query as Record<string, string>).toString(),
109
+ obj: route.query,
110
+ };
108
111
  }
109
112
 
110
113
  const [, query] = window.location.href.split("#")[1].split("?");
@@ -125,12 +128,12 @@ const useBladeNavigationSingleton = createSharedComposable(() => {
125
128
  const route = useRoute();
126
129
  const { setupPageTracking } = useAppInsights();
127
130
 
128
- const instance: BladeComponentInternalInstance = getCurrentInstance() as BladeComponentInternalInstance;
131
+ const instance = getCurrentInstance() as BladeComponentInternalInstance;
129
132
  const navigationInstance =
130
133
  (instance !== null && inject<BladeNavigationPlugin>("bladeNavigationPlugin")) || bladeNavigationInstance;
131
134
  const router = navigationInstance?.router;
132
135
 
133
- const { parseUrl, parseWorkspaceUrl, getURLQuery } = utils(router);
136
+ const { parseUrl, parseWorkspaceUrl, getURLQuery, routes } = utils(router);
134
137
 
135
138
  watch(
136
139
  () => route.path,
@@ -161,7 +164,9 @@ const useBladeNavigationSingleton = createSharedComposable(() => {
161
164
  }
162
165
 
163
166
  function updateActiveWorkspace(wsRouteComponent: BladeVNode) {
164
- wsRouteComponent.props.navigation.idx = 0;
167
+ if (wsRouteComponent.props?.navigation) {
168
+ wsRouteComponent.props.navigation.idx = 0;
169
+ }
165
170
  navigationInstance.blades.value[0] = wsRouteComponent;
166
171
  activeWorkspace.value = wsRouteComponent;
167
172
  closeBlade(1);
@@ -202,8 +207,10 @@ const useBladeNavigationSingleton = createSharedComposable(() => {
202
207
  const wsBladeUrl = workspace?.type.url;
203
208
  const lastBladeUrl = lastBlade?.type.url;
204
209
  const param = lastBlade?.props?.param;
205
- if (lastBlade && wsBladeUrl) {
206
- return "/" + parseUrl(wsBladeUrl)?.workspace + lastBladeUrl + (param ? "/" + param : "");
210
+ const parsedWorkspaceUrl = parseUrl(wsBladeUrl || "")?.workspace;
211
+
212
+ if (lastBlade && wsBladeUrl && parsedWorkspaceUrl) {
213
+ return "/" + parsedWorkspaceUrl + lastBladeUrl + (param ? "/" + param : "");
207
214
  } else {
208
215
  return wsBladeUrl;
209
216
  }
@@ -234,8 +241,8 @@ const useBladeNavigationSingleton = createSharedComposable(() => {
234
241
  try {
235
242
  const children = navigationInstance.blades.value.slice(index).reverse();
236
243
  let isPrevented = false;
237
- for (let index = 0; index < children.length; index++) {
238
- const element = children[index];
244
+ for (let i = 0; i < children.length; i++) {
245
+ const element = children[i];
239
246
 
240
247
  if (element.props?.navigation?.onBeforeClose) {
241
248
  const result = await element.props.navigation.onBeforeClose();
@@ -250,7 +257,7 @@ const useBladeNavigationSingleton = createSharedComposable(() => {
250
257
  }
251
258
 
252
259
  if (!isPrevented) {
253
- if (navigationInstance.blades.value[index - 1]?.props?.navigation?.isVisible === false) {
260
+ if (index > 0 && navigationInstance.blades.value[index - 1]?.props?.navigation?.isVisible === false) {
254
261
  navigationInstance.blades.value[index - 1].props.navigation.isVisible = true;
255
262
  }
256
263
  navigationInstance.blades.value.splice(index);
@@ -276,11 +283,14 @@ export function useBladeNavigation(): IUseBladeNavigation {
276
283
 
277
284
  const { hasAccess } = usePermissions();
278
285
 
279
- const instance: BladeComponentInternalInstance = getCurrentInstance() as BladeComponentInternalInstance;
286
+ const instance = getCurrentInstance() as BladeComponentInternalInstance;
280
287
 
281
288
  const { router, route, navigationInstance, closeBlade, setupPageTracking } = useBladeNavigationSingleton();
282
289
  const { parseUrl, getURLQuery, routes: routerRoutes } = utils(router);
283
- const mainRoute = routerRoutes.find((r) => r.meta?.root)!;
290
+ const mainRoute = routerRoutes.find((r) => r.meta?.root);
291
+ if (!mainRoute) {
292
+ throw new Error("Main route not found");
293
+ }
284
294
 
285
295
  async function openWorkspace<Blade extends Component>(
286
296
  { blade, param, options }: IBladeEvent<Blade>,
@@ -312,11 +322,12 @@ export function useBladeNavigation(): IUseBladeNavigation {
312
322
 
313
323
  if (!isPrevented && createdComponent.type?.url) {
314
324
  if (hasAccess(blade.permissions)) {
315
- // If the blade is the same as the one we want to open, do nothing. It prevents the loose of the instance state
316
- if (navigationInstance.blades.value.length > 0) {
317
- if (navigationInstance.blades.value[0].type.url === createdComponent.type.url) {
318
- return;
319
- }
325
+ if (
326
+ hasAccess(blade.permissions) &&
327
+ navigationInstance.blades.value.length > 0 &&
328
+ navigationInstance.blades.value[0].type.url === createdComponent.type.url
329
+ ) {
330
+ return;
320
331
  }
321
332
  navigationInstance.blades.value = [createdComponent];
322
333
  // Find the route with the matching URL and update the components.default property with the new component
@@ -324,15 +335,21 @@ export function useBladeNavigation(): IUseBladeNavigation {
324
335
  if (wsroute && wsroute.components) {
325
336
  wsroute.components.default = createdComponent;
326
337
  }
327
- return await router.push({ name: wsroute?.name, params: { ...params, ...route.params }, query, replace });
328
- } else
338
+ return await router.push({
339
+ name: wsroute?.name,
340
+ params: { ...params, ...route.params },
341
+ query,
342
+ replace,
343
+ });
344
+ } else {
329
345
  notification.error(i18n.global.t("PERMISSION_MESSAGES.ACCESS_RESTRICTED"), {
330
346
  timeout: 3000,
331
347
  });
348
+ }
332
349
  }
333
350
  } catch (e) {
334
351
  console.error(e);
335
- throw new Error(`Opening workspace '${blade.type.name}' is prevented`);
352
+ throw new Error(`Opening workspace '${blade?.type?.name || "Unknown"}' is prevented`);
336
353
  }
337
354
  }
338
355
 
@@ -367,7 +384,14 @@ export function useBladeNavigation(): IUseBladeNavigation {
367
384
 
368
385
  const currentBladeIdx = instanceComponent.props?.navigation?.idx ?? 0;
369
386
 
370
- const bladeNode = createBladeNode<Blade>({ blade, currentBladeIdx, options, param, onClose, onOpen });
387
+ const bladeNode = createBladeNode<Blade>({
388
+ blade,
389
+ currentBladeIdx,
390
+ options,
391
+ param,
392
+ onClose,
393
+ onOpen,
394
+ });
371
395
 
372
396
  if (!isPrevented) {
373
397
  if (hasAccess(blade.permissions)) {
@@ -386,8 +410,7 @@ export function useBladeNavigation(): IUseBladeNavigation {
386
410
  }
387
411
 
388
412
  function findInstanceComponentIndex(instanceComponent: BladeVNode) {
389
- return navigationInstance.blades.value /* @ts-expect-error - findLastIndex is not parsed correctly by ts */
390
- .findLastIndex((x) => _.isEqual(x.type, instanceComponent.type));
413
+ return _.findLastIndex(navigationInstance.blades.value, (x) => _.isEqual(x.type, instanceComponent.type));
391
414
  }
392
415
 
393
416
  function createBladeNode<Blade extends Component>(args: {
@@ -419,7 +442,7 @@ export function useBladeNavigation(): IUseBladeNavigation {
419
442
  console.debug(`vc-app#onParentCall({ method: ${args.method} }) called.`);
420
443
 
421
444
  if (args.method && parentExposedMethods && typeof parentExposedMethods[args.method] === "function") {
422
- const method = parentExposedMethods[args.method] as (args: unknown) => Promise<unknown>;
445
+ const method = parentExposedMethods[args.method];
423
446
  const result = await method(args.args);
424
447
 
425
448
  if (typeof args.callback === "function") {
@@ -436,7 +459,7 @@ export function useBladeNavigation(): IUseBladeNavigation {
436
459
  if (!instance) {
437
460
  warn("resolveComponentByName can only be used in setup().");
438
461
 
439
- return null as any; // Return type inferred as any due to the early return
462
+ return null as unknown as BladeInstanceConstructor;
440
463
  }
441
464
 
442
465
  if (!name) {
@@ -475,7 +498,7 @@ export function useBladeNavigation(): IUseBladeNavigation {
475
498
  const params = Object.fromEntries(Object.entries(to.params).filter(([key]) => key !== "pathMatch"));
476
499
 
477
500
  // Get the raw path of the main route.
478
- const parentRawPath = routerRoutes.find((route) => route.name === mainRoute.name)?.path;
501
+ const parentRawPath = routerRoutes.find((route) => route.name === mainRoute?.name)?.path;
479
502
 
480
503
  // Determine the parent path based on the parameters.
481
504
  const parentPath =
@@ -568,11 +591,12 @@ export function useBladeNavigation(): IUseBladeNavigation {
568
591
  }
569
592
 
570
593
  function setNavigationQuery(query: Record<string, string | number>) {
571
- if (instance.vnode.props.navigation.idx === 0) {
594
+ const typeName = instance.vnode.type.name?.toLowerCase();
595
+ if (typeName && instance.vnode.props.navigation.idx === 0) {
572
596
  // add blade name to query keys
573
597
  const namedQuery = _.mapKeys(
574
598
  _.mapValues(query, (value) => value?.toString()),
575
- (value, key) => instance.vnode.type.name?.toLowerCase() + "_" + key,
599
+ (value, key) => typeName + "_" + key,
576
600
  );
577
601
  const cleanQuery = _.omitBy(namedQuery, _.isNil);
578
602
 
@@ -585,12 +609,13 @@ export function useBladeNavigation(): IUseBladeNavigation {
585
609
  }
586
610
 
587
611
  function getNavigationQuery() {
588
- if (instance.vnode.props.navigation.idx === 0) {
612
+ const typeName = instance.vnode.type.name?.toLowerCase();
613
+ if (typeName && instance.vnode.props.navigation.idx === 0) {
589
614
  const queryKeys = Array.from(Object.keys(route.query));
590
- const bladeQueryKeys = queryKeys.filter((key) => key.startsWith(instance.vnode.type.name?.toLowerCase() ?? ""));
615
+ const bladeQueryKeys = queryKeys.filter((key) => key.startsWith(typeName));
591
616
 
592
617
  const namedQuery = _.mapKeys(_.pick(route.query, bladeQueryKeys), (value, key) =>
593
- key.replace(instance.vnode.type.name?.toLowerCase() + "_", ""),
618
+ key.replace(typeName + "_", ""),
594
619
  ) as Record<string, string | number>;
595
620
 
596
621
  const obj: typeof namedQuery = {};
@@ -118,7 +118,7 @@
118
118
  <VcHint
119
119
  v-for="(err, i) in form.errors"
120
120
  :key="i"
121
- class="tw-mt-3 !tw-text-[#f14e4e]"
121
+ class="tw-mt-3 !tw-text-[color:var(--change-password-error-color)]"
122
122
  >
123
123
  <!-- TODO: stylizing-->
124
124
  {{
@@ -219,3 +219,9 @@ function validate() {
219
219
  });
220
220
  }
221
221
  </script>
222
+
223
+ <style lang="scss">
224
+ :root {
225
+ --change-password-error-color: var(--base-error-color, var(--danger-500));
226
+ }
227
+ </style>
@@ -39,6 +39,6 @@ defineEmits<Emits>();
39
39
 
40
40
  <style lang="scss">
41
41
  :root {
42
- --confirm-button-color: #6b7987;
42
+ --confirm-button-color: var(--secondary-700);
43
43
  }
44
44
  </style>
@@ -42,6 +42,6 @@ defineEmits<Emits>();
42
42
 
43
43
  <style lang="scss">
44
44
  :root {
45
- --confirm-button-color: #6b7987;
45
+ --confirm-button-color: var(--secondary-700);
46
46
  }
47
47
  </style>
@@ -8,3 +8,6 @@ export * from "./language-selector";
8
8
  export * from "./user-dropdown-button";
9
9
  export * from "./notification-dropdown";
10
10
  export * from "./notification-template";
11
+ export * from "./app-bar-button";
12
+ export * from "./sidebar";
13
+ export * from "./theme-selector";