@pubinfo/core 2.0.0-rc.1 → 2.0.0-rc.3
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/{AppSetting-Bblni_W7.js → AppSetting-3wJKvibc.js} +19 -19
- package/dist/{HCheckList.vue_vue_type_script_setup_true_lang-A7PnhNKK.js → HCheckList.vue_vue_type_script_setup_true_lang-17EywJvs.js} +1 -1
- package/dist/{HToggle-xibvPpmf.js → HToggle-B-ZjSh6S.js} +1 -1
- package/dist/{PreferencesContent--JtPw_LT.js → PreferencesContent-xT4paU7N.js} +52 -52
- package/dist/{SettingBreadcrumb-BwhdAtkC.js → SettingBreadcrumb-CYnO51Ek.js} +5 -5
- package/dist/{SettingCopyright-DPsRDagL.js → SettingCopyright-FOW5ObHK.js} +2 -2
- package/dist/{SettingEnableTransition-mtHTUb08.js → SettingEnableTransition-Q5cvubmF.js} +12 -12
- package/dist/{SettingHome-agxHFIKq.js → SettingHome-Df7-AlWB.js} +8 -8
- package/dist/{SettingMenu-D6WwcOw-.js → SettingMenu-BNAJ3el9.js} +14 -14
- package/dist/{SettingMode-CkmhszlD.js → SettingMode-LzlRsBL9.js} +3 -3
- package/dist/{SettingNavSearch-CEB5DZGf.js → SettingNavSearch-BA08vYuw.js} +6 -6
- package/dist/{SettingOther-Dzs1uwnC.js → SettingOther-BE8dDCYD.js} +11 -11
- package/dist/{SettingPage-bOThkL2-.js → SettingPage-D061yXCv.js} +2 -2
- package/dist/{SettingTabbar-L6yQxAeE.js → SettingTabbar-COwdPPKy.js} +13 -13
- package/dist/{SettingThemes-Cxa5bR66.js → SettingThemes-BHaYERNp.js} +12 -12
- package/dist/{SettingToolbar-BZ2uHom2.js → SettingToolbar-fSuzu6ND.js} +10 -10
- package/dist/{SettingTopbar-hptxTh8m.js → SettingTopbar-D7GgP0KB.js} +6 -6
- package/dist/{SettingWidthMode-D2R2W4-n.js → SettingWidthMode-CNjzChe1.js} +11 -11
- package/dist/{TopThinMode-C26i10py.js → TopThinMode-B-28sBJD.js} +3 -3
- package/dist/built-in/layout-component/Layout.vue.d.ts +1 -0
- package/dist/built-in/layout-component/components/Tools/Fullscreen.vue.d.ts +2 -0
- package/dist/built-in/layout-component/components/Tools/PageReload.vue.d.ts +2 -0
- package/dist/built-in/layout-component/components/Tools/SearchBar.vue.d.ts +2 -0
- package/dist/built-in/layout-component/components/Tools/index.vue.d.ts +47 -207
- package/dist/built-in/layout-component/components/Tools/interface.d.ts +26 -0
- package/dist/built-in/layout-component/components/Topbar/Tabbar/MoreAction.vue.d.ts +0 -206
- package/dist/built-in/layout-component/components/ui/HDropdownMenu.vue.d.ts +2 -7
- package/dist/built-in/layout-component/composables/useGlobalSearch.d.ts +19 -0
- package/dist/built-in/layout-component/composables/useHotkey.d.ts +1 -5
- package/dist/built-in/layout-component/composables/useMainPage.d.ts +1 -1
- package/dist/built-in/layout-component/composables/useMenu.d.ts +1 -1
- package/dist/built-in/layout-component/composables/useTabbar.d.ts +1 -1
- package/dist/built-in/layout-component/composables/useTitle.d.ts +2 -1
- package/dist/built-in/layout-component/composables/useWatermark.d.ts +3 -1
- package/dist/built-in/layout-component/index.d.ts +9 -6
- package/dist/built-in/layout-component/utils/index.d.ts +0 -1
- package/dist/{colors-C8I6Fdyp.js → colors-BIQSd520.js} +1 -1
- package/dist/{index-RwbJwutI.js → index-Beb7_0-E.js} +14499 -14397
- package/dist/{index-D948mfZb.js → index-CPRiufg0.js} +1 -1
- package/dist/{index-DZ6SbWiv.js → index-DNdH93AP.js} +13 -13
- package/dist/index-DYMBkmAp.js +139 -0
- package/dist/{index-DdS6qgK_.js → index-Dlf6GQBd.js} +6418 -6439
- package/dist/{index-D3zjK9rd.js → index-IscoZG-Y.js} +2 -2
- package/dist/{index-DeWCd_-p.js → index-WubcSL0v.js} +1 -1
- package/dist/index-YSjb6X1D.js +232 -0
- package/dist/{index-EOTrQlGo.js → index-wxEEuQXu.js} +17 -17
- package/dist/index.d.ts +4 -2
- package/dist/index.js +53 -55
- package/dist/{pick-D6j4F3UM.js → pick-D_XPbQHB.js} +1 -1
- package/dist/style.css +1 -1
- package/package.json +10 -10
- package/src/built-in/authentication/pages/change-organization/assets/change-org.svg +1 -1
- package/src/built-in/authentication/pages/change-password/assets/mima.svg +1 -1
- package/src/built-in/authorization/pages/not-permission/403.svg +1 -1
- package/src/built-in/authorization/pages/not-permission/403_dark.svg +1 -1
- package/src/built-in/layout-component/Layout.vue +11 -22
- package/src/built-in/layout-component/assets/icons/favorites.svg +1 -1
- package/src/built-in/layout-component/assets/icons/toolbar-collapse.svg +1 -1
- package/src/built-in/layout-component/components/Header/TopMode/index.vue +1 -1
- package/src/built-in/layout-component/components/Sidebar/MainSidebar.vue +1 -1
- package/src/built-in/layout-component/components/Sidebar/index.vue +1 -1
- package/src/built-in/layout-component/components/Tools/DarkModeToggle.vue +108 -0
- package/src/built-in/layout-component/components/Tools/Fullscreen.vue +24 -0
- package/src/built-in/layout-component/components/Tools/PageReload.vue +22 -0
- package/src/built-in/layout-component/components/Tools/SearchBar.vue +44 -0
- package/src/built-in/layout-component/components/Tools/{Search.vue → SearchPanel.vue} +12 -6
- package/src/built-in/layout-component/components/Tools/index.vue +64 -130
- package/src/built-in/layout-component/components/Tools/interface.ts +27 -0
- package/src/built-in/layout-component/components/Topbar/Tabbar/MoreAction.vue +7 -6
- package/src/built-in/layout-component/components/Topbar/Tabbar/index.vue +2 -2
- package/src/built-in/layout-component/components/Topbar/Toolbar/index.vue +32 -10
- package/src/built-in/layout-component/components/ui/HDropdownMenu.vue +19 -26
- package/src/built-in/layout-component/composables/useGetComputedStyle.ts +2 -3
- package/src/built-in/layout-component/composables/useGlobalSearch.ts +48 -0
- package/src/built-in/layout-component/composables/useHotkey.ts +6 -10
- package/src/built-in/layout-component/composables/useMainPage.ts +5 -6
- package/src/built-in/layout-component/composables/useMenu.ts +3 -5
- package/src/built-in/layout-component/composables/useTabbar.ts +3 -5
- package/src/built-in/layout-component/composables/useTitle.ts +2 -3
- package/src/built-in/layout-component/composables/useWatermark.ts +25 -12
- package/src/built-in/layout-component/index.ts +21 -12
- package/src/built-in/layout-component/provider.ts +6 -2
- package/src/built-in/layout-component/utils/index.ts +0 -1
- package/src/built-in/settings/router.ts +5 -1
- package/src/features/assets/fonts/digital-7/digital-7-webfont.svg +131 -133
- package/src/features/assets/fonts/digital-7_mono/digital-7_mono-webfont.svg +130 -132
- package/src/features/assets/images/org.svg +2 -2
- package/src/features/components/NotAllowed/assets/403.svg +1 -1
- package/src/features/components/NotAllowed/assets/403_dark.svg +1 -1
- package/src/features/components/PubinfoIcon/index.vue +1 -1
- package/src/features/pages/not-found/assets/404.svg +1 -1
- package/src/features/pages/not-found/assets/404_dark.svg +1 -1
- package/src/features/stores/utils/routerHelper.ts +3 -0
- package/src/index.ts +7 -9
- package/dist/built-in/layout-component/utils/eventBus.d.ts +0 -5
- package/dist/index-CkyHqPON.js +0 -139
- package/dist/index-xzfvpJSq.js +0 -234
- package/src/built-in/layout-component/components/Tools/DayNightSwitch.vue +0 -70
- package/src/built-in/layout-component/utils/eventBus.ts +0 -8
- /package/dist/built-in/layout-component/components/Tools/{DayNightSwitch.vue.d.ts → DarkModeToggle.vue.d.ts} +0 -0
- /package/dist/built-in/layout-component/components/Tools/{Search.vue.d.ts → SearchPanel.vue.d.ts} +0 -0
|
@@ -1,128 +1,108 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { DropdownMenuRender } from './interface';
|
|
3
3
|
import { useI18n } from 'vue-i18n';
|
|
4
4
|
import CarbonUserAvatarFilledAlt from '~icons/carbon/user-avatar-filled-alt';
|
|
5
|
-
import FluentArrowSync16Filled from '~icons/fluent/arrow-sync-16-filled';
|
|
6
|
-
import FluentFullScreenMaximize16Filled from '~icons/fluent/full-screen-maximize-16-filled';
|
|
7
|
-
import FluentFullScreenMinimize16Filled from '~icons/fluent/full-screen-minimize-16-filled';
|
|
8
|
-
import IconamoonSearch from '~icons/iconamoon/search';
|
|
9
5
|
import MaterialSymbolsExpandMoreRounded from '~icons/material-symbols/expand-more-rounded';
|
|
10
|
-
import PhLineVerticalThin from '~icons/ph/line-vertical-thin';
|
|
11
6
|
|
|
7
|
+
import PhLineVerticalThin from '~icons/ph/line-vertical-thin';
|
|
12
8
|
import { useContext } from '../../composables/useContext';
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import DayNightSwitch from './DayNightSwitch.vue';
|
|
9
|
+
import DarkModeToggle from './DarkModeToggle.vue';
|
|
10
|
+
import Fullscreen from './Fullscreen.vue';
|
|
16
11
|
import HotkeysIntro from './HotkeysIntro.vue';
|
|
12
|
+
import PageReload from './PageReload.vue';
|
|
17
13
|
import Preferences from './Preferences/index.vue';
|
|
18
|
-
import
|
|
14
|
+
import SearchBar from './SearchBar.vue';
|
|
15
|
+
import SearchPanel from './SearchPanel.vue';
|
|
19
16
|
|
|
20
17
|
defineOptions({
|
|
21
18
|
name: 'Tools',
|
|
22
19
|
});
|
|
23
20
|
|
|
21
|
+
const props = withDefaults(
|
|
22
|
+
defineProps<{
|
|
23
|
+
// 用户菜单渲染函数
|
|
24
|
+
dropdownMenuRender?: DropdownMenuRender
|
|
25
|
+
}>(),
|
|
26
|
+
{
|
|
27
|
+
dropdownMenuRender: (({ Home, Preferences, Hotkeys, Org, Profile, Password, Logout, Divider }) => {
|
|
28
|
+
return [Home, Preferences, Divider, Hotkeys, Divider, Org, Profile, Password, Logout];
|
|
29
|
+
}) as DropdownMenuRender,
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
24
33
|
const router = useRouter();
|
|
25
34
|
const { settingsStore, userStore, generateI18nTitle } = useContext();
|
|
26
35
|
|
|
27
36
|
const { t } = useI18n();
|
|
28
37
|
|
|
29
|
-
const mainPage = useMainPage();
|
|
30
|
-
const { isFullscreen, toggle } = useFullscreen();
|
|
31
|
-
|
|
32
38
|
const hotkeysIntroRef = ref();
|
|
33
39
|
const preferencesRef = ref();
|
|
34
|
-
const searchRef = ref();
|
|
35
40
|
|
|
36
|
-
const userMenu = computed(() =>
|
|
37
|
-
|
|
38
|
-
{
|
|
41
|
+
const userMenu = computed(() => {
|
|
42
|
+
return {
|
|
43
|
+
Home: {
|
|
44
|
+
key: 'home',
|
|
39
45
|
label: generateI18nTitle('route.home', settingsStore.settings.home.title),
|
|
40
46
|
icon: 'i-ant-design:home-twotone',
|
|
41
|
-
|
|
47
|
+
onClick: () => router.push({ name: 'Home' }),
|
|
42
48
|
hide: !settingsStore.settings.home.enable,
|
|
43
49
|
},
|
|
44
|
-
{
|
|
50
|
+
Preferences: {
|
|
51
|
+
key: 'preferences',
|
|
45
52
|
label: t('app.preferences'),
|
|
46
53
|
icon: 'i-iconamoon-star-duotone',
|
|
47
|
-
|
|
54
|
+
onClick: () => preferencesRef.value?.open?.(),
|
|
48
55
|
hide: !settingsStore.settings.app.enableUserPreferences,
|
|
49
56
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{
|
|
57
|
+
Hotkeys: {
|
|
58
|
+
key: 'hotkeys',
|
|
53
59
|
label: t('app.hotkeys'),
|
|
54
60
|
icon: 'i-iconamoon-lightning-2-duotone',
|
|
55
|
-
|
|
61
|
+
onClick: () => hotkeysIntroRef.value?.open?.(),
|
|
56
62
|
hide: settingsStore.mode !== 'pc',
|
|
57
63
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
{
|
|
64
|
+
Org: {
|
|
65
|
+
key: 'org',
|
|
61
66
|
label: t('app.changeOrg'),
|
|
62
67
|
icon: 'i-iconamoon-synchronize-duotone',
|
|
63
|
-
|
|
68
|
+
onClick: () => router.push({
|
|
64
69
|
name: 'ChangeOrganization',
|
|
65
70
|
params: { orgId: userStore.user.orgId },
|
|
66
71
|
}),
|
|
67
72
|
hide: userStore.user.orgList.length <= 1,
|
|
68
73
|
},
|
|
69
|
-
{
|
|
74
|
+
Profile: {
|
|
75
|
+
key: 'profile',
|
|
70
76
|
label: t('route.personal.profile'),
|
|
71
77
|
icon: 'i-iconamoon-profile-duotone',
|
|
72
|
-
|
|
78
|
+
onClick: () => router.push({ name: 'Profile' }),
|
|
73
79
|
},
|
|
74
|
-
{
|
|
80
|
+
Password: {
|
|
81
|
+
key: 'password',
|
|
75
82
|
label: t('app.changePassword'),
|
|
76
83
|
icon: 'i-iconamoon-lock-duotone',
|
|
77
|
-
|
|
84
|
+
onClick: () => router.push({
|
|
78
85
|
name: 'ChangePassword',
|
|
79
86
|
params: {
|
|
80
87
|
changePassWordToken: userStore.user.token,
|
|
81
88
|
},
|
|
82
89
|
}),
|
|
83
90
|
},
|
|
84
|
-
{
|
|
91
|
+
Logout: {
|
|
92
|
+
key: 'logout',
|
|
85
93
|
label: t('app.logout'),
|
|
86
94
|
icon: 'i-iconamoon-arrow-left-3-square-duotone',
|
|
87
|
-
|
|
95
|
+
onClick: () => userStore.logout(),
|
|
88
96
|
},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const colorScheme = settingsStore.settings.app.colorScheme === 'dark' ? 'light' : 'dark';
|
|
95
|
-
settingsStore.setColorScheme(colorScheme);
|
|
96
|
-
await settingsStore.setPreferencesSetting({
|
|
97
|
-
app: {
|
|
98
|
-
colorScheme,
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
});
|
|
97
|
+
Divider: {
|
|
98
|
+
key: 'divider',
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const endRadius = Math.hypot(
|
|
107
|
-
Math.max(x, innerWidth - x),
|
|
108
|
-
Math.max(y, innerHeight - y),
|
|
109
|
-
);
|
|
110
|
-
const clipPath = [
|
|
111
|
-
`circle(0px at ${x}px ${y}px)`,
|
|
112
|
-
`circle(${endRadius}px at ${x}px ${y}px)`,
|
|
113
|
-
];
|
|
114
|
-
document.documentElement.animate(
|
|
115
|
-
{
|
|
116
|
-
clipPath: settingsStore.settings.app.colorScheme !== 'dark' ? clipPath : clipPath.reverse(),
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
duration: 300,
|
|
120
|
-
easing: 'ease-out',
|
|
121
|
-
pseudoElement: settingsStore.settings.app.colorScheme !== 'dark' ? '::view-transition-new(root)' : '::view-transition-old(root)',
|
|
122
|
-
},
|
|
123
|
-
);
|
|
124
|
-
});
|
|
125
|
-
}
|
|
103
|
+
const menus = computed(() => {
|
|
104
|
+
return props.dropdownMenuRender?.(userMenu.value);
|
|
105
|
+
});
|
|
126
106
|
|
|
127
107
|
const avatarError = ref(false);
|
|
128
108
|
|
|
@@ -131,73 +111,33 @@ watch(() => userStore.user.avatar, () => {
|
|
|
131
111
|
avatarError.value = false;
|
|
132
112
|
}
|
|
133
113
|
});
|
|
134
|
-
|
|
135
|
-
const searchComponentsClass = computed(() => {
|
|
136
|
-
const componentsClass = {
|
|
137
|
-
'side': 'ring-1 ',
|
|
138
|
-
'head': 'bg-[var(--g-header-menu-active-bg)]',
|
|
139
|
-
'single': ' ring-1',
|
|
140
|
-
'only-side': 'ring-1',
|
|
141
|
-
'only-head': ' bg-[var(--g-header-menu-active-bg)]',
|
|
142
|
-
};
|
|
143
|
-
const menuMode = settingsStore.settings.menu.menuMode;
|
|
144
|
-
return componentsClass[menuMode];
|
|
145
|
-
});
|
|
146
114
|
</script>
|
|
147
115
|
|
|
148
116
|
<template>
|
|
149
117
|
<div class="tools flex items-center gap-4 whitespace-nowrap px-4">
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
<HKbd
|
|
159
|
-
v-if="settingsStore.settings.navSearch.enableHotkeys"
|
|
160
|
-
class="ml-2"
|
|
161
|
-
>{{ settingsStore.os === 'mac' ? '⌥' : 'Alt' }} S</HKbd>
|
|
162
|
-
</span>
|
|
163
|
-
<div class="flex items-center empty:hidden">
|
|
164
|
-
<span
|
|
165
|
-
v-if="settingsStore.settings.navSearch.enable && settingsStore.mode === 'mobile'"
|
|
166
|
-
class="item"
|
|
167
|
-
@click="searchRef?.toggle?.()"
|
|
168
|
-
>
|
|
169
|
-
<IconamoonSearch text="14px" />
|
|
170
|
-
</span>
|
|
171
|
-
<span
|
|
172
|
-
v-if="settingsStore.mode === 'pc' && settingsStore.settings.toolbar.enableFullscreen"
|
|
173
|
-
class="item"
|
|
174
|
-
@click="toggle"
|
|
175
|
-
>
|
|
176
|
-
<FluentFullScreenMinimize16Filled v-if="isFullscreen" text="16px" />
|
|
177
|
-
<FluentFullScreenMaximize16Filled v-else text="16px" />
|
|
178
|
-
</span>
|
|
179
|
-
<span
|
|
180
|
-
v-if="settingsStore.settings.toolbar.enablePageReload"
|
|
181
|
-
class="item"
|
|
182
|
-
@click="mainPage.reload()"
|
|
183
|
-
>
|
|
184
|
-
<FluentArrowSync16Filled text="15px" />
|
|
185
|
-
</span>
|
|
186
|
-
<DayNightSwitch @click="toggleColorScheme" />
|
|
118
|
+
<SearchBar />
|
|
119
|
+
|
|
120
|
+
<div class="flex items-center empty:hidden gap-3">
|
|
121
|
+
<slot name="default">
|
|
122
|
+
<Fullscreen />
|
|
123
|
+
<PageReload />
|
|
124
|
+
<DarkModeToggle />
|
|
125
|
+
</slot>
|
|
187
126
|
</div>
|
|
127
|
+
|
|
188
128
|
<div flex-center cursor-pointer gap-1>
|
|
189
129
|
<img
|
|
190
130
|
v-if="userStore.user.avatar && !avatarError"
|
|
191
131
|
:src="userStore.user.avatar"
|
|
192
132
|
:onerror="() => (avatarError = true)"
|
|
193
|
-
class="
|
|
133
|
+
class="size-[24px] rounded-full"
|
|
194
134
|
>
|
|
195
135
|
<CarbonUserAvatarFilledAlt v-else text="20px" mr-2px />
|
|
196
|
-
<div flex-center cursor-pointer>
|
|
136
|
+
<div class="flex-center cursor-pointer">
|
|
197
137
|
{{ userStore.userOrgName }}
|
|
198
138
|
</div>
|
|
199
|
-
<PhLineVerticalThin />
|
|
200
|
-
<HDropdownMenu :items="
|
|
139
|
+
<PhLineVerticalThin v-if="userStore?.userOrgName" />
|
|
140
|
+
<HDropdownMenu :items="menus">
|
|
201
141
|
<div flex-center cursor-pointer gap-1>
|
|
202
142
|
{{ userStore.user.account }}
|
|
203
143
|
<MaterialSymbolsExpandMoreRounded ml="5px" mr="10px" />
|
|
@@ -206,13 +146,7 @@ const searchComponentsClass = computed(() => {
|
|
|
206
146
|
</div>
|
|
207
147
|
|
|
208
148
|
<HotkeysIntro ref="hotkeysIntroRef" />
|
|
209
|
-
<
|
|
149
|
+
<SearchPanel />
|
|
210
150
|
<Preferences v-if="settingsStore.settings.app.enableUserPreferences" ref="preferencesRef" />
|
|
211
151
|
</div>
|
|
212
152
|
</template>
|
|
213
|
-
|
|
214
|
-
<style scoped>
|
|
215
|
-
.item {
|
|
216
|
-
--at-apply: flex px-2 py-1 cursor-pointer;
|
|
217
|
-
}
|
|
218
|
-
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface DropdownMenu {
|
|
2
|
+
key?: string | 'divider'
|
|
3
|
+
icon?: string
|
|
4
|
+
label?: string
|
|
5
|
+
disabled?: boolean
|
|
6
|
+
hide?: boolean
|
|
7
|
+
onClick?: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type DropdownMenuRender = (items: {
|
|
11
|
+
/** 主页 */
|
|
12
|
+
Home: DropdownMenu
|
|
13
|
+
/** 个人偏好设置 */
|
|
14
|
+
Preferences: DropdownMenu
|
|
15
|
+
/** 快捷键介绍 */
|
|
16
|
+
Hotkeys: DropdownMenu
|
|
17
|
+
/** 切换组织 */
|
|
18
|
+
Org: DropdownMenu
|
|
19
|
+
/** 个人中心 */
|
|
20
|
+
Profile: DropdownMenu
|
|
21
|
+
/** 修改密码 */
|
|
22
|
+
Password: DropdownMenu
|
|
23
|
+
/** 登出 */
|
|
24
|
+
Logout: DropdownMenu
|
|
25
|
+
/** 分割线 */
|
|
26
|
+
Divider: DropdownMenu
|
|
27
|
+
}) => DropdownMenu[];
|
|
@@ -12,8 +12,9 @@ import RiCloseFill from '~icons/ri/close-fill';
|
|
|
12
12
|
import RiPushpin2Fill from '~icons/ri/pushpin-2-fill';
|
|
13
13
|
import { PubinfoIcon } from '@/features/components';
|
|
14
14
|
import { useContext } from '../../../composables/useContext';
|
|
15
|
-
import
|
|
16
|
-
import
|
|
15
|
+
import { useGlobalSearch } from '../../../composables/useGlobalSearch';
|
|
16
|
+
import { useTabbar } from '../../../composables/useTabbar';
|
|
17
|
+
import Search from '../../Tools/SearchPanel.vue';
|
|
17
18
|
|
|
18
19
|
defineOptions({
|
|
19
20
|
name: 'TabbarMoreAction',
|
|
@@ -30,7 +31,7 @@ const { t } = useI18n();
|
|
|
30
31
|
const activedTabId = computed(() => tabbar.getId());
|
|
31
32
|
|
|
32
33
|
const dropdownTabContainerRef = ref();
|
|
33
|
-
const
|
|
34
|
+
const { toggle: toggleGlobalSearch } = useGlobalSearch();
|
|
34
35
|
|
|
35
36
|
const isDragging = ref(false);
|
|
36
37
|
|
|
@@ -60,7 +61,7 @@ watch(() => dropdownTabContainerRef.value, (val) => {
|
|
|
60
61
|
function actionCommand(command: 'search-tabs' | 'other-side' | 'left-side' | 'right-side') {
|
|
61
62
|
switch (command) {
|
|
62
63
|
case 'search-tabs':
|
|
63
|
-
|
|
64
|
+
toggleGlobalSearch('tab');
|
|
64
65
|
break;
|
|
65
66
|
case 'other-side':
|
|
66
67
|
tabbar.closeOtherSide();
|
|
@@ -142,7 +143,7 @@ function iconName(isActive: boolean, icon: Tabbar.recordRaw['icon'], activeIcon:
|
|
|
142
143
|
</template>
|
|
143
144
|
</HDropdown>
|
|
144
145
|
|
|
145
|
-
<Search
|
|
146
|
+
<Search />
|
|
146
147
|
</div>
|
|
147
148
|
</template>
|
|
148
149
|
|
|
@@ -153,7 +154,7 @@ function iconName(isActive: boolean, icon: Tabbar.recordRaw['icon'], activeIcon:
|
|
|
153
154
|
|
|
154
155
|
.tabbar-dropdown .quick-button .button {
|
|
155
156
|
--at-apply: flex items-center justify-center w-8 h-8 cursor-pointer bg-[--g-bg]
|
|
156
|
-
transition-[colors] duration-[0.3s] rounded-[5px] border-
|
|
157
|
+
transition-[colors] duration-[0.3s] rounded-[5px] border-0 [outline:none];
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
.tabbar-dropdown .quick-button .button:hover:not(:disabled) {
|
|
@@ -11,8 +11,8 @@ import RiPushpin2Fill from '~icons/ri/pushpin-2-fill';
|
|
|
11
11
|
import { PubinfoIcon } from '@/features/components';
|
|
12
12
|
import { storage } from '@/utils';
|
|
13
13
|
import { useContext } from '../../../composables/useContext';
|
|
14
|
-
import useMainPage from '../../../composables/useMainPage';
|
|
15
|
-
import useTabbar from '../../../composables/useTabbar';
|
|
14
|
+
import { useMainPage } from '../../../composables/useMainPage';
|
|
15
|
+
import { useTabbar } from '../../../composables/useTabbar';
|
|
16
16
|
import MoreAction from './MoreAction.vue';
|
|
17
17
|
import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css';
|
|
18
18
|
|
|
@@ -56,8 +56,10 @@ function createHomeBreadcrumb() {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
interface BreadcrumbItemNode { title: string, path: string, mainIndex?: number }
|
|
60
|
+
|
|
59
61
|
const breadcrumbList = computed(() => {
|
|
60
|
-
const breadcrumbList:
|
|
62
|
+
const breadcrumbList: BreadcrumbItemNode[] = [];
|
|
61
63
|
if (settingsStore.settings.home.enable) {
|
|
62
64
|
breadcrumbList.push(createHomeBreadcrumb());
|
|
63
65
|
}
|
|
@@ -74,7 +76,8 @@ const breadcrumbList = computed(() => {
|
|
|
74
76
|
|
|
75
77
|
if (menuStore.allMenus[index]?.meta) {
|
|
76
78
|
breadcrumbList.push({
|
|
77
|
-
path:
|
|
79
|
+
path: `__MAIN__${index}`,
|
|
80
|
+
mainIndex: index,
|
|
78
81
|
title: generateI18nTitle(menuStore.allMenus[index].meta?.i18n, menuStore.allMenus[index].meta?.title),
|
|
79
82
|
});
|
|
80
83
|
}
|
|
@@ -147,21 +150,40 @@ function recursiveTreeMap<T extends { children?: T[] }>(tree: T[], fn: (node: T)
|
|
|
147
150
|
* 根据 path 字段读取树中的指定节点
|
|
148
151
|
*/
|
|
149
152
|
function getCurrentBreadcrumb(path: string) {
|
|
153
|
+
if (path.startsWith('__MAIN__')) {
|
|
154
|
+
const idx = Number(path.replace('__MAIN__', ''));
|
|
155
|
+
const main = menuStore.allMenus[idx];
|
|
156
|
+
if (main) {
|
|
157
|
+
const mapNode = (r: any): any => ({
|
|
158
|
+
title: generateI18nTitle(r.meta?.i18n, r.meta?.title),
|
|
159
|
+
path: r.path,
|
|
160
|
+
children: (r.children || [])
|
|
161
|
+
.filter((c: any) => c.meta?.sidebar !== false)
|
|
162
|
+
.map((c: any) => mapNode(c)),
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
title: generateI18nTitle(main.meta?.i18n, main.meta?.title),
|
|
166
|
+
path,
|
|
167
|
+
children: (main.children || [])
|
|
168
|
+
.filter(c => c.meta?.sidebar !== false)
|
|
169
|
+
.map(c => mapNode(c)),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
|
|
150
175
|
const fn = (node: Record<string, any>) => node.path === path;
|
|
151
176
|
const list = [...breadcrumbTree.value];
|
|
152
177
|
let currentNode;
|
|
153
|
-
|
|
154
178
|
for (const node of list) {
|
|
155
179
|
if (fn(node)) {
|
|
156
180
|
currentNode = node;
|
|
157
181
|
break;
|
|
158
182
|
}
|
|
159
|
-
|
|
160
183
|
if (node?.children) {
|
|
161
184
|
list.push(...node.children);
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
|
-
|
|
165
187
|
return currentNode ?? {};
|
|
166
188
|
}
|
|
167
189
|
|
|
@@ -169,16 +191,16 @@ function getCurrentBreadcrumb(path: string) {
|
|
|
169
191
|
* 点击面包屑的下拉树节点
|
|
170
192
|
*/
|
|
171
193
|
function onSelect(node: RouteRecordRaw, index: number) {
|
|
172
|
-
if (!node
|
|
194
|
+
if (!node) {
|
|
173
195
|
return;
|
|
174
196
|
}
|
|
175
197
|
|
|
176
|
-
if (
|
|
198
|
+
if (index === (breadcrumbList.value.length - 1)) {
|
|
177
199
|
return;
|
|
178
200
|
}
|
|
179
201
|
|
|
180
|
-
if (!node?.children?.length) {
|
|
181
|
-
router.push(pathCompile(node
|
|
202
|
+
if (!node?.children?.length && node.path) {
|
|
203
|
+
router.push(pathCompile(node.path));
|
|
182
204
|
}
|
|
183
205
|
}
|
|
184
206
|
</script>
|
|
@@ -218,7 +240,7 @@ function onSelect(node: RouteRecordRaw, index: number) {
|
|
|
218
240
|
>
|
|
219
241
|
<HDropdownTree
|
|
220
242
|
:item="getCurrentBreadcrumb(item.path)"
|
|
221
|
-
:disabled="
|
|
243
|
+
:disabled="(index === breadcrumbList.length - 1) || getCurrentBreadcrumb(item.path)?.children?.length <= 1"
|
|
222
244
|
@select="onSelect($event, index)"
|
|
223
245
|
>
|
|
224
246
|
<span class="flex items-center gap-0.5">
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { DropdownMenu } from '../Tools/interface';
|
|
2
3
|
import { PubinfoIcon } from '@/features/components';
|
|
3
4
|
|
|
4
5
|
const props = defineProps<{
|
|
5
|
-
items:
|
|
6
|
-
icon?: string
|
|
7
|
-
label: string
|
|
8
|
-
disabled?: boolean
|
|
9
|
-
hide?: boolean
|
|
10
|
-
handle?: () => void
|
|
11
|
-
}[][]
|
|
6
|
+
items: DropdownMenu[]
|
|
12
7
|
}>();
|
|
13
8
|
|
|
14
9
|
const myItems = computed(() => {
|
|
15
|
-
return props.items.
|
|
16
|
-
return item.filter(v => !v.hide);
|
|
17
|
-
}).filter(v => v.length);
|
|
10
|
+
return props.items.filter(item => !item?.hide);
|
|
18
11
|
});
|
|
19
12
|
</script>
|
|
20
13
|
|
|
@@ -27,23 +20,23 @@ const myItems = computed(() => {
|
|
|
27
20
|
:auto-hide="false"
|
|
28
21
|
>
|
|
29
22
|
<slot />
|
|
23
|
+
|
|
30
24
|
<template #popper>
|
|
31
|
-
<div
|
|
32
|
-
v-for="(item, index) in myItems"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</button>
|
|
25
|
+
<div class="dark:bg-[var(--g-container-bg)] py-1">
|
|
26
|
+
<template v-for="(item, index) in myItems" :key="index">
|
|
27
|
+
<div v-if="item?.key === 'divider'" border-b="~ solid stone-2 dark:stone-7 last:size-0" class="my-1" />
|
|
28
|
+
|
|
29
|
+
<div v-else class="px-1">
|
|
30
|
+
<button
|
|
31
|
+
:disabled="item.disabled"
|
|
32
|
+
class="w-full flex cursor-pointer items-center gap-2 border-size-0 rounded-md bg-inherit px-2 py-1.5 text-sm text-dark disabled:cursor-not-allowed dark:text-white disabled:opacity-50 hover:not-disabled:bg-stone-1 dark:hover:not-disabled:bg-stone-9"
|
|
33
|
+
@click="item?.onClick"
|
|
34
|
+
>
|
|
35
|
+
<PubinfoIcon v-if="item?.icon" :name="item.icon" />
|
|
36
|
+
{{ item?.label }}
|
|
37
|
+
</button>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
47
40
|
</div>
|
|
48
41
|
</template>
|
|
49
42
|
</VMenu>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useContext } from './useContext';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 获取指定元素的计算样式属性值
|
|
@@ -17,8 +17,7 @@ type unit = `${string}px`;
|
|
|
17
17
|
* @returns 包含主侧边栏和子侧边栏实际宽度的计算属性对象。
|
|
18
18
|
*/
|
|
19
19
|
export function useGetSidebarActualWidth() {
|
|
20
|
-
const settingsStore =
|
|
21
|
-
const menuStore = useMenuStore();
|
|
20
|
+
const { settingsStore, menuStore } = useContext();
|
|
22
21
|
|
|
23
22
|
const mainSidebarActualWidth = computed<unit>(() => {
|
|
24
23
|
const menuMode = settingsStore.settings.menu.menuMode;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
|
|
3
|
+
type SearchType = 'menu' | 'tab';
|
|
4
|
+
|
|
5
|
+
const isShow = ref(false);
|
|
6
|
+
const searchType = ref<SearchType>('menu');
|
|
7
|
+
|
|
8
|
+
function open(type?: SearchType) {
|
|
9
|
+
if (type) {
|
|
10
|
+
searchType.value = type;
|
|
11
|
+
}
|
|
12
|
+
isShow.value = true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function close() {
|
|
16
|
+
isShow.value = false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function toggle(type?: SearchType) {
|
|
20
|
+
if (!isShow.value) {
|
|
21
|
+
if (type) {
|
|
22
|
+
searchType.value = type;
|
|
23
|
+
}
|
|
24
|
+
isShow.value = true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
isShow.value = false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 全局搜索服务
|
|
33
|
+
* 可以支持多处挂载,只需要使用 `useGlobalSearch` 开启即可
|
|
34
|
+
* 这样可以避免如果使用快捷键可能会多处开启 search 的问题
|
|
35
|
+
*
|
|
36
|
+
* close [#38](https://github.com/wsypower/pubinfo/issues/38)
|
|
37
|
+
*/
|
|
38
|
+
export function useGlobalSearch() {
|
|
39
|
+
return {
|
|
40
|
+
isShow,
|
|
41
|
+
searchType,
|
|
42
|
+
open,
|
|
43
|
+
close,
|
|
44
|
+
toggle,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type { SearchType };
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import type { useMenuStore, useSettingsStore } from '@/features/stores';
|
|
2
1
|
import hotkeys from 'hotkeys-js';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { useContext } from './useContext';
|
|
3
|
+
import { useMainPage } from './useMainPage';
|
|
4
|
+
import { useMenu } from './useMenu';
|
|
5
|
+
|
|
6
|
+
export function useHotkey() {
|
|
7
|
+
const { settingsStore, menuStore } = useContext();
|
|
5
8
|
|
|
6
|
-
export function useHotkey({
|
|
7
|
-
menuStore,
|
|
8
|
-
settingsStore,
|
|
9
|
-
}: {
|
|
10
|
-
menuStore: ReturnType<typeof useMenuStore>
|
|
11
|
-
settingsStore: ReturnType<typeof useSettingsStore>
|
|
12
|
-
}) {
|
|
13
9
|
const mainPage = useMainPage();
|
|
14
10
|
const menu = useMenu();
|
|
15
11
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import useTabbar from './useTabbar';
|
|
1
|
+
import { useContext } from './useContext';
|
|
2
|
+
import { useTabbar } from './useTabbar';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 用于主页面功能的自定义钩子。
|
|
@@ -9,13 +9,12 @@ import useTabbar from './useTabbar';
|
|
|
9
9
|
* - resetCustomTitle: 重置当前页面的自定义标题。
|
|
10
10
|
* - maximize: 设置主页面的最大化状态。
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
12
|
+
export function useMainPage() {
|
|
13
|
+
const { settingsStore, tabbarStore } = useContext();
|
|
14
|
+
|
|
13
15
|
const route = useRoute();
|
|
14
16
|
const router = useRouter();
|
|
15
17
|
|
|
16
|
-
const settingsStore = useSettingsStore();
|
|
17
|
-
const tabbarStore = useTabbarStore();
|
|
18
|
-
|
|
19
18
|
const tabbar = useTabbar();
|
|
20
19
|
|
|
21
20
|
/**
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import type { Menu } from '#/menu';
|
|
2
2
|
import { message } from 'ant-design-vue';
|
|
3
|
-
import {
|
|
3
|
+
import { useContext } from './useContext';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 用于管理菜单功能的自定义组合函数。
|
|
7
7
|
* @returns 一个包含 `switchTo` 函数的对象。
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export function useMenu() {
|
|
10
|
+
const { settingsStore, menuStore } = useContext();
|
|
10
11
|
const router = useRouter();
|
|
11
12
|
|
|
12
|
-
const settingsStore = useSettingsStore();
|
|
13
|
-
const menuStore = useMenuStore();
|
|
14
|
-
|
|
15
13
|
function switchTo(index: number | string, mainRouter?: Menu.recordMainRaw) {
|
|
16
14
|
if (mainRouter && mainRouter.meta?.isDev) {
|
|
17
15
|
message.info('暂未上线,敬请期待!');
|