chore: 新增是否开启首选项导航栏(外观、布局、快捷键、通用)吸顶效果,调整部分样式 (#6804)

This commit is contained in:
zouawen 2025-10-14 06:55:11 +08:00 committed by GitHub
parent 2ce161e585
commit 59097e2466
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 65 additions and 11 deletions

View File

@ -22,6 +22,7 @@ const defaultPreferences: Preferences = {
enableCheckUpdates: true, enableCheckUpdates: true,
enablePreferences: true, enablePreferences: true,
enableRefreshToken: false, enableRefreshToken: false,
enableStickyPreferencesNavigationBar: true,
isMobile: false, isMobile: false,
layout: 'sidebar-nav', layout: 'sidebar-nav',
locale: 'zh-CN', locale: 'zh-CN',

View File

@ -59,6 +59,10 @@ interface AppPreferences {
* @zh_CN refreshToken * @zh_CN refreshToken
*/ */
enableRefreshToken: boolean; enableRefreshToken: boolean;
/**
* @zh_CN
*/
enableStickyPreferencesNavigationBar: boolean;
/** 是否移动端 */ /** 是否移动端 */
isMobile: boolean; isMobile: boolean;
/** 布局方式 */ /** 布局方式 */

View File

@ -35,16 +35,24 @@ const tabsIndicatorStyle = computed(() => {
width: `${(100 / props.tabs.length).toFixed(0)}%`, width: `${(100 / props.tabs.length).toFixed(0)}%`,
}; };
}); });
function activeClass(tab: string): string[] {
return tab === activeTab.value ? ['!font-bold', 'text-primary'] : [];
}
</script> </script>
<template> <template>
<Tabs v-model="activeTab" :default-value="getDefaultValue"> <Tabs v-model="activeTab" :default-value="getDefaultValue">
<TabsList :style="tabsStyle" class="bg-accent relative grid w-full"> <TabsList
:style="tabsStyle"
class="bg-accent !outline-heavy relative grid w-full !outline !outline-2"
>
<TabsIndicator :style="tabsIndicatorStyle" /> <TabsIndicator :style="tabsIndicatorStyle" />
<template v-for="tab in tabs" :key="tab.value"> <template v-for="tab in tabs" :key="tab.value">
<TabsTrigger <TabsTrigger
:value="tab.value" :value="tab.value"
class="z-20 inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium disabled:pointer-events-none disabled:opacity-50" :class="activeClass(tab.value)"
class="hover:text-primary z-20 inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium disabled:pointer-events-none disabled:opacity-50"
> >
{{ tab.label }} {{ tab.label }}
</TabsTrigger> </TabsTrigger>

View File

@ -23,7 +23,7 @@ const forwardedProps = useForwardProps(delegatedProps);
v-bind="forwardedProps" v-bind="forwardedProps"
:class=" :class="
cn( cn(
'absolute bottom-0 left-0 z-10 h-full w-1/2 translate-x-[--radix-tabs-indicator-position] rounded-full px-0 py-1 pr-1 transition-[width,transform] duration-300', 'absolute bottom-0 left-0 z-10 h-full w-1/2 translate-x-[--radix-tabs-indicator-position] rounded-full px-0 py-1 pr-0.5 transition-[width,transform] duration-300',
props.class, props.class,
) )
" "

View File

