Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben/layouts",
|
||||
"version": "5.0.1",
|
||||
"version": "5.1.0",
|
||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||
"repository": {
|
||||
|
@@ -10,7 +10,7 @@ import { RouterView } from 'vue-router';
|
||||
import { useContentHeight } from '@vben/hooks';
|
||||
import { preferences, usePreferences } from '@vben/preferences';
|
||||
import { storeToRefs, useTabbarStore } from '@vben/stores';
|
||||
import { Spinner } from '@vben-core/shadcn-ui';
|
||||
import { VbenSpinner } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { IFrameRouterView } from '../../iframe';
|
||||
import { useContentSpinner } from './use-content-spinner';
|
||||
@@ -86,7 +86,7 @@ function transformComponent(
|
||||
|
||||
<template>
|
||||
<div class="relative h-full">
|
||||
<Spinner
|
||||
<VbenSpinner
|
||||
v-if="preferences.transition.loading"
|
||||
:spinning="spinning"
|
||||
:style="contentStyles"
|
||||
|
@@ -5,7 +5,12 @@ import { preferences, usePreferences } from '@vben/preferences';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
import { VbenFullScreen } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { GlobalSearch, LanguageToggle, ThemeToggle } from '../../widgets';
|
||||
import {
|
||||
GlobalSearch,
|
||||
LanguageToggle,
|
||||
PreferencesButton,
|
||||
ThemeToggle,
|
||||
} from '../../widgets';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
@@ -26,34 +31,44 @@ const accessStore = useAccessStore();
|
||||
const { globalSearchShortcutKey } = usePreferences();
|
||||
const slots = useSlots();
|
||||
const rightSlots = computed(() => {
|
||||
const list = [{ index: 30, name: 'user-dropdown' }];
|
||||
const list = [{ index: 100, name: 'user-dropdown' }];
|
||||
if (preferences.widget.globalSearch) {
|
||||
list.push({
|
||||
index: 5,
|
||||
name: 'global-search',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.themeToggle) {
|
||||
|
||||
if (
|
||||
preferences.app.enablePreferences &&
|
||||
preferences.app.preferencesButtonPosition === 'header'
|
||||
) {
|
||||
list.push({
|
||||
index: 10,
|
||||
name: 'preferences',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.themeToggle) {
|
||||
list.push({
|
||||
index: 15,
|
||||
name: 'theme-toggle',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.languageToggle) {
|
||||
list.push({
|
||||
index: 15,
|
||||
index: 20,
|
||||
name: 'language-toggle',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.fullscreen) {
|
||||
list.push({
|
||||
index: 20,
|
||||
index: 25,
|
||||
name: 'fullscreen',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.notification) {
|
||||
list.push({
|
||||
index: 25,
|
||||
index: 30,
|
||||
name: 'notification',
|
||||
});
|
||||
}
|
||||
@@ -66,6 +81,7 @@ const rightSlots = computed(() => {
|
||||
});
|
||||
return list.sort((a, b) => a.index - b.index);
|
||||
});
|
||||
|
||||
const leftSlots = computed(() => {
|
||||
const list: any[] = [];
|
||||
|
||||
@@ -108,8 +124,12 @@ const leftSlots = computed(() => {
|
||||
class="mr-4"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-else-if="slot.name === 'preferences'">
|
||||
<PreferencesButton class="mr-2" />
|
||||
</template>
|
||||
<template v-else-if="slot.name === 'theme-toggle'">
|
||||
<ThemeToggle class="mr-2" />
|
||||
<ThemeToggle class="mr-2 mt-[2px]" />
|
||||
</template>
|
||||
<template v-else-if="slot.name === 'language-toggle'">
|
||||
<LanguageToggle class="mr-2" />
|
||||
|
@@ -41,17 +41,19 @@ const {
|
||||
isSideMixedNav,
|
||||
layout,
|
||||
sidebarCollapsed,
|
||||
theme,
|
||||
} = usePreferences();
|
||||
const userStore = useUserStore();
|
||||
const { updateWatermark } = useWatermark();
|
||||
const lockStore = useLockStore();
|
||||
|
||||
const headerMenuTheme = computed(() => {
|
||||
return isDark.value ? 'dark' : 'light';
|
||||
const sidebarTheme = computed(() => {
|
||||
const dark = isDark.value || preferences.theme.semiDarkSidebar;
|
||||
return dark ? 'dark' : 'light';
|
||||
});
|
||||
|
||||
const theme = computed(() => {
|
||||
const dark = isDark.value || preferences.theme.semiDarkMenu;
|
||||
const headerTheme = computed(() => {
|
||||
const dark = isDark.value || preferences.theme.semiDarkHeader;
|
||||
return dark ? 'dark' : 'light';
|
||||
});
|
||||
|
||||
@@ -160,6 +162,7 @@ const headerSlots = computed(() => {
|
||||
:footer-fixed="preferences.footer.fixed"
|
||||
:header-hidden="preferences.header.hidden"
|
||||
:header-mode="preferences.header.mode"
|
||||
:header-theme="headerTheme"
|
||||
:header-toggle-sidebar-button="preferences.widget.sidebarToggle"
|
||||
:header-visible="preferences.header.enable"
|
||||
:is-mobile="preferences.app.isMobile"
|
||||
@@ -170,8 +173,7 @@ const headerSlots = computed(() => {
|
||||
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
|
||||
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
|
||||
:sidebar-hidden="preferences.sidebar.hidden"
|
||||
:sidebar-semi-dark="preferences.theme.semiDarkMenu"
|
||||
:sidebar-theme="theme"
|
||||
:sidebar-theme="sidebarTheme"
|
||||
:sidebar-width="preferences.sidebar.width"
|
||||
:tabbar-enable="preferences.tabbar.enable"
|
||||
:tabbar-height="preferences.tabbar.height"
|
||||
@@ -192,14 +194,6 @@ const headerSlots = computed(() => {
|
||||
updatePreferences({ sidebar: { extraCollapse: value } })
|
||||
"
|
||||
>
|
||||
<template v-if="preferences.app.enablePreferences" #preferences>
|
||||
<Preferences @clear-preferences-and-logout="clearPreferencesAndLogout" />
|
||||
</template>
|
||||
|
||||
<template #floating-groups>
|
||||
<VbenBackTop />
|
||||
</template>
|
||||
|
||||
<!-- logo -->
|
||||
<template #logo>
|
||||
<VbenLogo
|
||||
@@ -208,7 +202,7 @@ const headerSlots = computed(() => {
|
||||
:collapsed="logoCollapsed"
|
||||
:src="preferences.logo.source"
|
||||
:text="preferences.app.name"
|
||||
:theme="showHeaderNav ? headerMenuTheme : theme"
|
||||
:theme="showHeaderNav ? headerTheme : theme"
|
||||
/>
|
||||
</template>
|
||||
<!-- 头部区域 -->
|
||||
@@ -230,7 +224,7 @@ const headerSlots = computed(() => {
|
||||
:default-active="headerActive"
|
||||
:menus="wrapperMenus(headerMenus)"
|
||||
:rounded="isMenuRounded"
|
||||
:theme="headerMenuTheme"
|
||||
:theme="headerTheme"
|
||||
class="w-full"
|
||||
mode="horizontal"
|
||||
@select="handleMenuSelect"
|
||||
@@ -256,7 +250,7 @@ const headerSlots = computed(() => {
|
||||
:default-active="sidebarActive"
|
||||
:menus="wrapperMenus(sidebarMenus)"
|
||||
:rounded="isMenuRounded"
|
||||
:theme="theme"
|
||||
:theme="sidebarTheme"
|
||||
mode="vertical"
|
||||
@select="handleMenuSelect"
|
||||
/>
|
||||
@@ -267,7 +261,7 @@ const headerSlots = computed(() => {
|
||||
:active-path="extraActiveMenu"
|
||||
:menus="wrapperMenus(headerMenus)"
|
||||
:rounded="isMenuRounded"
|
||||
:theme="theme"
|
||||
:theme="sidebarTheme"
|
||||
@default-select="handleDefaultSelect"
|
||||
@enter="handleMenuMouseEnter"
|
||||
@select="handleMixedMenuSelect"
|
||||
@@ -280,7 +274,7 @@ const headerSlots = computed(() => {
|
||||
:collapse="preferences.sidebar.extraCollapse"
|
||||
:menus="wrapperMenus(extraMenus)"
|
||||
:rounded="isMenuRounded"
|
||||
:theme="theme"
|
||||
:theme="sidebarTheme"
|
||||
/>
|
||||
</template>
|
||||
<template #side-extra-title>
|
||||
@@ -325,6 +319,19 @@ const headerSlots = computed(() => {
|
||||
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
|
||||
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
|
||||
</Transition>
|
||||
|
||||
<template
|
||||
v-if="
|
||||
preferences.app.enablePreferences &&
|
||||
preferences.app.preferencesButtonPosition === 'fixed'
|
||||
"
|
||||
>
|
||||
<Preferences
|
||||
class="z-100 fixed bottom-20 right-0"
|
||||
@clear-preferences-and-logout="clearPreferencesAndLogout"
|
||||
/>
|
||||
</template>
|
||||
<VbenBackTop />
|
||||
</template>
|
||||
</VbenAdminLayout>
|
||||
</template>
|
||||
|
@@ -6,7 +6,7 @@ import { useRoute } from 'vue-router';
|
||||
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useTabbarStore } from '@vben/stores';
|
||||
import { Spinner } from '@vben-core/shadcn-ui';
|
||||
import { VbenSpinner } from '@vben-core/shadcn-ui';
|
||||
|
||||
defineOptions({ name: 'IFrameRouterView' });
|
||||
|
||||
@@ -73,7 +73,7 @@ function showSpinning(index: number) {
|
||||
v-show="routeShow(item)"
|
||||
class="relative size-full"
|
||||
>
|
||||
<Spinner :spinning="showSpinning(index)" />
|
||||
<VbenSpinner :spinning="showSpinning(index)" />
|
||||
<iframe
|
||||
:src="item.meta.iframeSrc as string"
|
||||
class="size-full"
|
||||
|
@@ -54,9 +54,6 @@ const styleItems = computed((): SelectOption[] => [
|
||||
<SwitchItem v-model="tabbarDragable" :disabled="!tabbarEnable">
|
||||
{{ $t('preferences.tabbar.dragable') }}
|
||||
</SwitchItem>
|
||||
<SelectItem v-model="tabbarStyleType" :items="styleItems">
|
||||
{{ $t('preferences.tabbar.styleType.title') }}
|
||||
</SelectItem>
|
||||
<SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable">
|
||||
{{ $t('preferences.tabbar.icon') }}
|
||||
</SwitchItem>
|
||||
@@ -69,4 +66,7 @@ const styleItems = computed((): SelectOption[] => [
|
||||
<SwitchItem v-model="tabbarShowMaximize" :disabled="!tabbarEnable">
|
||||
{{ $t('preferences.tabbar.showMaximize') }}
|
||||
</SwitchItem>
|
||||
<SelectItem v-model="tabbarStyleType" :items="styleItems">
|
||||
{{ $t('preferences.tabbar.styleType.title') }}
|
||||
</SelectItem>
|
||||
</template>
|
||||
|
@@ -1,6 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectOption } from '@vben/types';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SelectItem from '../select-item.vue';
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
@@ -14,6 +19,20 @@ const widgetNotification = defineModel<boolean>('widgetNotification');
|
||||
const widgetThemeToggle = defineModel<boolean>('widgetThemeToggle');
|
||||
const widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');
|
||||
const widgetLockScreen = defineModel<boolean>('widgetLockScreen');
|
||||
const appPreferencesButtonPosition = defineModel<string>(
|
||||
'appPreferencesButtonPosition',
|
||||
);
|
||||
|
||||
const positionItems = computed((): SelectOption[] => [
|
||||
{
|
||||
label: $t('preferences.position.header'),
|
||||
value: 'header',
|
||||
},
|
||||
{
|
||||
label: $t('preferences.position.fixed'),
|
||||
value: 'fixed',
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -38,4 +57,7 @@ const widgetLockScreen = defineModel<boolean>('widgetLockScreen');
|
||||
<SwitchItem v-model="widgetSidebarToggle">
|
||||
{{ $t('preferences.widget.sidebarToggle') }}
|
||||
</SwitchItem>
|
||||
<SelectItem v-model="appPreferencesButtonPosition" :items="positionItems">
|
||||
{{ $t('preferences.position.title') }}
|
||||
</SelectItem>
|
||||
</template>
|
||||
|
@@ -13,9 +13,8 @@ defineOptions({
|
||||
});
|
||||
|
||||
const modelValue = defineModel<string>({ default: 'auto' });
|
||||
const themeSemiDarkMenu = defineModel<boolean>('themeSemiDarkMenu', {
|
||||
default: true,
|
||||
});
|
||||
const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
|
||||
const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
|
||||
|
||||
const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [
|
||||
{
|
||||
@@ -71,11 +70,14 @@ function nameView(name: string) {
|
||||
</template>
|
||||
|
||||
<SwitchItem
|
||||
v-model="themeSemiDarkMenu"
|
||||
v-model="themeSemiDarkSidebar"
|
||||
:disabled="modelValue === 'dark'"
|
||||
class="mt-6"
|
||||
>
|
||||
{{ $t('preferences.theme.darkMenu') }}
|
||||
{{ $t('preferences.theme.darkSidebar') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="themeSemiDarkHeader" :disabled="modelValue === 'dark'">
|
||||
{{ $t('preferences.theme.darkHeader') }}
|
||||
</SwitchItem>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,2 +1,3 @@
|
||||
export { default as Preferences } from './preferences.vue';
|
||||
export { default as PreferencesButton } from './preferences-button.vue';
|
||||
export * from './use-open-preferences';
|
||||
|
@@ -0,0 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { Settings } from '@vben/icons';
|
||||
import { VbenIconButton } from '@vben-core/shadcn-ui';
|
||||
|
||||
import Preferences from './preferences.vue';
|
||||
</script>
|
||||
<template>
|
||||
<Preferences>
|
||||
<VbenIconButton>
|
||||
<Settings class="size-4" />
|
||||
</VbenIconButton>
|
||||
</Preferences>
|
||||
</template>
|
@@ -7,13 +7,14 @@ import type {
|
||||
LayoutHeaderModeType,
|
||||
LayoutType,
|
||||
NavigationStyleType,
|
||||
PreferencesButtonPositionType,
|
||||
ThemeModeType,
|
||||
} from '@vben/types';
|
||||
import type { SegmentedItem } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { Copy, RotateCw, Settings2 } from '@vben/icons';
|
||||
import { Copy, RotateCw, Settings } from '@vben/icons';
|
||||
import { $t, loadLocaleMessages } from '@vben/locales';
|
||||
import {
|
||||
clearPreferencesCache,
|
||||
@@ -63,6 +64,9 @@ const appColorWeakMode = defineModel<boolean>('appColorWeakMode');
|
||||
const appContentCompact = defineModel<ContentCompactType>('appContentCompact');
|
||||
const appWatermark = defineModel<boolean>('appWatermark');
|
||||
const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
|
||||
const appPreferencesButtonPosition = defineModel<PreferencesButtonPositionType>(
|
||||
'appPreferencesButtonPosition',
|
||||
);
|
||||
|
||||
const transitionProgress = defineModel<boolean>('transitionProgress');
|
||||
const transitionName = defineModel<string>('transitionName');
|
||||
@@ -73,7 +77,8 @@ const themeColorPrimary = defineModel<string>('themeColorPrimary');
|
||||
const themeBuiltinType = defineModel<BuiltinThemeType>('themeBuiltinType');
|
||||
const themeMode = defineModel<ThemeModeType>('themeMode');
|
||||
const themeRadius = defineModel<string>('themeRadius');
|
||||
const themeSemiDarkMenu = defineModel<boolean>('themeSemiDarkMenu');
|
||||
const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
|
||||
const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
|
||||
|
||||
const sidebarEnable = defineModel<boolean>('sidebarEnable');
|
||||
const sidebarWidth = defineModel<number>('sidebarWidth');
|
||||
@@ -219,19 +224,21 @@ async function handleReset() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="z-100 fixed right-0 top-1/2">
|
||||
<div>
|
||||
<VbenSheet
|
||||
v-model:open="openPreferences"
|
||||
:description="$t('preferences.subtitle')"
|
||||
:title="$t('preferences.title')"
|
||||
>
|
||||
<template #trigger>
|
||||
<VbenButton
|
||||
:title="$t('preferences.title')"
|
||||
class="bg-primary flex-col-center h-10 w-10 cursor-pointer rounded-l-lg rounded-r-none border-none"
|
||||
>
|
||||
<Settings2 class="size-5" />
|
||||
</VbenButton>
|
||||
<slot name="trigger">
|
||||
<VbenButton
|
||||
:title="$t('preferences.title')"
|
||||
class="bg-primary flex-col-center size-10 cursor-pointer rounded-l-lg rounded-r-none border-none"
|
||||
>
|
||||
<Settings class="size-5" />
|
||||
</VbenButton>
|
||||
</slot>
|
||||
</template>
|
||||
<template #extra>
|
||||
<div class="flex items-center">
|
||||
@@ -274,7 +281,8 @@ async function handleReset() {
|
||||
<Block :title="$t('preferences.theme.title')">
|
||||
<Theme
|
||||
v-model="themeMode"
|
||||
v-model:theme-semi-dark-menu="themeSemiDarkMenu"
|
||||
v-model:theme-semi-dark-header="themeSemiDarkHeader"
|
||||
v-model:theme-semi-dark-sidebar="themeSemiDarkSidebar"
|
||||
/>
|
||||
</Block>
|
||||
<Block :title="$t('preferences.theme.builtin.title')">
|
||||
@@ -356,6 +364,9 @@ async function handleReset() {
|
||||
</Block>
|
||||
<Block :title="$t('preferences.widget.title')">
|
||||
<Widget
|
||||
v-model:app-preferences-button-position="
|
||||
appPreferencesButtonPosition
|
||||
"
|
||||
v-model:widget-fullscreen="widgetFullscreen"
|
||||
v-model:widget-global-search="widgetGlobalSearch"
|
||||
v-model:widget-language-toggle="widgetLanguageToggle"
|
||||
|
@@ -47,5 +47,9 @@ const listen = computed(() => {
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<PreferencesSheet v-bind="attrs" v-on="listen" />
|
||||
<PreferencesSheet v-bind="attrs" v-on="listen">
|
||||
<template #trigger>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</PreferencesSheet>
|
||||
</template>
|
||||
|
Reference in New Issue
Block a user