@shwfed/nuxt 0.1.64 → 0.1.66
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.
- package/dist/module.d.mts +57 -20
- package/dist/module.json +1 -1
- package/dist/module.mjs +10 -1
- package/dist/runtime/components/app.d.vue.ts +3 -78
- package/dist/runtime/components/app.vue +411 -558
- package/dist/runtime/components/app.vue.d.ts +3 -78
- package/dist/runtime/components/ui/sidebar/SidebarGroup.vue +1 -1
- package/dist/runtime/components/ui/sidebar/SidebarGroupLabel.vue +1 -1
- package/dist/runtime/components/ui/sidebar/SidebarMenu.vue +1 -1
- package/dist/runtime/composables/useFavorite.d.ts +23 -0
- package/dist/runtime/composables/useFavorite.js +68 -0
- package/dist/runtime/composables/useNavigationTabs.d.ts +7 -0
- package/dist/runtime/composables/useNavigationTabs.js +65 -0
- package/dist/runtime/plugins/api/index.js +15 -23
- package/dist/runtime/utils/command-palette.d.ts +71 -0
- package/dist/runtime/utils/command-palette.js +72 -0
- package/dist/runtime/utils/command.d.ts +15 -0
- package/dist/runtime/utils/command.js +28 -0
- package/dist/runtime/utils/route.d.ts +2 -0
- package/dist/runtime/utils/route.js +14 -0
- package/dist/runtime/utils/sidebar-fallback.d.ts +16 -0
- package/dist/runtime/utils/sidebar-fallback.js +32 -0
- package/package.json +1 -1
- package/dist/runtime/server/tsconfig.json +0 -3
|
@@ -1,81 +1,6 @@
|
|
|
1
1
|
import type { Scope } from 'effect';
|
|
2
2
|
import { Effect } from 'effect';
|
|
3
|
-
type Item = Readonly<{
|
|
4
|
-
id: string;
|
|
5
|
-
/**
|
|
6
|
-
* 命令的标题
|
|
7
|
-
*
|
|
8
|
-
* 调用者处理 i18n
|
|
9
|
-
*
|
|
10
|
-
* @type string
|
|
11
|
-
*/
|
|
12
|
-
title: string;
|
|
13
|
-
/**
|
|
14
|
-
* 命令的图标
|
|
15
|
-
*
|
|
16
|
-
* @type string
|
|
17
|
-
*/
|
|
18
|
-
icon?: string;
|
|
19
|
-
/**
|
|
20
|
-
* 命令是否禁用
|
|
21
|
-
*
|
|
22
|
-
* @type DSL
|
|
23
|
-
*/
|
|
24
|
-
disabled?: boolean | string;
|
|
25
|
-
/**
|
|
26
|
-
* 命令是否隐藏
|
|
27
|
-
*
|
|
28
|
-
* @type DSL | boolean
|
|
29
|
-
*/
|
|
30
|
-
hidden?: boolean | string;
|
|
31
|
-
/**
|
|
32
|
-
* 命令的关键词
|
|
33
|
-
*
|
|
34
|
-
* @type string[]
|
|
35
|
-
*/
|
|
36
|
-
keywords?: ReadonlyArray<string>;
|
|
37
|
-
}>;
|
|
38
|
-
type CommandPosition = 'profile' | 'command-palette';
|
|
39
|
-
interface Command extends Item {
|
|
40
|
-
positions: ReadonlyArray<CommandPosition>;
|
|
41
|
-
effect: Effect.Effect<void, never, Scope.Scope>;
|
|
42
|
-
}
|
|
43
|
-
interface Navigation extends Item {
|
|
44
|
-
/**
|
|
45
|
-
* 导航项的跳转目标
|
|
46
|
-
*
|
|
47
|
-
* @type string
|
|
48
|
-
*/
|
|
49
|
-
target: string;
|
|
50
|
-
/**
|
|
51
|
-
* 导航项是否为外部链接
|
|
52
|
-
*
|
|
53
|
-
* @type DSL
|
|
54
|
-
*/
|
|
55
|
-
external: string;
|
|
56
|
-
}
|
|
57
3
|
type __VLS_Props = {
|
|
58
|
-
/**
|
|
59
|
-
* 所有导航项
|
|
60
|
-
*/
|
|
61
|
-
navigation?: ReadonlyArray<Navigation | Readonly<{
|
|
62
|
-
id: string;
|
|
63
|
-
title: string;
|
|
64
|
-
icon?: string;
|
|
65
|
-
children: ReadonlyArray<Navigation>;
|
|
66
|
-
}>>;
|
|
67
|
-
/**
|
|
68
|
-
* 应用内命令列表,用于命令面板(Cmd+K)和/或顶栏个人资料下拉菜单。
|
|
69
|
-
* 每项为「单个命令」或「分组」:单个命令含 positions、effect;分组含 id、title、可选 icon、children(Command 数组)。
|
|
70
|
-
* positions 控制展示位置:'command-palette' 出现在命令面板,'profile' 出现在个人资料菜单;可同时包含两者。
|
|
71
|
-
* 用户选择某命令时执行其 effect(带 Scope)。可选 disabled、hidden(CEL 表达式)、keywords 与导航等用法一致。
|
|
72
|
-
*/
|
|
73
|
-
commands?: ReadonlyArray<Command | Readonly<{
|
|
74
|
-
id: string;
|
|
75
|
-
title: string;
|
|
76
|
-
icon?: string;
|
|
77
|
-
children: ReadonlyArray<Command>;
|
|
78
|
-
}>>;
|
|
79
4
|
/**
|
|
80
5
|
* 应用的全局 DSL(CEL)执行上下文。传入一个 Effect,在应用启动时运行一次;
|
|
81
6
|
* 其解析结果(一个 record)会被永久设为全局上下文,供后续所有 CEL 求值(如 `$dsl.evaluate`)使用。
|
|
@@ -114,11 +39,11 @@ type __VLS_Props = {
|
|
|
114
39
|
*/
|
|
115
40
|
dsl?: Effect.Effect<Record<string, unknown>, never, Scope.Scope>;
|
|
116
41
|
};
|
|
117
|
-
declare var
|
|
42
|
+
declare var __VLS_122: {}, __VLS_346: {};
|
|
118
43
|
type __VLS_Slots = {} & {
|
|
119
|
-
menu?: (props: typeof
|
|
44
|
+
menu?: (props: typeof __VLS_122) => any;
|
|
120
45
|
} & {
|
|
121
|
-
default?: (props: typeof
|
|
46
|
+
default?: (props: typeof __VLS_346) => any;
|
|
122
47
|
};
|
|
123
48
|
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>;
|
|
124
49
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -15,7 +15,7 @@ const props = defineProps({
|
|
|
15
15
|
:as="as"
|
|
16
16
|
:as-child="asChild"
|
|
17
17
|
:class="cn(
|
|
18
|
-
'text-zinc-700/70 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear [&>svg]:size-4 [&>svg]:shrink-0',
|
|
18
|
+
'text-zinc-700/70 flex gap-x-2 h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear [&>svg]:size-4 [&>svg]:shrink-0',
|
|
19
19
|
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
|
|
20
20
|
props.class
|
|
21
21
|
)"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
type Item<K extends string | number> = Readonly<{
|
|
3
|
+
id: K;
|
|
4
|
+
}>;
|
|
5
|
+
type Group<K extends string | number> = Readonly<{
|
|
6
|
+
id: K;
|
|
7
|
+
children: Array<Item<K>>;
|
|
8
|
+
}>;
|
|
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>>): {
|
|
11
|
+
favorite: <I extends Item<K>>(item: I, of: K) => void;
|
|
12
|
+
unfavorite: <I extends Item<K>>(item: I, of?: K) => void;
|
|
13
|
+
toggle: <I extends Item<K>>(item: I, of: K) => void;
|
|
14
|
+
isFavorited: (item: Item<K>, of: K) => boolean;
|
|
15
|
+
canBeFavorited: (_: Item<K>, of: K) => boolean;
|
|
16
|
+
withFavorites: import("vue").ComputedRef<(T | {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
icon: string;
|
|
20
|
+
children: T[];
|
|
21
|
+
})[]>;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useLocalStorage } from "@vueuse/core";
|
|
2
|
+
import { computed, toValue } from "vue";
|
|
3
|
+
import { useI18n } from "vue-i18n";
|
|
4
|
+
const isItem = (item) => !("children" in item);
|
|
5
|
+
const isGroup = (item) => "children" in item;
|
|
6
|
+
export function useFavorite(key, items) {
|
|
7
|
+
const { t } = useI18n({
|
|
8
|
+
useScope: "global",
|
|
9
|
+
messages: {
|
|
10
|
+
zh: { favorites: "\u6536\u85CF" },
|
|
11
|
+
ja: { favorites: "\u304A\u6C17\u306B\u5165\u308A" },
|
|
12
|
+
en: { favorites: "Favorites" }
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const memo = useLocalStorage(`favorite-${key}`, /* @__PURE__ */ new Set(), {
|
|
16
|
+
writeDefaults: false
|
|
17
|
+
});
|
|
18
|
+
const keyed = (item, of) => [item.id, of].filter((v) => v !== void 0).join("::");
|
|
19
|
+
const unkeyed = (key2) => {
|
|
20
|
+
const [id, of] = key2.split("::");
|
|
21
|
+
return [id, of];
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
favorite: (item, of) => {
|
|
25
|
+
memo.value = new Set(memo.value).add(keyed(item, of));
|
|
26
|
+
},
|
|
27
|
+
unfavorite: (item, of) => {
|
|
28
|
+
const next = new Set(memo.value);
|
|
29
|
+
next.delete(keyed(item, of));
|
|
30
|
+
memo.value = next;
|
|
31
|
+
},
|
|
32
|
+
toggle: (item, of) => {
|
|
33
|
+
const next = new Set(memo.value);
|
|
34
|
+
const key2 = keyed(item, of);
|
|
35
|
+
if (next.has(key2)) {
|
|
36
|
+
next.delete(key2);
|
|
37
|
+
} else {
|
|
38
|
+
next.add(key2);
|
|
39
|
+
}
|
|
40
|
+
memo.value = next;
|
|
41
|
+
},
|
|
42
|
+
isFavorited: (item, of) => {
|
|
43
|
+
return memo.value.has(keyed(item, of));
|
|
44
|
+
},
|
|
45
|
+
canBeFavorited: (_, of) => {
|
|
46
|
+
return of !== "$favorites";
|
|
47
|
+
},
|
|
48
|
+
withFavorites: computed(() => {
|
|
49
|
+
return [
|
|
50
|
+
{
|
|
51
|
+
id: "$favorites",
|
|
52
|
+
title: t("favorites"),
|
|
53
|
+
icon: "fluent:star-20-regular",
|
|
54
|
+
children: Array.from(memo.value.values()).map((key2) => {
|
|
55
|
+
const [id, of] = unkeyed(key2);
|
|
56
|
+
if (of === void 0) {
|
|
57
|
+
return toValue(items).find((item) => isItem(item) && item.id === id);
|
|
58
|
+
} else {
|
|
59
|
+
const group = toValue(items).find((item) => isGroup(item) && item.id === of);
|
|
60
|
+
return group?.children?.find((item) => item.id === id);
|
|
61
|
+
}
|
|
62
|
+
}).filter(Boolean)
|
|
63
|
+
},
|
|
64
|
+
...toValue(items)
|
|
65
|
+
].filter((group) => "children" in group ? group.children.length > 0 : true);
|
|
66
|
+
})
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function useNavigationTabs(): {
|
|
2
|
+
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;
|
|
7
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useRoute, useRouter } from "#app";
|
|
2
|
+
import { useSessionStorage } from "@vueuse/core";
|
|
3
|
+
import { computed, watch } from "vue";
|
|
4
|
+
import { normalizeRoutePath } from "../utils/route.js";
|
|
5
|
+
export function useNavigationTabs() {
|
|
6
|
+
const tabs = useSessionStorage("navigation-tabs", /* @__PURE__ */ new Set(), {
|
|
7
|
+
writeDefaults: false
|
|
8
|
+
});
|
|
9
|
+
const active = useSessionStorage("navigation-active-tab", void 0, {
|
|
10
|
+
writeDefaults: false
|
|
11
|
+
});
|
|
12
|
+
const route = useRoute();
|
|
13
|
+
const router = useRouter();
|
|
14
|
+
const tabList = computed(() => Array.from(tabs.value));
|
|
15
|
+
const activateTab = (tab) => {
|
|
16
|
+
active.value = normalizeRoutePath(tab);
|
|
17
|
+
};
|
|
18
|
+
const closeTab = (tab) => {
|
|
19
|
+
const normalizedTab = normalizeRoutePath(tab);
|
|
20
|
+
const nextTabs = tabList.value;
|
|
21
|
+
const closedIndex = nextTabs.findIndex((tab2) => tab2 === normalizedTab);
|
|
22
|
+
tabs.value.delete(normalizedTab);
|
|
23
|
+
if (active.value !== normalizedTab)
|
|
24
|
+
return;
|
|
25
|
+
const previousTab = closedIndex > 0 ? nextTabs[closedIndex - 1] : void 0;
|
|
26
|
+
const nextTab = closedIndex >= 0 ? nextTabs[closedIndex + 1] : void 0;
|
|
27
|
+
const fallbackTab = previousTab ?? nextTab;
|
|
28
|
+
if (fallbackTab) {
|
|
29
|
+
activateTab(fallbackTab);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
activateTab("/");
|
|
33
|
+
};
|
|
34
|
+
watch(active, (tab) => {
|
|
35
|
+
if (!tab)
|
|
36
|
+
return;
|
|
37
|
+
const normalizedTab = normalizeRoutePath(tab);
|
|
38
|
+
if (tab !== normalizedTab) {
|
|
39
|
+
active.value = normalizedTab;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (route.path !== normalizedTab)
|
|
43
|
+
router.replace(normalizedTab);
|
|
44
|
+
if (!tabs.value.has(normalizedTab))
|
|
45
|
+
tabs.value.add(normalizedTab);
|
|
46
|
+
});
|
|
47
|
+
watch(
|
|
48
|
+
() => route.path,
|
|
49
|
+
(path) => {
|
|
50
|
+
const normalizedPath = normalizeRoutePath(path);
|
|
51
|
+
if (active.value !== normalizedPath)
|
|
52
|
+
active.value = normalizedPath;
|
|
53
|
+
if (!tabs.value.has(normalizedPath))
|
|
54
|
+
tabs.value.add(normalizedPath);
|
|
55
|
+
},
|
|
56
|
+
{ immediate: true }
|
|
57
|
+
);
|
|
58
|
+
return {
|
|
59
|
+
tabs,
|
|
60
|
+
tabList,
|
|
61
|
+
active,
|
|
62
|
+
activateTab,
|
|
63
|
+
closeTab
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineNuxtPlugin, navigateTo, useNuxtApp, useRuntimeConfig } from "#app";
|
|
2
2
|
import { useNavigatorLanguage } from "@vueuse/core";
|
|
3
|
+
import { getProperty } from "dot-prop";
|
|
3
4
|
import z from "zod";
|
|
4
5
|
export default defineNuxtPlugin({
|
|
5
6
|
name: "shwfed-nuxt:api",
|
|
@@ -13,12 +14,14 @@ export default defineNuxtPlugin({
|
|
|
13
14
|
onRequest: ({
|
|
14
15
|
options
|
|
15
16
|
}) => {
|
|
16
|
-
|
|
17
|
+
const headersExpression = getProperty(config.apis, "headers");
|
|
18
|
+
const tokenExpression = getProperty(config.apis, "token");
|
|
19
|
+
if (typeof headersExpression === "string" && typeof tokenExpression === "string") {
|
|
17
20
|
try {
|
|
18
|
-
const token = $dsl.evaluate`${
|
|
21
|
+
const token = $dsl.evaluate`${tokenExpression}`();
|
|
19
22
|
if (token === void 0 || typeof token !== "string")
|
|
20
23
|
throw new Error("Token is undefined");
|
|
21
|
-
const headers = $dsl.evaluate`${
|
|
24
|
+
const headers = $dsl.evaluate`${headersExpression}`({
|
|
22
25
|
token
|
|
23
26
|
});
|
|
24
27
|
for (const [key, value] of Object.entries(z.record(z.string(), z.string()).parse(headers))) {
|
|
@@ -33,23 +36,17 @@ export default defineNuxtPlugin({
|
|
|
33
36
|
}
|
|
34
37
|
},
|
|
35
38
|
onResponse: ({ response }) => {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
if (
|
|
39
|
+
const expiredExpression = getProperty(config.apis, "expired");
|
|
40
|
+
const logoutUri = getProperty(config.apis, "logoutUri");
|
|
41
|
+
if (typeof expiredExpression === "string" && typeof logoutUri === "string") {
|
|
39
42
|
try {
|
|
40
|
-
const expired = $dsl.evaluate`${
|
|
43
|
+
const expired = $dsl.evaluate`${expiredExpression}`({
|
|
41
44
|
response: response._data
|
|
42
45
|
});
|
|
43
46
|
if (expired === true) {
|
|
44
47
|
nuxt.runWithContext(() => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
response_type: "code",
|
|
48
|
-
client_id: config.apis.clientId,
|
|
49
|
-
redirect_uri: redirectUri
|
|
50
|
-
});
|
|
51
|
-
url.search = params.toString();
|
|
52
|
-
navigateTo(url.href, {
|
|
48
|
+
window.sessionStorage.clear();
|
|
49
|
+
navigateTo(logoutUri, {
|
|
53
50
|
external: true,
|
|
54
51
|
replace: true
|
|
55
52
|
});
|
|
@@ -64,16 +61,11 @@ export default defineNuxtPlugin({
|
|
|
64
61
|
provide: {
|
|
65
62
|
api,
|
|
66
63
|
logout: () => {
|
|
67
|
-
const logoutUri = config.apis
|
|
68
|
-
if (logoutUri
|
|
64
|
+
const logoutUri = getProperty(config.apis, "logoutUri");
|
|
65
|
+
if (typeof logoutUri !== "string")
|
|
69
66
|
return;
|
|
70
|
-
const url = new URL(logoutUri);
|
|
71
|
-
const params = new URLSearchParams({
|
|
72
|
-
client_id: config.apis.clientId
|
|
73
|
-
});
|
|
74
|
-
url.search = params.toString();
|
|
75
67
|
window.sessionStorage.clear();
|
|
76
|
-
navigateTo(
|
|
68
|
+
navigateTo(logoutUri, {
|
|
77
69
|
external: true,
|
|
78
70
|
replace: true
|
|
79
71
|
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export type PaletteId = string | number;
|
|
2
|
+
export type NavigationPaletteInputItem = Readonly<{
|
|
3
|
+
id: PaletteId;
|
|
4
|
+
title: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
route: string;
|
|
7
|
+
keywords?: ReadonlyArray<string>;
|
|
8
|
+
}>;
|
|
9
|
+
export type NavigationPaletteInputGroup = Readonly<{
|
|
10
|
+
id: PaletteId;
|
|
11
|
+
title: string;
|
|
12
|
+
icon?: string;
|
|
13
|
+
children: ReadonlyArray<NavigationPaletteInputItem>;
|
|
14
|
+
}>;
|
|
15
|
+
export type NavigationPaletteInputEntry = NavigationPaletteInputItem | NavigationPaletteInputGroup;
|
|
16
|
+
export type NavigationPaletteItem = Readonly<{
|
|
17
|
+
id: PaletteId;
|
|
18
|
+
title: string;
|
|
19
|
+
icon?: string;
|
|
20
|
+
route: string;
|
|
21
|
+
keywords: Array<string>;
|
|
22
|
+
}>;
|
|
23
|
+
export type NavigationPaletteGroup = Readonly<{
|
|
24
|
+
id: PaletteId;
|
|
25
|
+
title: string;
|
|
26
|
+
icon?: string;
|
|
27
|
+
children: Array<NavigationPaletteItem>;
|
|
28
|
+
}>;
|
|
29
|
+
export type NavigationPaletteEntry = NavigationPaletteItem | NavigationPaletteGroup;
|
|
30
|
+
export type CommandPaletteInputItem = Readonly<{
|
|
31
|
+
id: PaletteId;
|
|
32
|
+
title: string;
|
|
33
|
+
icon?: string;
|
|
34
|
+
disabled: boolean;
|
|
35
|
+
effect?: string;
|
|
36
|
+
keywords?: ReadonlyArray<string>;
|
|
37
|
+
}>;
|
|
38
|
+
export type CommandPaletteInputGroup = Readonly<{
|
|
39
|
+
id: PaletteId;
|
|
40
|
+
title: string;
|
|
41
|
+
icon?: string;
|
|
42
|
+
children: ReadonlyArray<CommandPaletteInputItem>;
|
|
43
|
+
}>;
|
|
44
|
+
export type CommandPaletteInputEntry = CommandPaletteInputItem | CommandPaletteInputGroup;
|
|
45
|
+
export type CommandPaletteItem = Readonly<{
|
|
46
|
+
id: PaletteId;
|
|
47
|
+
title: string;
|
|
48
|
+
icon?: string;
|
|
49
|
+
disabled: boolean;
|
|
50
|
+
effect?: string;
|
|
51
|
+
keywords: Array<string>;
|
|
52
|
+
}>;
|
|
53
|
+
export type CommandPaletteGroup = Readonly<{
|
|
54
|
+
id: PaletteId;
|
|
55
|
+
title: string;
|
|
56
|
+
icon?: string;
|
|
57
|
+
children: Array<CommandPaletteItem>;
|
|
58
|
+
}>;
|
|
59
|
+
export type CommandPaletteEntry = CommandPaletteItem | CommandPaletteGroup;
|
|
60
|
+
export declare const splitNavigationForPalette: (entries: ReadonlyArray<NavigationPaletteInputEntry>) => {
|
|
61
|
+
favoriteRoutes: Readonly<{
|
|
62
|
+
id: PaletteId;
|
|
63
|
+
title: string;
|
|
64
|
+
icon?: string;
|
|
65
|
+
route: string;
|
|
66
|
+
keywords: Array<string>;
|
|
67
|
+
}>[];
|
|
68
|
+
navigationEntries: NavigationPaletteEntry[];
|
|
69
|
+
};
|
|
70
|
+
export declare const normalizeCommandsForPalette: (entries: ReadonlyArray<CommandPaletteInputEntry>) => Array<CommandPaletteEntry>;
|
|
71
|
+
export declare const createPaletteItemValue: (prefix: "fav" | "nav" | "cmd", itemId: PaletteId, groupId?: PaletteId) => string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const normalizeKeywords = (keywords) => {
|
|
2
|
+
if (keywords === void 0)
|
|
3
|
+
return [];
|
|
4
|
+
return [...keywords];
|
|
5
|
+
};
|
|
6
|
+
const normalizeNavigationItem = (item) => {
|
|
7
|
+
return {
|
|
8
|
+
id: item.id,
|
|
9
|
+
title: item.title,
|
|
10
|
+
icon: item.icon,
|
|
11
|
+
route: item.route,
|
|
12
|
+
keywords: normalizeKeywords(item.keywords)
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export const splitNavigationForPalette = (entries) => {
|
|
16
|
+
const favoriteRoutes = [];
|
|
17
|
+
const navigationEntries = [];
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if ("children" in entry) {
|
|
20
|
+
const children = entry.children.map((child) => normalizeNavigationItem(child));
|
|
21
|
+
if (entry.id === "$favorites") {
|
|
22
|
+
favoriteRoutes.push(...children);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
navigationEntries.push({
|
|
26
|
+
id: entry.id,
|
|
27
|
+
title: entry.title,
|
|
28
|
+
icon: entry.icon,
|
|
29
|
+
children
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
navigationEntries.push(normalizeNavigationItem(entry));
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
favoriteRoutes,
|
|
37
|
+
navigationEntries
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const normalizeCommandItem = (item) => {
|
|
41
|
+
return {
|
|
42
|
+
id: item.id,
|
|
43
|
+
title: item.title,
|
|
44
|
+
icon: item.icon,
|
|
45
|
+
disabled: item.disabled,
|
|
46
|
+
effect: item.effect,
|
|
47
|
+
keywords: normalizeKeywords(item.keywords)
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export const normalizeCommandsForPalette = (entries) => {
|
|
51
|
+
const commandEntries = [];
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
if ("children" in entry) {
|
|
54
|
+
commandEntries.push({
|
|
55
|
+
id: entry.id,
|
|
56
|
+
title: entry.title,
|
|
57
|
+
icon: entry.icon,
|
|
58
|
+
children: entry.children.map((child) => normalizeCommandItem(child))
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
commandEntries.push(normalizeCommandItem(entry));
|
|
63
|
+
}
|
|
64
|
+
return commandEntries;
|
|
65
|
+
};
|
|
66
|
+
export const createPaletteItemValue = (prefix, itemId, groupId) => {
|
|
67
|
+
const parts = [prefix];
|
|
68
|
+
if (groupId !== void 0)
|
|
69
|
+
parts.push(String(groupId));
|
|
70
|
+
parts.push(String(itemId));
|
|
71
|
+
return parts.join(":");
|
|
72
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const commandActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
3
|
+
type: z.ZodLiteral<"route">;
|
|
4
|
+
to: z.ZodString;
|
|
5
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
6
|
+
type: z.ZodLiteral<"external">;
|
|
7
|
+
href: z.ZodString;
|
|
8
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
9
|
+
type: z.ZodLiteral<"logout">;
|
|
10
|
+
}, z.core.$strip>], "type">;
|
|
11
|
+
export type CommandAction = z.infer<typeof commandActionSchema>;
|
|
12
|
+
export type ExecuteCommandActionOptions = {
|
|
13
|
+
logout: () => void;
|
|
14
|
+
};
|
|
15
|
+
export declare const executeCommandAction: (action: CommandAction, options: ExecuteCommandActionOptions) => void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { navigateTo } from "#app";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const commandActionSchema = z.discriminatedUnion("type", [
|
|
4
|
+
z.object({
|
|
5
|
+
type: z.literal("route"),
|
|
6
|
+
to: z.string()
|
|
7
|
+
}),
|
|
8
|
+
z.object({
|
|
9
|
+
type: z.literal("external"),
|
|
10
|
+
href: z.string()
|
|
11
|
+
}),
|
|
12
|
+
z.object({
|
|
13
|
+
type: z.literal("logout")
|
|
14
|
+
})
|
|
15
|
+
]);
|
|
16
|
+
export const executeCommandAction = (action, options) => {
|
|
17
|
+
switch (action.type) {
|
|
18
|
+
case "route":
|
|
19
|
+
navigateTo(action.to);
|
|
20
|
+
return;
|
|
21
|
+
case "external":
|
|
22
|
+
navigateTo(action.href, { external: true });
|
|
23
|
+
return;
|
|
24
|
+
case "logout":
|
|
25
|
+
options.logout();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function normalizeRoutePath(path) {
|
|
2
|
+
if (!path)
|
|
3
|
+
return "/";
|
|
4
|
+
const pathWithoutQueryOrHash = path.split(/[?#]/)[0] ?? "/";
|
|
5
|
+
const normalized = pathWithoutQueryOrHash.replace(/\/+$/, "");
|
|
6
|
+
return normalized || "/";
|
|
7
|
+
}
|
|
8
|
+
export function isRouteActive(currentPath, itemRoute) {
|
|
9
|
+
const current = normalizeRoutePath(currentPath);
|
|
10
|
+
const item = normalizeRoutePath(itemRoute);
|
|
11
|
+
if (item === "/")
|
|
12
|
+
return current === "/";
|
|
13
|
+
return current === item || current.startsWith(`${item}/`);
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type RouteItem = Readonly<{
|
|
2
|
+
route: string;
|
|
3
|
+
}>;
|
|
4
|
+
type GroupItem = Readonly<{
|
|
5
|
+
children: Array<RouteItem>;
|
|
6
|
+
}>;
|
|
7
|
+
export type SidebarNavigationItem = RouteItem | GroupItem;
|
|
8
|
+
export declare function getDefaultNavigationRoute(items: Array<SidebarNavigationItem>): string | undefined;
|
|
9
|
+
export declare function hasRootNavigation(items: Array<SidebarNavigationItem>): boolean;
|
|
10
|
+
export declare function applyRootNavigationFallback(options: {
|
|
11
|
+
path: string;
|
|
12
|
+
items: Array<SidebarNavigationItem>;
|
|
13
|
+
tabs: Set<string>;
|
|
14
|
+
activateTab: (route: string) => void;
|
|
15
|
+
}): void;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { normalizeRoutePath } from "./route.js";
|
|
2
|
+
function isRouteItem(item) {
|
|
3
|
+
return "route" in item;
|
|
4
|
+
}
|
|
5
|
+
export function getDefaultNavigationRoute(items) {
|
|
6
|
+
for (const item of items) {
|
|
7
|
+
if (isRouteItem(item))
|
|
8
|
+
return normalizeRoutePath(item.route);
|
|
9
|
+
const firstChildRoute = item.children[0]?.route;
|
|
10
|
+
if (firstChildRoute)
|
|
11
|
+
return normalizeRoutePath(firstChildRoute);
|
|
12
|
+
}
|
|
13
|
+
return void 0;
|
|
14
|
+
}
|
|
15
|
+
export function hasRootNavigation(items) {
|
|
16
|
+
return items.some((item) => {
|
|
17
|
+
if (isRouteItem(item))
|
|
18
|
+
return normalizeRoutePath(item.route) === "/";
|
|
19
|
+
return item.children.some((child) => normalizeRoutePath(child.route) === "/");
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function applyRootNavigationFallback(options) {
|
|
23
|
+
if (normalizeRoutePath(options.path) !== "/")
|
|
24
|
+
return;
|
|
25
|
+
if (hasRootNavigation(options.items))
|
|
26
|
+
return;
|
|
27
|
+
const fallbackRoute = getDefaultNavigationRoute(options.items);
|
|
28
|
+
if (!fallbackRoute || fallbackRoute === "/")
|
|
29
|
+
return;
|
|
30
|
+
options.tabs.delete("/");
|
|
31
|
+
options.activateTab(fallbackRoute);
|
|
32
|
+
}
|
package/package.json
CHANGED