sprintify-ui 0.0.19 → 0.0.21

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 (54) hide show
  1. package/dist/sprintify-ui.es.js +6877 -4264
  2. package/dist/types/src/components/BaseActionItem.vue.d.ts +121 -0
  3. package/dist/types/src/components/BaseAlert.vue.d.ts +3 -3
  4. package/dist/types/src/components/BaseAppDialogs.vue.d.ts +1 -1
  5. package/dist/types/src/components/BaseBoolean.vue.d.ts +2 -2
  6. package/dist/types/src/components/BaseCounter.vue.d.ts +3 -3
  7. package/dist/types/src/components/BaseDialog.vue.d.ts +4 -4
  8. package/dist/types/src/components/BaseInput.vue.d.ts +1 -1
  9. package/dist/types/src/components/BaseLayoutNotificationDropdown.vue.d.ts +24 -0
  10. package/dist/types/src/components/BaseLayoutNotificationItem.vue.d.ts +14 -0
  11. package/dist/types/src/components/BaseLayoutSidebar.vue.d.ts +114 -0
  12. package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +182 -0
  13. package/dist/types/src/components/BaseLayoutStacked.vue.d.ts +76 -0
  14. package/dist/types/src/components/BaseLayoutStackedConfigurable.vue.d.ts +182 -0
  15. package/dist/types/src/components/BaseMenu.vue.d.ts +17 -15
  16. package/dist/types/src/components/BaseMenuItem.vue.d.ts +5 -5
  17. package/dist/types/src/components/BaseNavbar.vue.d.ts +20 -1
  18. package/dist/types/src/components/BaseNavbarItem.vue.d.ts +17 -71
  19. package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +11 -2
  20. package/dist/types/src/components/BaseNavbarSideItem.vue.d.ts +26 -0
  21. package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +50 -0
  22. package/dist/types/src/components/BaseSwitch.vue.d.ts +3 -3
  23. package/dist/types/src/components/BaseSystemAlert.vue.d.ts +8 -8
  24. package/dist/types/src/components/BaseTableColumn.vue.d.ts +1 -1
  25. package/dist/types/src/components/index.d.ts +6 -1
  26. package/dist/types/src/index.d.ts +12 -0
  27. package/dist/types/src/types/Notification.d.ts +8 -0
  28. package/dist/types/src/types/types.d.ts +9 -0
  29. package/package.json +6 -3
  30. package/src/components/BaseActionItem.vue +68 -0
  31. package/src/components/{HasMany.stories.js → BaseHasMany.stories.js} +0 -0
  32. package/src/components/BaseLayoutNotificationDropdown.vue +101 -0
  33. package/src/components/BaseLayoutNotificationItem.vue +58 -0
  34. package/src/components/BaseLayoutSidebar.vue +199 -0
  35. package/src/components/BaseLayoutSidebarConfigurable.stories.js +129 -0
  36. package/src/components/BaseLayoutSidebarConfigurable.vue +118 -0
  37. package/src/components/BaseLayoutStacked.vue +52 -0
  38. package/src/components/BaseLayoutStackedConfigurable.stories.js +110 -0
  39. package/src/components/BaseLayoutStackedConfigurable.vue +129 -0
  40. package/src/components/BaseMediaItem.vue +7 -7
  41. package/src/components/BaseMediaLibrary.vue +3 -3
  42. package/src/components/BaseMediaPreview.vue +1 -1
  43. package/src/components/BaseMenu.vue +12 -4
  44. package/src/components/BaseNavbar.stories.js +18 -14
  45. package/src/components/BaseNavbar.vue +19 -3
  46. package/src/components/BaseNavbarItem.vue +17 -43
  47. package/src/components/BaseNavbarItemContent.vue +36 -16
  48. package/src/components/BaseNavbarSideItem.vue +42 -0
  49. package/src/components/BaseNavbarSideItemContent.vue +77 -0
  50. package/src/components/index.ts +11 -0
  51. package/src/lang/en.json +3 -0
  52. package/src/lang/fr.json +3 -0
  53. package/src/types/Notification.ts +10 -0
  54. package/src/types/types.ts +11 -0
@@ -144,8 +144,8 @@ declare const _default: import("vue").DefineComponent<{
144
144
  default: () => {};
145
145
  };