@ -134,14 +134,14 @@ watch(
<template v-if="theme.type !== 'custom'"> <template v-if="theme.type !== 'custom'">
<div <div
:style="{ backgroundColor: theme.color }" :style="{ backgroundColor: theme.color }"
class="mx-10 my-2 size-5 rounded-md" class="mx-9 my-2 size-5 rounded-md"
></div> ></div>
</template> </template>
<template v-else> <template v-else>
<div class="size-full px-10 py-2" @click.stop="selectColor"> <div class="size-full px-9 py-2" @click.stop="selectColor">
<div class="flex-center relative size-5 rounded-sm"> <div class="flex-center relative size-5 rounded-sm">
<UserRoundPen <UserRoundPen
class="absolute z-10 size-5 opacity-60 group-hover:opacity-100" class="z-1 absolute size-5 opacity-60 group-hover:opacity-100"
/> />
<input <input
ref="colorInput" ref="colorInput"

View File

@ -16,7 +16,7 @@ import type { SegmentedItem } from '@vben-core/shadcn-ui';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Copy, RotateCw } from '@vben/icons'; import { Copy, Pin, PinOff, RotateCw } from '@vben/icons';
import { $t, loadLocaleMessages } from '@vben/locales'; import { $t, loadLocaleMessages } from '@vben/locales';
import { import {
clearPreferencesCache, clearPreferencesCache,
@ -69,6 +69,9 @@ const appContentCompact = defineModel<ContentCompactType>('appContentCompact');
const appWatermark = defineModel<boolean>('appWatermark'); const appWatermark = defineModel<boolean>('appWatermark');
const appWatermarkContent = defineModel<string>('appWatermarkContent'); const appWatermarkContent = defineModel<string>('appWatermarkContent');
const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates'); const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
const appEnableStickyPreferencesNavigationBar = defineModel<boolean>(
'appEnableStickyPreferencesNavigationBar',
);
const appPreferencesButtonPosition = defineModel<PreferencesButtonPositionType>( const appPreferencesButtonPosition = defineModel<PreferencesButtonPositionType>(
'appPreferencesButtonPosition', 'appPreferencesButtonPosition',
); );
@ -241,7 +244,7 @@ async function handleReset() {
<Drawer <Drawer
:description="$t('preferences.subtitle')" :description="$t('preferences.subtitle')"
:title="$t('preferences.title')" :title="$t('preferences.title')"
class="sm:max-w-sm" class="!border-0 sm:max-w-sm"
> >
<template #extra> <template #extra>
<div class="flex items-center"> <div class="flex items-center">
@ -249,18 +252,44 @@ async function handleReset() {
:disabled="!diffPreference" :disabled="!diffPreference"
:tooltip="$t('preferences.resetTip')" :tooltip="$t('preferences.resetTip')"
class="relative" class="relative"
@click="handleReset"
> >
<span <span
v-if="diffPreference" v-if="diffPreference"
class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded" class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
></span> ></span>
<RotateCw class="size-4" @click="handleReset" /> <RotateCw class="size-4" />
</VbenIconButton>
<VbenIconButton
:tooltip="
appEnableStickyPreferencesNavigationBar
? $t('preferences.disableStickyPreferencesNavigationBar')
: $t('preferences.enableStickyPreferencesNavigationBar')
"
class="relative"
@click="
() =>
(appEnableStickyPreferencesNavigationBar =
!appEnableStickyPreferencesNavigationBar)
"
>
<PinOff
v-if="appEnableStickyPreferencesNavigationBar"
class="size-4"
/>
<Pin v-else class="size-4" />
</VbenIconButton> </VbenIconButton>
</div> </div>
</template> </template>
<div class="p-1"> <div>
<VbenSegmented v-model="activeTab" :tabs="tabs"> <VbenSegmented
v-model="activeTab"
:tabs="tabs"
:class="{
'sticky-tabs-header': appEnableStickyPreferencesNavigationBar,
}"
>
<template #general> <template #general>
<Block :title="$t('preferences.general')"> <Block :title="$t('preferences.general')">
<General <General
@ -449,3 +478,11 @@ async function handleReset() {
</Drawer> </Drawer>
</div> </div>
</template> </template>
<style scoped>
:deep(.sticky-tabs-header [role='tablist']) {
position: sticky;
top: -12px;
z-index: 10;
}
</style>

View File

@ -1,6 +1,8 @@
{ {
"title": "Preferences", "title": "Preferences",
"subtitle": "Customize Preferences & Preview in Real Time", "subtitle": "Customize Preferences & Preview in Real Time",
"enableStickyPreferencesNavigationBar": "Enable sticky preferences navigation bar",
"disableStickyPreferencesNavigationBar": "Disable sticky preferences navigation bar",
"resetTip": "Data has changed, click to reset", "resetTip": "Data has changed, click to reset",
"resetTitle": "Reset Preferences", "resetTitle": "Reset Preferences",
"resetSuccess": "Preferences reset successfully", "resetSuccess": "Preferences reset successfully",

View File

@ -1,6 +1,8 @@
{ {
"title": "偏好设置", "title": "偏好设置",
"subtitle": "自定义偏好设置 & 实时预览", "subtitle": "自定义偏好设置 & 实时预览",
"enableStickyPreferencesNavigationBar": "开启首选项导航栏吸顶效果",
"disableStickyPreferencesNavigationBar": "关闭首选项导航栏吸顶效果",
"resetTitle": "重置偏好设置", "resetTitle": "重置偏好设置",
"resetTip": "数据有变化,点击可进行重置", "resetTip": "数据有变化,点击可进行重置",
"resetSuccess": "重置偏好设置成功", "resetSuccess": "重置偏好设置成功",