@shwfed/nuxt 0.1.75 → 0.1.77

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.
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
- import { useHead, useNuxtApp, useRoute, useRuntimeConfig } from "#app";
3
- import { computed, reactive, watch } from "vue";
2
+ import { useHead, useNuxtApp, useRuntimeConfig } from "#app";
3
+ import { reactive } from "vue";
4
4
  import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "./ui/command";
5
5
  import { TooltipProvider } from "./ui/tooltip";
6
6
  import { Toaster } from "vue-sonner";
@@ -12,25 +12,28 @@ import { setGlobalDslContext } from "../plugins/cel/context";
12
12
  import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "./ui/sidebar";
13
13
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collapsible";
14
14
  import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "./ui/dropdown-menu";
15
- import { z } from "zod";
16
15
  import Logo from "./logo.vue";
17
16
  import { useFavorite } from "../composables/useFavorite";
18
17
  import { useNavigationTabs } from "../composables/useNavigationTabs";
19
- import { commandActionSchema, executeCommandAction } from "../utils/command";
20
- import { createPaletteItemValue, normalizeCommandsForPalette, splitNavigationForPalette } from "../utils/command-palette";
21
- import { resolveNavigationTitle } from "../utils/navigation-title";
22
- import { isRouteActive } from "../utils/route";
23
- import { applyRootNavigationFallback } from "../utils/sidebar-fallback";
24
- const { $dsl, $logout, $md, $api, $toast } = useNuxtApp();
25
- const { t } = useI18n();
26
- const route = useRoute();
27
- const { tabs, active, tabList, activateTab, closeTab } = useNavigationTabs();
28
18
  const {
29
19
  public: {
30
- shwfed: config
20
+ shwfed
31
21
  }
32
22
  } = useRuntimeConfig();