146
146
  }>>, {
147
- label: string;
148
147
  meta: Record<string, any> | unknown[];
148
+ label: string;
149
149
  width: number;
150
150
  toggle: boolean;
151
151
  field: string;
@@ -1,3 +1,4 @@
1
+ import BaseActionItem from './BaseActionItem.vue';
1
2
  import BaseAlert from './BaseAlert.vue';
2
3
  import BaseApp from './BaseApp.vue';
3
4
  import BaseAppDialogs from './BaseAppDialogs.vue';
@@ -59,4 +60,8 @@ import BaseTable from './BaseTable.vue';
59
60
  import BaseTableColumn from './BaseTableColumn.vue';
60
61
  import BaseTextarea from './BaseTextarea.vue';
61
62
  import BaseTextareaAutoresize from './BaseTextareaAutoresize.vue';
62
- export { BaseAlert, BaseApp, BaseAppDialogs, BaseAppNotifications, BaseAutocomplete, BaseAutocompleteFetch, BaseAvatar, BaseBadge, BaseBelongsTo, BaseBoolean, BaseBreadcrumbs, BaseButton, BaseCard, BaseCardRow, BaseCharacterCounter, BaseClipboard, BaseContainer, BaseCounter, BaseDataIterator, BaseDataTable, BaseDatePicker, BaseDateSelect, BaseDescriptionList, BaseDescriptionListItem, BaseDialog, BaseFilePicker, BaseFileUploader, BaseHasMany, BaseIcon, BaseInput, BaseInputLabel, BaseLoadingCover, BaseMediaItem, BaseMediaLibrary, BaseMediaPreview, BaseMenu, BaseMenuItem, BaseModalCenter, BaseModalSide, BaseNavbar, BaseNavbarItem, BaseNavbarItemContent, BasePagination, BasePanel, BasePassword, BaseProcessRing, BaseReadMore, BaseSelect, BaseSideNavigation, BaseSideNavigationItem, BaseSkeleton, BaseSwitch, BaseSystemAlert, BaseTabs, BaseTabItem, BaseTagAutocomplete, BaseTagAutocompleteFetch, BaseTable, BaseTableColumn, BaseTextarea, BaseTextareaAutoresize, };
63
+ import BaseLayoutStacked from './BaseLayoutStacked.vue';
64
+ import BaseLayoutStackedConfigurable from './BaseLayoutStackedConfigurable.vue';
65
+ import BaseLayoutSidebar from './BaseLayoutSidebar.vue';
66
+ import BaseLayoutSidebarConfigurable from './BaseLayoutSidebarConfigurable.vue';
67
+ export { BaseActionItem, BaseAlert, BaseApp, BaseAppDialogs, BaseAppNotifications, BaseAutocomplete, BaseAutocompleteFetch, BaseAvatar, BaseBadge, BaseBelongsTo, BaseBoolean, BaseBreadcrumbs, BaseButton, BaseCard, BaseCardRow, BaseCharacterCounter, BaseClipboard, BaseContainer, BaseCounter, BaseDataIterator, BaseDataTable, BaseDatePicker, BaseDateSelect, BaseDescriptionList, BaseDescriptionListItem, BaseDialog, BaseFilePicker, BaseFileUploader, BaseHasMany, BaseIcon, BaseInput, BaseInputLabel, BaseLoadingCover, BaseMediaItem, BaseMediaLibrary, BaseMediaPreview, BaseMenu, BaseMenuItem, BaseModalCenter, BaseModalSide, BaseNavbar, BaseNavbarItem, BaseNavbarItemContent, BasePagination, BasePanel, BasePassword, BaseProcessRing, BaseReadMore, BaseSelect, BaseSideNavigation, BaseSideNavigationItem, BaseSkeleton, BaseSwitch, BaseSystemAlert, BaseTabs, BaseTabItem, BaseTagAutocomplete, BaseTagAutocompleteFetch, BaseTable, BaseTableColumn, BaseTextarea, BaseTextareaAutoresize, BaseLayoutStacked, BaseLayoutStackedConfigurable, BaseLayoutSidebar, BaseLayoutSidebarConfigurable, };
@@ -32,6 +32,7 @@ declare const messages: {
32
32
  next_month: string;
33
33
  none: string;
34
34
  nothing_found: string;
35
+ notifications_empty: string;
35
36
  or: string;
36
37
  pagination_detail: string;
37
38
  previous: string;
@@ -40,6 +41,7 @@ declare const messages: {
40
41
  remove: string;
41
42
  remove_file: string;
42
43
  remove_file_description: string;
44
+ see_all_notifications: string;
43
45
  select_an_item: string;
44
46
  select_an_option: string;
45
47
  success: string;
@@ -56,6 +58,7 @@ declare const messages: {
56
58
  up_to_x: string;
57
59
  upload_failed: string;
58
60
  whoops: string;
61
+ x_ago: string;
59
62
  x_rows_selected: string;
60
63
  year: string;
61
64
  yes_delete: string;
@@ -90,6 +93,7 @@ declare const messages: {
90
93
  next_month: string;
91
94
  none: string;
92
95
  nothing_found: string;
96
+ notifications_empty: string;
93
97
  or: string;
94
98
  pagination_detail: string;
95
99
  previous: string;
@@ -98,6 +102,7 @@ declare const messages: {
98
102
  remove: string;
99
103
  remove_file: string;
100
104
  remove_file_description: string;
105
+ see_all_notifications: string;
101
106
  select_an_item: string;
102
107
  select_an_option: string;
103
108
  success: string;
@@ -114,6 +119,7 @@ declare const messages: {
114
119
  up_to_x: string;
115
120
  upload_failed: string;
116
121
  whoops: string;
122
+ x_ago: string;
117
123
  x_rows_selected: string;
118
124
  year: string;
119
125
  yes_delete: string;
@@ -159,6 +165,7 @@ declare const config: {
159
165
  next_month: string;
160
166
  none: string;
161
167
  nothing_found: string;
168
+ notifications_empty: string;
162
169
  or: string;
163
170
  pagination_detail: string;
164
171
  previous: string;
@@ -167,6 +174,7 @@ declare const config: {
167
174
  remove: string;
168
175
  remove_file: string;
169
176
  remove_file_description: string;
177
+ see_all_notifications: string;
170
178
  select_an_item: string;
171
179
  select_an_option: string;
172
180
  success: string;
@@ -183,6 +191,7 @@ declare const config: {
183
191
  up_to_x: string;
184
192
  upload_failed: string;
185
193
  whoops: string;
194
+ x_ago: string;
186
195
  x_rows_selected: string;
187
196
  year: string;
188
197
  yes_delete: string;
@@ -217,6 +226,7 @@ declare const config: {
217
226
  next_month: string;
218
227
  none: string;
219
228
  nothing_found: string;
229
+ notifications_empty: string;
220
230
  or: string;
221
231
  pagination_detail: string;
222
232
  previous: string;
@@ -225,6 +235,7 @@ declare const config: {
225
235
  remove: string;
226
236
  remove_file: string;
227
237
  remove_file_description: string;
238
+ see_all_notifications: string;
228
239
  select_an_item: string;
229
240
  select_an_option: string;
230
241
  success: string;
@@ -241,6 +252,7 @@ declare const config: {
241
252
  up_to_x: string;
242
253
  upload_failed: string;
243
254
  whoops: string;
255
+ x_ago: string;
244
256
  x_rows_selected: string;
245
257
  year: string;
246
258
  yes_delete: string;
@@ -0,0 +1,8 @@
1
+ import { RouteLocationRaw } from 'vue-router';
2
+ interface Notification {
3
+ id: string;
4
+ text: string;
5
+ to: RouteLocationRaw;
6
+ created_at?: string;
7
+ }
8
+ export { Notification };
@@ -1,5 +1,6 @@
1
1
  import { RouteLocationRaw } from 'vue-router';
2
2
  import { UploadedFile } from './UploadedFile';
3
+ import { Notification as AppNotification } from './Notification';
3
4
  export interface Breadcrumb {
4
5
  icon?: string;
5
6
  to: RouteLocationRaw;
@@ -144,3 +145,11 @@ export interface Notification {
144
145
  color: 'info' | 'success' | 'danger' | 'warning';
145
146
  duration: number;
146
147
  }
148
+ /**
149
+ * App Notification
150
+ */
151
+ export interface NotificationsConfig {
152
+ items: AppNotification[];
153
+ footerLabel?: string;
154
+ footerTo?: RouteLocationRaw;
155
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprintify-ui",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "scripts": {
5
5
  "build": "rimraf dist && vue-tsc && vite build",
6
6
  "build-fast": "rimraf dist && vite build",
@@ -17,15 +17,16 @@
17
17
  "@tailwindcss/typography": "^0.5.8",
18
18
  "@vueuse/core": "^9.0.0",
19
19
  "axios": "^0.26.1",
20
+ "humanize-duration": "^3.0.0",
20
21
  "lodash": "^4.17.21",
21
22
  "luxon": "^3.0.0",
23
+ "pikaday": "^1.8.2",
22
24
  "pinia": "^2.0.0",
23
25
  "qs": "^6.0.0",
24
26
  "tailwindcss": "^3.0.0",
25
27
  "vue": "^3.0.0",
26
28
  "vue-i18n": "^9.0.0",
27
- "vue-router": "^4.0.0",
28
- "pikaday": "^1.8.2"
29
+ "vue-router": "^4.0.0"
29
30
  },
30
31
  "dependencies": {
31
32
  "@headlessui/vue": "^1.7.4"
@@ -44,6 +45,7 @@
44
45
  "@tailwindcss/forms": "^0.5.3",
45
46
  "@tailwindcss/line-clamp": "^0.4.2",
46
47
  "@tailwindcss/typography": "^0.5.8",
48
+ "@types/humanize-duration": "^3.27.1",
47
49
  "@types/luxon": "^3.1.0",
48
50
  "@types/object-hash": "^2.2.1",
49
51
  "@types/pikaday": "^1.7.6",
@@ -63,6 +65,7 @@
63
65
  "eslint-plugin-storybook": "^0.6.7",
64
66
  "eslint-plugin-vue": "^9.7.0",
65
67
  "eslint-plugin-vue-scoped-css": "^2.2.0",
68
+ "humanize-duration": "^3.27.3",
66
69
  "lodash": "^4.17.21",
67
70
  "luxon": "^3.1.0",
68
71
  "object-hash": "^3.0.0",
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <RouterLink
3
+ v-if="item.to"
4
+ v-slot="{ isActive, href: slotHref, navigate }"
5
+ custom
6
+ :to="item.to"
7
+ >
8
+ <a
9
+ :active="isActive"
10
+ :href="slotHref"
11
+ :class="itemClass"
12
+ :aria-current="isActive ? 'page' : undefined"
13
+ @click.prevent="onClick(navigate)"
14
+ >
15
+ <slot :active="isActive"> </slot>
16
+ </a>
17
+ </RouterLink>
18
+ <button
19
+ v-else-if="item.action"
20
+ type="button"
21
+ :class="itemClass"
22
+ @click="onClick(item.action)"
23
+ >
24
+ <slot :active="false"> </slot>
25
+ </button>
26
+ <a
27
+ v-else-if="item.href"
28
+ :href="item.href"
29
+ :class="itemClass"
30
+ @click="onClick()"
31
+ >
32
+ <slot :active="false"> </slot>
33
+ </a>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { PropType } from 'vue';
38
+ import { ActionItem } from '@/types/types';
39
+
40
+ defineProps({
41
+ item: {
42
+ required: true,
43
+ type: Object as PropType<ActionItem>,
44
+ },
45
+ dark: {
46
+ default: false,
47
+ type: Boolean,
48
+ },
49
+ itemClass: {
50
+ default: '',
51
+ type: [String, Array, Object],
52
+ },
53
+ });
54
+
55
+ const closeMenu = inject('closeMenu') as () => void;
56
+
57
+ const emit = defineEmits(['click']);
58
+
59
+ type asyncFunc = () => Promise<void>;
60
+
61
+ async function onClick(func: asyncFunc | null = null) {
62
+ if (func) {
63
+ await func();
64
+ }
65
+ emit('click');
66
+ closeMenu();
67
+ }
68
+ </script>
@@ -0,0 +1,101 @@
1
+ <template>
2
+ <BaseMenu
3
+ class="inline-block"
4
+ :position="mobile ? 'custom' : 'bottom-left'"
5
+ :menu-class="['sm:w-[320px] w-[280px]', mobile ? 'right-4' : '']"
6
+ >
7
+ <template #button="{ open }">
8
+ <div
9
+ class="relative flex items-center rounded-full p-1.5"
10
+ :class="[open ? '' : '']"
11
+ >
12
+ <BaseIcon
13
+ icon="heroicons:bell"
14
+ class="h-6 w-6"
15
+ :class="[dark ? 'text-slate-300' : 'text-slate-600']"
16
+ ></BaseIcon>
17
+ <BaseCounter
18
+ v-if="notificationsConfig.items.length"
19
+ class="absolute top-0 right-0"
20
+ :count="notificationsConfig.items.length"
21
+ ></BaseCounter>
22
+ </div>
23
+ </template>
24
+
25
+ <template #items>
26
+ <template
27
+ v-for="notification in notificationsConfig.items"
28
+ :key="notification.id + 'link'"
29
+ >
30
+ <BaseLayoutNotificationItem
31
+ :notification="notification"
32
+ ></BaseLayoutNotificationItem>
33
+ </template>
34
+ <div
35
+ v-if="notificationsConfig.items.length == 0"
36
+ class="flex items-center justify-center p-6"
37
+ >
38
+ <div class="">
39
+ <BaseIcon
40
+ icon="heroicons:inbox-stack"
41
+ class="mx-auto mb-2 h-8 w-8 text-slate-400"
42
+ ></BaseIcon>
43
+ <p class="text-center text-sm text-slate-700">
44
+ {{ $t('sui.notifications_empty') }}
45
+ </p>
46
+ </div>
47
+ </div>
48
+
49
+ <div
50
+ v-if="notificationsConfig.footerTo"
51
+ class="mt-1 border-t border-slate-200 pt-1"
52
+ >
53
+ <RouterLink
54
+ v-slot="{ href, navigate }"
55
+ custom
56
+ :to="notificationsConfig.footerTo"
57
+ >
58
+ <MenuItem as="a" :href="href" @click="navigate">
59
+ <div
60
+ class="hover block px-3 py-2 text-center text-sm font-medium text-primary-600 hover:bg-slate-100"
61
+ >
62
+ {{
63
+ notificationsConfig.footerLabel
64
+ ? notificationsConfig.footerLabel
65
+ : $t('sui.see_all_notifications')
66
+ }}
67
+ </div>
68
+ </MenuItem>
69
+ </RouterLink>
70
+ </div>
71
+ </template>
72
+ </BaseMenu>
73
+ </template>
74
+
75
+ <script lang="ts" setup>
76
+ import { PropType } from 'vue';
77
+ import { BaseIcon } from '.';
78
+ import BaseCounter from './BaseCounter.vue';
79
+ import BaseLayoutNotificationItem from './BaseLayoutNotificationItem.vue';
80
+ import BaseMenu from './BaseMenu.vue';
81
+ import { useBreakpoints } from '@/composables/breakpoints';
82
+ import { NotificationsConfig } from '../types/types';
83
+ import { MenuItem } from '@headlessui/vue';
84
+
85
+ defineProps({
86
+ notificationsConfig: {
87
+ required: true,
88
+ type: Object as PropType<NotificationsConfig>,
89
+ },
90
+ dark: {
91
+ default: false,
92
+ type: Boolean,
93
+ },
94
+ });
95
+
96
+ const breakpoints = useBreakpoints();
97
+
98
+ const mobile = computed((): boolean => {
99
+ return breakpoints.smaller('sm').value;
100
+ });
101
+ </script>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <router-link v-slot="{ href, navigate }" custom :to="notification.to">
3
+ <MenuItem v-slot="{ active }" as="a" :href="href" @click="navigate">
4
+ <div class="px-3 py-2" :class="[active ? 'bg-slate-100' : '']">
5
+ <div
6
+ class="text-sm leading-tight text-slate-800"
7
+ v-html="notification.text"
8
+ ></div>
9
+ <p v-if="createdAt" class="mt-1 text-xs text-slate-400">
10
+ {{ createdAt }}
11
+ </p>
12
+ </div>
13
+ </MenuItem>
14
+ </router-link>
15
+ </template>
16
+
17
+ <script lang="ts" setup>
18
+ import { Notification } from '@/types/Notification';
19
+ import { MenuItem } from '@headlessui/vue';
20
+ import { DateTime } from 'luxon';
21
+ import { PropType } from 'vue';
22
+ import humanizeDuration from 'humanize-duration';
23
+
24
+ const i18n = useI18n();
25
+
26
+ const props = defineProps({
27
+ notification: {
28
+ required: true,
29
+ type: Object as PropType<Notification>,
30
+ },
31
+ });
32
+
33
+ const now = ref(DateTime.now());
34
+
35
+ const intervalId = setInterval(() => {
36
+ now.value.plus({ second: 1 });
37
+ }, 1000);
38
+
39
+ const createdAt = computed(() => {
40
+ if (props.notification.created_at) {
41
+ const duration = DateTime.fromISO(props.notification.created_at).diff(
42
+ now.value
43
+ ).milliseconds;
44
+
45
+ const durationHuman = humanizeDuration(duration, {
46
+ language: i18n.locale.value,
47
+ round: true,
48
+ largest: 1,
49
+ });
50
+
51
+ return i18n.t('sui.x_ago', { duration: durationHuman });
52
+ }
53
+ });
54
+
55
+ onBeforeUnmount(() => {
56
+ clearInterval(intervalId);
57
+ });
58
+ </script>
@@ -0,0 +1,199 @@
1
+ <template>
2
+ <div class="min-h-full">
3
+ <TransitionRoot as="template" :show="showMobileMenu">
4
+ <Dialog
5
+ as="div"
6
+ class="relative z-40 xl:hidden"
7
+ @close="showMobileMenu = false"
8
+ >
9
+ <TransitionChild
10
+ as="template"
11
+ enter="transition-opacity ease-linear duration-300"
12
+ enter-from="opacity-0"
13
+ enter-to="opacity-100"
14
+ leave="transition-opacity ease-linear duration-300"
15
+ leave-from="opacity-100"
16
+ leave-to="opacity-0"
17
+ >
18
+ <div class="fixed inset-0 bg-slate-600 bg-opacity-75" />
19
+ </TransitionChild>
20
+
21
+ <div class="fixed inset-0 z-40 flex">
22
+ <TransitionChild
23
+ as="template"
24
+ enter="transition ease-in-out duration-300 transform"
25
+ enter-from="-translate-x-full"
26
+ enter-to="translate-x-0"
27
+ leave="transition ease-in-out duration-300 transform"
28
+ leave-from="translate-x-0"
29
+ leave-to="-translate-x-full"
30
+ >
31
+ <DialogPanel
32
+ class="relative flex w-full max-w-xs flex-1 flex-col pt-5 pb-4"
33
+ :class="[dark ? 'bg-slate-800' : 'bg-white']"
34
+ >
35
+ <TransitionChild
36
+ as="template"
37
+ enter="ease-in-out duration-300"
38
+ enter-from="opacity-0"
39
+ enter-to="opacity-100"
40
+ leave="ease-in-out duration-300"
41
+ leave-from="opacity-100"
42
+ leave-to="opacity-0"
43
+ >
44
+ <div class="absolute top-0 right-0 -mr-12 pt-2">
45
+ <button
46
+ type="button"
47
+ class="ml-1 flex h-10 w-10 items-center justify-center rounded-full"
48
+ @click="showMobileMenu = false"
49
+ >
50
+ <span class="sr-only">Close sidebar</span>
51
+ <BaseIcon
52
+ icon="heroicons:x-mark"
53
+ class="h-6 w-6 text-white"
54
+ aria-hidden="true"
55
+ />
56
+ </button>
57
+ </div>
58
+ </TransitionChild>
59
+ <div class="flex flex-shrink-0 items-center px-4">
60
+ <img class="block h-8 w-auto" :src="logoUrl" :alt="appName" />
61
+ </div>
62
+ <div class="mt-5 h-0 flex-1 overflow-y-auto">
63
+ <nav>
64
+ <slot name="menu" />
65
+ </nav>
66
+ </div>
67
+ </DialogPanel>
68
+ </TransitionChild>
69
+ <div class="w-14 flex-shrink-0" aria-hidden="true">
70
+ <!-- Dummy element to force sidebar to shrink to fit close icon -->
71
+ </div>
72
+ </div>
73
+ </Dialog>
74
+ </TransitionRoot>
75
+
76
+ <div class="flex min-h-full flex-col xl:pl-64">
77
+ <div class="sticky top-0 left-0 z-10 shrink-0 shadow">
78
+ <BaseSystemAlert
79
+ v-for="systemAlert in systemAlerts"
80
+ :key="systemAlert.id"
81
+ :color="systemAlert.color"
82
+ :to="systemAlert.to"
83
+ :action="systemAlert.action"
84
+ :closable="systemAlert.closable"
85
+ @close="systemAlertStore.remove(systemAlert)"
86
+ >
87
+ {{ systemAlert.message }}
88
+ </BaseSystemAlert>
89
+
90
+ <div class="flex h-16 bg-white">
91
+ <button
92
+ type="button"
93
+ class="border-r border-slate-200 px-4 text-slate-500 xl:hidden"
94
+ @click="showMobileMenu = true"
95
+ >
96
+ <span class="sr-only">Open sidebar</span>
97
+ <BaseIcon
98
+ icon="heroicons:bars-3-bottom-left"
99
+ class="h-6 w-6"
100
+ aria-hidden="true"
101
+ />
102
+ </button>
103
+
104
+ <!-- Navbar -->
105
+ <div class="flex flex-1">
106
+ <slot name="navbar" />
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <!-- Position: relative to contain Loading Covers -->
112
+ <main class="relative min-h-full flex-1">
113
+ <slot />
114
+ </main>
115
+ </div>
116
+
117
+ <!-- Static sidebar for desktop -->
118
+ <div class="z-10 hidden xl:fixed xl:inset-y-0 xl:flex xl:w-64 xl:flex-col">
119
+ <!-- Sidebar component, swap this element with another sidebar if you like -->
120
+ <div
121
+ class="flex min-h-0 flex-1 flex-col"
122
+ :class="[dark ? 'bg-slate-800' : 'bg-white shadow']"
123
+ >
124
+ <div
125
+ class="flex h-16 flex-shrink-0 items-center px-4"
126
+ :class="[dark ? 'bg-slate-900' : 'bg-white']"
127
+ >
128
+ <img class="block h-8 w-auto" :src="logoUrl" :alt="appName" />
129
+ </div>
130
+ <div class="flex flex-1">
131
+ <nav class="flex-1">
132
+ <slot name="menu" />
133
+ </nav>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </template>
139
+
140
+ <script setup lang="ts">
141
+ import { ref } from 'vue';
142
+ import {
143
+ Dialog,
144
+ DialogPanel,
145
+ TransitionChild,
146
+ TransitionRoot,
147
+ } from '@headlessui/vue';
148
+
149
+ import { useSystemAlertStore } from '../stores/systemAlerts';
150
+ import { BaseIcon } from '.';
151
+ import BaseSystemAlert from './BaseSystemAlert.vue';
152
+
153
+ const props = defineProps({
154
+ appName: {
155
+ default: '',
156
+ type: String,
157
+ },
158
+ logoUrl: {
159
+ default: 'https://sprintify.witify.io/img/logo/logo-side-dark.svg',
160
+ type: String,
161
+ },
162
+ dark: {
163
+ default: false,
164
+ type: Boolean,
165
+ },
166
+ });
167
+
168
+ /**
169
+ * System Alert And Navigation size
170
+ */
171
+
172
+ const systemAlertStore = useSystemAlertStore();
173
+
174
+ const systemAlerts = computed(() => {
175
+ return systemAlertStore.systemAlerts;
176
+ });
177
+
178
+ /**
179
+ * Show/Hide sidebar
180
+ */
181
+
182
+ const showMobileMenu = ref(false);
183
+
184
+ function toggleMenu() {
185
+ showMobileMenu.value = !showMobileMenu.value;
186
+ }
187
+
188
+ function openMenu() {
189
+ showMobileMenu.value = true;
190
+ }
191
+
192
+ function closeMenu() {
193
+ showMobileMenu.value = false;
194
+ }
195
+
196
+ provide('toggleMenu', toggleMenu);
197
+ provide('openMenu', openMenu);
198
+ provide('closeMenu', closeMenu);
199
+ </script>