23
+ const { $dsl } = useNuxtApp();
24
+ const { t } = useI18n();
25
+ const props = defineProps({
26
+ dsl: { type: null, required: false },
27
+ sidebar: { type: Array, required: false },
28
+ commands: { type: Array, required: false }
29
+ });
30
+ const { active, tabs, nameOf, close } = useNavigationTabs(() => props.sidebar ?? []);
31
+ const ui = reactive({
32
+ isCommandPaletteOpen: false,
33
+ isProfileDropdownOpen: false
34
+ });
33
35
  useHead({
36
+ title: () => active.value && nameOf(active.value),
34
37
  bodyAttrs: {
35
38
  style: {
36
39
  "--primary": "#2DA8BC",
@@ -38,221 +41,23 @@ useHead({
38
41
  }
39
42
  }
40
43
  });
41
- const props = defineProps({
42
- dsl: { type: null, required: false }
43
- });
44
- const ui = reactive({
45
- isCommandPaletteOpen: false,
46
- isProfileDropdownOpen: false
47
- });
48
44
  const { start: startProfileCloseTimer, stop: stopProfileCloseTimer } = useTimeoutFn(() => {
49
45
  ui.isProfileDropdownOpen = false;
50
46
  }, 150, { immediate: false });
51
47
  const { meta_k } = useMagicKeys();
52
48
  whenever(() => meta_k?.value, () => ui.isCommandPaletteOpen = !ui.isCommandPaletteOpen);
53
49
  setGlobalDslContext(await props.dsl?.pipe(Effect.scoped).pipe(Effect.runPromise) ?? {});
54
- const navigationItem = z.object({
55
- id: z.union([z.string(), z.number()]),
56
- title: z.string(),
57
- icon: z.string().optional(),
58
- route: z.string(),
59
- keywords: z.array(z.string()).optional()
60
- });
61
- const navigationGroup = z.object({
62
- id: z.union([z.string(), z.number()]),
63
- title: z.string(),
64
- icon: z.string().optional(),
65
- children: z.array(navigationItem)
66
- });
67
- const navigationEntry = z.union([navigationGroup, navigationItem]);
68
- const navigationItems = computed(() => {
69
- try {
70
- const result = $dsl.evaluate`${config.sidebar.menus}`();
71
- return z.array(navigationEntry).parse(result);
72
- } catch {
73
- return [];
74
- }
75
- });
76
50
  const {
77
51
  isFavorited: isNavigationFavorited,
78
52
  canBeFavorited: canBeNavigationFavorited,
79
53
  toggle: toggleNavigationFavorite,
80
54
  withFavorites: navigations
81
- } = useFavorite("navigation", navigationItems);
82
- const isNavigationItemActive = (itemRoute) => isRouteActive(route.path, itemRoute);
83
- const getTabLabel = (tab) => {
84
- return resolveNavigationTitle(navigationItems.value, tab);
55
+ } = useFavorite("navigation", () => props.sidebar ?? []);
56
+ const logout = () => {
57
+ if (shwfed.api.logout)
58
+ window.location.href = shwfed.api.logout;
59
+ return Effect.void;
85
60
  };
86
- const activeTabLabel = computed(() => {
87
- if (active.value === void 0)
88
- return void 0;
89
- return getTabLabel(active.value);
90
- });
91
- useHead(() => ({
92
- title: activeTabLabel.value
93
- }));
94
- const profileName = computed(() => {
95
- if (config.profile.name === void 0)
96
- return t("profile");
97
- try {
98
- const content = $md.inline`${config.profile.name}`();
99
- const plainText = content.replace(/<[^>]*>/g, "").trim();
100
- if (plainText.length === 0)
101
- return t("profile");
102
- return plainText;
103
- } catch {
104
- return t("profile");
105
- }
106
- });
107
- const commandItem = z.object({
108
- id: z.union([z.string(), z.number()]),
109
- title: z.string(),
110
- icon: z.string().optional(),
111
- hidden: z.string().optional(),
112
- disabled: z.string().optional(),
113
- effect: z.string().optional(),
114
- keywords: z.array(z.string()).optional()
115
- });
116
- const commandGroup = z.object({
117
- id: z.union([z.string(), z.number()]),
118
- title: z.string(),
119
- icon: z.string().optional(),
120
- children: z.array(commandItem)
121
- });
122
- const evaluateDslBoolean = (expression) => {
123
- if (expression === void 0)
124
- return false;
125
- try {
126
- return $dsl.evaluate`${expression}`() === true;
127
- } catch {
128
- return false;
129
- }
130
- };
131
- const normalizeEffectExpression = (expression) => {
132
- return expression.replace(/([{,]\s*)([a-z_][\w-]*)(\s*:)/gi, "$1'$2'$3");
133
- };
134
- const profileCommands = computed(() => {
135
- if (config.commands === void 0)
136
- return [];
137
- try {
138
- const result = $dsl.evaluate`${config.commands}`();
139
- const entries = z.array(z.union([commandGroup, commandItem])).parse(result);
140
- const normalized = [];
141
- for (const entry of entries) {
142
- if ("children" in entry) {
143
- const children = entry.children.filter((child) => !evaluateDslBoolean(child.hidden)).map((child) => ({
144
- id: child.id,
145
- title: child.title,
146
- icon: child.icon,
147
- disabled: evaluateDslBoolean(child.disabled),
148
- effect: child.effect,
149
- keywords: child.keywords
150
- }));
151
- if (children.length > 0) {
152
- normalized.push({
153
- id: entry.id,
154
- title: entry.title,
155
- icon: entry.icon,
156
- children
157
- });
158
- }
159
- continue;
160
- }
161
- if (evaluateDslBoolean(entry.hidden))
162
- continue;
163
- normalized.push({
164
- id: entry.id,
165
- title: entry.title,
166
- icon: entry.icon,
167
- disabled: evaluateDslBoolean(entry.disabled),
168
- effect: entry.effect,
169
- keywords: entry.keywords
170
- });
171
- }
172
- return normalized;
173
- } catch {
174
- return [];
175
- }
176
- });
177
- const isBodyInit = (value) => {
178
- return typeof value === "string" || value instanceof Blob || value instanceof ArrayBuffer || ArrayBuffer.isView(value) || value instanceof FormData || value instanceof URLSearchParams || value instanceof ReadableStream;
179
- };
180
- const toApiRequestBody = (value) => {
181
- if (value === void 0 || value === null)
182
- return value;
183
- if (isBodyInit(value))
184
- return value;
185
- if (typeof value === "object")
186
- return value;
187
- return void 0;
188
- };
189
- const executeCommandEffect = async (effect) => {
190
- if (effect === void 0)
191
- return false;
192
- let action;
193
- try {
194
- let result;
195
- try {
196
- result = $dsl.evaluate`${effect}`();
197
- } catch {
198
- result = $dsl.evaluate`${normalizeEffectExpression(effect)}`();
199
- }
200
- action = commandActionSchema.parse(result);
201
- await executeCommandAction(action, {
202
- logout: $logout,
203
- request: async (requestAction) => $api(requestAction.url, {
204
- method: requestAction.method,
205
- body: toApiRequestBody(requestAction.body),
206
- query: requestAction.query,
207
- headers: requestAction.headers
208
- })
209
- });
210
- return true;
211
- } catch (error) {
212
- if (action?.type === "request") {
213
- const message = error instanceof Error && error.message.length > 0 ? error.message : "Request failed";
214
- $toast.error(message);
215
- }
216
- return false;
217
- }
218
- };
219
- const executeProfileCommand = async (effect) => {
220
- if (effect === void 0 || await executeCommandEffect(effect))
221
- ui.isProfileDropdownOpen = false;
222
- };
223
- const normalizedNavigationForPalette = computed(() => {
224
- try {
225
- return z.array(navigationEntry).parse(navigations.value);
226
- } catch {
227
- return navigationItems.value;
228
- }
229
- });
230
- const paletteNavigation = computed(() => splitNavigationForPalette(normalizedNavigationForPalette.value));
231
- const favoriteRoutesForPalette = computed(() => paletteNavigation.value.favoriteRoutes);
232
- const navigationForPalette = computed(() => paletteNavigation.value.navigationEntries);
233
- const commandForPalette = computed(() => normalizeCommandsForPalette(profileCommands.value));
234
- const executePaletteItem = async (item) => {
235
- if (item.type === "route") {
236
- activateTab(item.route);
237
- ui.isCommandPaletteOpen = false;
238
- return;
239
- }
240
- if (item.effect !== void 0 && !await executeCommandEffect(item.effect))
241
- return;
242
- ui.isCommandPaletteOpen = false;
243
- };
244
- watch(
245
- () => route.path,
246
- (path) => {
247
- applyRootNavigationFallback({
248
- path,
249
- items: navigationItems.value,
250
- tabs: tabs.value,
251
- activateTab
252
- });
253
- },
254
- { immediate: true }
255
- );
256
61
  </script>
257
62
 
258
63
  <template>
@@ -276,102 +81,68 @@ watch(
276
81
  </section>
277
82
  </CommandEmpty>
278
83
 
279
- <CommandGroup
280
- v-if="favoriteRoutesForPalette.length > 0"
281
- :heading="t('favorites')"
282
- >
283
- <CommandItem
284
- v-for="menu in favoriteRoutesForPalette"
285
- :key="`fav:${menu.id}:${menu.route}`"
286
- :value="createPaletteItemValue('fav', `${menu.id}:${menu.route}`)"
287
- @select="executePaletteItem({ type: 'route', route: menu.route })"
288
- >
289
- <span>{{ menu.title }}</span>
290
- <span
291
- v-if="menu.keywords.length > 0"
292
- class="sr-only"
293
- >
294
- {{ menu.keywords.join(" ") }}
295
- </span>
296
- </CommandItem>
297
- </CommandGroup>
298
-
299
84
  <template
300
- v-for="navigation in navigationForPalette"
301
- :key="navigation.id"
85
+ v-for="command in props.commands"
86
+ :key="command.id"
302
87
  >
303
88
  <CommandGroup
304
- v-if="'children' in navigation"
305
- :heading="navigation.title"
89
+ v-if="'children' in command"
90
+ :heading="command.title"
306
91
  >
307
92
  <CommandItem
308
- v-for="menu in navigation.children"
309
- :key="menu.id"
310
- :value="createPaletteItemValue('nav', menu.id, navigation.id)"
311
- @select="executePaletteItem({ type: 'route', route: menu.route })"
93
+ v-for="child in command.children.filter((child2) => !child2.hidden)"
94
+ :key="child.id"
95
+ :value="child.id"
96
+ :disabled="child.disabled"
97
+ @select="child.effect?.pipe(Effect.tap(() => {
98
+ ui.isCommandPaletteOpen = false;
99
+ })).pipe(Effect.runPromise)"
312
100
  >
313
- <span>{{ menu.title }}</span>
314
- <span
315
- v-if="menu.keywords.length > 0"
316
- class="sr-only"
317
- >
318
- {{ menu.keywords.join(" ") }}
101
+ <span>{{ child.title }}</span>
102
+ <span class="sr-only">
103
+ {{ child.keywords?.join(" ") }}
319
104
  </span>
320
105
  </CommandItem>
321
106
  </CommandGroup>
322
107
  <CommandGroup v-else>
323
108
  <CommandItem
324
- :value="createPaletteItemValue('nav', navigation.id)"
325
- @select="executePaletteItem({ type: 'route', route: navigation.route })"
109
+ :value="command.id"
110
+ :disabled="command.disabled"
111
+ @select="command.effect?.pipe(Effect.tap(() => {
112
+ ui.isCommandPaletteOpen = false;
113
+ })).pipe(Effect.runPromise)"
326
114
  >
327
- <span>{{ navigation.title }}</span>
328
- <span
329
- v-if="navigation.keywords.length > 0"
330
- class="sr-only"
331
- >
332
- {{ navigation.keywords.join(" ") }}
115
+ <span>{{ command.title }}</span>
116
+ <span class="sr-only">
117
+ {{ command.keywords?.join(" ") }}
333
118
  </span>
334
119
  </CommandItem>
335
120
  </CommandGroup>
336
121
  </template>
337
122
 
338
123
  <template
339
- v-for="command in commandForPalette"
340
- :key="command.id"
124
+ v-for="navigation in props.sidebar"
125
+ :key="navigation.id"
341
126
  >
342
127
  <CommandGroup
343
- v-if="'children' in command"
344
- :heading="command.title"
128
+ v-if="'children' in navigation"
129
+ :heading="navigation.title"
345
130
  >
346
131
  <CommandItem
347
- v-for="child in command.children"
348
- :key="child.id"
349
- :value="createPaletteItemValue('cmd', child.id, command.id)"
350
- :disabled="child.disabled"
351
- @select="executePaletteItem({ type: 'command', effect: child.effect })"
132
+ v-for="menu in navigation.children"
133
+ :key="menu.id"
134
+ :value="menu.id"
135
+ @select="$router.replace(menu.route)"
352
136
  >
353
- <span>{{ child.title }}</span>
354
- <span
355
- v-if="child.keywords.length > 0"
356
- class="sr-only"
357
- >
358
- {{ child.keywords.join(" ") }}
359
- </span>
137
+ <span>{{ menu.title }}</span>
360
138
  </CommandItem>
361
139
  </CommandGroup>
362
140
  <CommandGroup v-else>
363
141
  <CommandItem
364
- :value="createPaletteItemValue('cmd', command.id)"
365
- :disabled="command.disabled"
366
- @select="executePaletteItem({ type: 'command', effect: command.effect })"
142
+ :value="navigation.id"
143
+ @select="$router.replace(navigation.route)"
367
144
  >
368
- <span>{{ command.title }}</span>
369
- <span
370
- v-if="command.keywords.length > 0"
371
- class="sr-only"
372
- >
373
- {{ command.keywords.join(" ") }}
374
- </span>
145
+ <span>{{ navigation.title }}</span>
375
146
  </CommandItem>
376
147
  </CommandGroup>
377
148
  </template>
@@ -400,7 +171,7 @@ watch(
400
171
  @click.prevent="stopProfileCloseTimer();
401
172
  ui.isProfileDropdownOpen = true"
402
173
  >
403
- {{ profileName }}
174
+ <slot name="profile" />
404
175
  </button>
405
176
  </DropdownMenuTrigger>
406
177
  <DropdownMenuContent
@@ -411,33 +182,37 @@ watch(
411
182
  startProfileCloseTimer()"
412
183
  >
413
184
  <template
414
- v-for="command in profileCommands"
185
+ v-for="command in props.commands"
415
186
  :key="command.id"
416
187
  >
417
- <template v-if="'children' in command">
188
+ <template v-if="'children' in command && command.children.some((child2) => !child2.hidden)">
418
189
  <DropdownMenuLabel>
419
190
  {{ command.title }}
420
191
  </DropdownMenuLabel>
421
192
  <DropdownMenuGroup>
422
- <DropdownMenuItem
193
+ <template
423
194
  v-for="child in command.children"
424
195
  :key="child.id"
425
- :disabled="child.disabled"
426
- @select="executeProfileCommand(child.effect)"
427
196
  >
428
- <Icon
429
- v-if="child.icon"
430
- :icon="child.icon"
431
- />
432
- {{ child.title }}
433
- </DropdownMenuItem>
197
+ <DropdownMenuItem
198
+ v-if="!child.hidden"
199
+ :disabled="child.disabled"
200
+ @select="child.effect?.pipe(Effect.runPromise)"
201
+ >
202
+ <Icon
203
+ v-if="child.icon"
204
+ :icon="child.icon"
205
+ />
206
+ {{ child.title }}
207
+ </DropdownMenuItem>
208
+ </template>
434
209
  </DropdownMenuGroup>
435
210
  <DropdownMenuSeparator />
436
211
  </template>
437
212
  <DropdownMenuItem
438
- v-else
213
+ v-else-if="!('children' in command) && !command.hidden"
439
214
  :disabled="command.disabled"
440
- @select="executeProfileCommand(command.effect)"
215
+ @select="command.effect?.pipe(Effect.runPromise)"
441
216
  >
442
217
  <Icon
443
218
  v-if="command.icon"
@@ -446,7 +221,15 @@ watch(
446
221
  {{ command.title }}
447
222
  </DropdownMenuItem>
448
223
  </template>
449
- <DropdownMenuSeparator v-if="profileCommands.length > 0" />
224
+ <DropdownMenuItem
225
+ @select="logout"
226
+ >
227
+ <Icon
228
+ icon="fluent:sign-out-20-regular"
229
+ />
230
+ {{ t("logout") }}
231
+ </DropdownMenuItem>
232
+ <DropdownMenuSeparator v-if="props.commands?.some((command2) => 'children' in command2 ? command2.children.some((child2) => !child2.hidden) : !command2.hidden)" />
450
233
  <DropdownMenuItem disabled>
451
234
  <Icon icon="fluent:history-20-regular" />
452
235
  {{ t("build") }}
@@ -503,11 +286,11 @@ watch(
503
286
  <SidebarMenuButton
504
287
  v-if="'route' in menu"
505
288
  as-child
506
- :is-active="isNavigationItemActive(menu.route)"
289
+ :is-active="active === menu.route"
507
290
  >
508
291
  <button
509
292
  type="button"
510
- @click="activateTab(menu.route)"
293
+ @click="active = menu.route"
511
294
  >
512
295
  <Icon
513
296
  v-if="menu.icon"
@@ -539,11 +322,11 @@ watch(
539
322
  <SidebarMenuItem>
540
323
  <SidebarMenuButton
541
324
  as-child
542
- :is-active="isNavigationItemActive(group.route)"
325
+ :is-active="active === group.route"
543
326
  >
544
327
  <button
545
328
  type="button"
546
- @click="activateTab(group.route)"
329
+ @click="active = group.route"
547
330
  >
548
331
  <Icon
549
332
  v-if="group.icon"
@@ -564,7 +347,7 @@ watch(
564
347
  <main class="flex-1 flex flex-col bg-zinc-100 overflow-hidden">
565
348
  <nav class="bg-white p-1 border-b border-zinc-100 h-10 flex items-center justify-start gap-1 overflow-x-auto min-w-0">
566
349
  <div
567
- v-for="tab in tabList"
350
+ v-for="tab in tabs"
568
351
  :key="tab"
569
352
  :class="[
570
353
  'h-8 max-w-60 border rounded px-2 text-sm flex items-center gap-2 shrink-0 min-w-0 transition-colors',
@@ -574,14 +357,15 @@ watch(
574
357
  <button
575
358
  type="button"
576
359
  class="truncate cursor-pointer"
577
- @click="activateTab(tab)"
360
+ @click="active = tab"
578
361
  >
579
- {{ getTabLabel(tab) }}
362
+ {{ nameOf(tab) }}
580
363
  </button>
581
364
  <button
365
+ v-if="tabs.size !== 1"
582
366
  type="button"
583
367
  class="cursor-pointer text-zinc-500 hover:text-zinc-900"
584
- @click.stop="closeTab(tab)"
368
+ @click.stop="close(tab)"
585
369
  >
586
370
  <Icon icon="fluent:dismiss-20-regular" />
587
371
  </button>
@@ -1,5 +1,21 @@
1
1
  import type { Scope } from 'effect';
2
2
  import { Effect } from 'effect';
3
+ import { type Sidebar as SidebarType } from '../composables/useNavigationTabs.js';
4
+ type ProfileCommandInputItem = Readonly<{
5
+ id: string | number;
6
+ title: string;
7
+ icon?: string;
8
+ hidden?: boolean;
9
+ disabled?: boolean;
10
+ effect?: Effect.Effect<void>;
11
+ keywords?: Array<string>;
12
+ }>;
13
+ type ProfileCommandInputGroup = Readonly<{
14
+ id: string | number;
15
+ title: string;
16
+ icon?: string;
17
+ children: Array<ProfileCommandInputItem>;
18
+ }>;
3
19
  type __VLS_Props = {
4
20
  /**
5
21
  * 应用的全局 DSL(CEL)执行上下文。传入一个 Effect,在应用启动时运行一次;
@@ -38,12 +54,26 @@ type __VLS_Props = {
38
54
  * // CEL 中可访问 user.name、permissions.canEdit 等;失败时在 effect 内兜底,不抛错
39
55
  */
40
56
  dsl?: Effect.Effect<Record<string, unknown>, never, Scope.Scope>;
57
+ /**
58
+ * Sidebar config.
59
+ *
60
+ * `menus` is structured navigation data.
61
+ */
62
+ sidebar?: SidebarType;
63
+ /**
64
+ * Profile command config.
65
+ *
66
+ * Structured command entries for profile menu and command palette.
67
+ */
68
+ commands?: Array<ProfileCommandInputItem | ProfileCommandInputGroup>;
41
69
  };
42
- declare var __VLS_122: {}, __VLS_346: {};
70
+ declare var __VLS_108: {}, __VLS_124: {}, __VLS_347: {};
43
71
  type __VLS_Slots = {} & {
44
- menu?: (props: typeof __VLS_122) => any;
72
+ menu?: (props: typeof __VLS_108) => any;
73
+ } & {
74
+ profile?: (props: typeof __VLS_124) => any;
45
75
  } & {
46
- default?: (props: typeof __VLS_346) => any;
76
+ default?: (props: typeof __VLS_347) => any;
47
77
  };
48
78
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
49
79
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -7,7 +7,7 @@ type Group<K extends string | number> = Readonly<{
7
7
  children: Array<Item<K>>;
8
8
  }>;
9
9
  type Favoritable<K extends string | number> = Item<K> | Group<K>;
10
- export declare function useFavorite<K extends string | number, T extends Favoritable<K>>(key: string, items: MaybeRefOrGetter<Array<T>>): {
10
+ export declare function useFavorite<K extends string | number, T extends Favoritable<K>>(key: string, items: MaybeRefOrGetter<ReadonlyArray<T>>): {
11
11
  favorite: <I extends Item<K>>(item: I, of: K) => void;
12
12
  unfavorite: <I extends Item<K>>(item: I, of?: K) => void;
13
13
  toggle: <I extends Item<K>>(item: I, of: K) => void;
@@ -1,7 +1,21 @@
1
- export declare function useNavigationTabs(): {
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ type SidebarMenuItem = Readonly<{
3
+ id: string | number;
4
+ title: string;
5
+ icon?: string;
6
+ route: string;
7
+ }>;
8
+ type SidebarMenuGroup = Readonly<{
9
+ id: string | number;
10
+ title: string;
11
+ icon?: string;
12
+ children: Array<SidebarMenuItem>;
13
+ }>;
14
+ export type Sidebar = ReadonlyArray<SidebarMenuItem | SidebarMenuGroup>;
15
+ export declare function useNavigationTabs(navigations: MaybeRefOrGetter<Sidebar>): {
2
16
  tabs: import("@vueuse/shared").RemovableRef<Set<string>>;
3
- tabList: import("vue").ComputedRef<string[]>;
4
- active: import("@vueuse/shared").RemovableRef<string | undefined>;
5
- activateTab: (tab: string) => void;
6
- closeTab: (tab: string) => void;
17
+ nameOf: (path: string) => string | undefined;
18
+ close: (raw: string) => void;
19
+ active: import("vue").WritableComputedRef<string | undefined, string>;
7
20
  };
21
+ export {};