mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-10-01 23:56:40 +08:00
feat(layouts): 添加菜单反转模式来增加对比度
This commit is contained in:
parent
20347b7d65
commit
caf4804565
18
components.d.ts
vendored
18
components.d.ts
vendored
@ -13,17 +13,9 @@ declare module 'vue' {
|
|||||||
IconAntDesignCloseOutlined: typeof import('~icons/ant-design/close-outlined')['default']
|
IconAntDesignCloseOutlined: typeof import('~icons/ant-design/close-outlined')['default']
|
||||||
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
||||||
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
||||||
IconCustomActivity: typeof import('~icons/custom/activity')['default']
|
|
||||||
IconCustomAvatar: typeof import('~icons/custom/avatar')['default']
|
IconCustomAvatar: typeof import('~icons/custom/avatar')['default']
|
||||||
IconCustomBanner: typeof import('~icons/custom/banner')['default']
|
|
||||||
IconCustomCast: typeof import('~icons/custom/cast')['default']
|
|
||||||
IconCustomEmptyData: typeof import('~icons/custom/empty-data')['default']
|
|
||||||
IconCustomLogo: typeof import('~icons/custom/logo')['default']
|
IconCustomLogo: typeof import('~icons/custom/logo')['default']
|
||||||
IconCustomLogoFill: typeof import('~icons/custom/logo-fill')['default']
|
IconCustomLogoFill: typeof import('~icons/custom/logo-fill')['default']
|
||||||
IconCustomNetworkError: typeof import('~icons/custom/network-error')['default']
|
|
||||||
IconCustomNoPermission: typeof import('~icons/custom/no-permission')['default']
|
|
||||||
IconCustomNotFound: typeof import('~icons/custom/not-found')['default']
|
|
||||||
IconCustomServiceError: typeof import('~icons/custom/service-error')['default']
|
|
||||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||||
IconIcOutlineCheck: typeof import('~icons/ic/outline-check')['default']
|
IconIcOutlineCheck: typeof import('~icons/ic/outline-check')['default']
|
||||||
@ -55,8 +47,6 @@ declare module 'vue' {
|
|||||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||||
NDataTable: typeof import('naive-ui')['NDataTable']
|
NDataTable: typeof import('naive-ui')['NDataTable']
|
||||||
NDescriptions: typeof import('naive-ui')['NDescriptions']
|
|
||||||
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
|
|
||||||
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||||
NDivider: typeof import('naive-ui')['NDivider']
|
NDivider: typeof import('naive-ui')['NDivider']
|
||||||
NDrawer: typeof import('naive-ui')['NDrawer']
|
NDrawer: typeof import('naive-ui')['NDrawer']
|
||||||
@ -69,26 +59,18 @@ declare module 'vue' {
|
|||||||
NGrid: typeof import('naive-ui')['NGrid']
|
NGrid: typeof import('naive-ui')['NGrid']
|
||||||
NGridItem: typeof import('naive-ui')['NGridItem']
|
NGridItem: typeof import('naive-ui')['NGridItem']
|
||||||
NInput: typeof import('naive-ui')['NInput']
|
NInput: typeof import('naive-ui')['NInput']
|
||||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
|
||||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||||
NList: typeof import('naive-ui')['NList']
|
|
||||||
NListItem: typeof import('naive-ui')['NListItem']
|
|
||||||
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
||||||
NMenu: typeof import('naive-ui')['NMenu']
|
NMenu: typeof import('naive-ui')['NMenu']
|
||||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||||
NModal: typeof import('naive-ui')['NModal']
|
NModal: typeof import('naive-ui')['NModal']
|
||||||
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||||
NPopover: typeof import('naive-ui')['NPopover']
|
|
||||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
NSelect: typeof import('naive-ui')['NSelect']
|
NSelect: typeof import('naive-ui')['NSelect']
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
NSpin: typeof import('naive-ui')['NSpin']
|
|
||||||
NStatistic: typeof import('naive-ui')['NStatistic']
|
|
||||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||||
NTabs: typeof import('naive-ui')['NTabs']
|
NTabs: typeof import('naive-ui')['NTabs']
|
||||||
NTag: typeof import('naive-ui')['NTag']
|
|
||||||
NThing: typeof import('naive-ui')['NThing']
|
|
||||||
NTimeline: typeof import('naive-ui')['NTimeline']
|
NTimeline: typeof import('naive-ui')['NTimeline']
|
||||||
NTimelineItem: typeof import('naive-ui')['NTimelineItem']
|
NTimelineItem: typeof import('naive-ui')['NTimelineItem']
|
||||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||||
|
17890
package-lock.json
generated
Normal file
17890
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="bg-white text-[#333639] dark:(bg-[#18181c] text-white text-opacity-82) transition-all duration-300 ease-in-out"
|
class="dark:(bg-[#18181c] text-white text-opacity-82) transition-all duration-300 ease-in-out"
|
||||||
|
:class="invertedClass"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
inverted?: boolean;
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
inverted: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const invertedClass = computed(() => (props.inverted ? 'bg-[#001428] text-white' : 'bg-white text-[#333639]'));
|
||||||
|
</script>
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<hover-container class="w-40px h-full" tooltip-content="全屏" @click="toggle">
|
<hover-container class="w-40px h-full" tooltip-content="全屏" content-class="hover:text-primary" @click="toggle">
|
||||||
<icon-gridicons-fullscreen-exit v-if="isFullscreen" class="text-18px" />
|
<icon-gridicons-fullscreen-exit v-if="isFullscreen" class="text-18px" />
|
||||||
<icon-gridicons-fullscreen v-else class="text-18px" />
|
<icon-gridicons-fullscreen v-else class="text-18px" />
|
||||||
</hover-container>
|
</hover-container>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<hover-container tooltip-content="github" class="w-40px h-full">
|
<hover-container tooltip-content="github" content-class="hover:text-primary" class="w-40px h-full">
|
||||||
<a href="https://github.com/honghuangdc/soybean-admin" target="_blank" class="flex-center">
|
<a href="https://github.com/honghuangdc/soybean-admin" target="_blank" class="flex-center">
|
||||||
<icon-mdi-github class="text-20px text-[#666]" />
|
<icon-mdi-github class="text-20px" />
|
||||||
</a>
|
</a>
|
||||||
</hover-container>
|
</hover-container>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-menu :value="activeKey" mode="horizontal" :options="menus" @update:value="handleUpdateMenu" />
|
<n-menu
|
||||||
|
:value="activeKey"
|
||||||
|
mode="horizontal"
|
||||||
|
:options="menus"
|
||||||
|
:inverted="theme.layout.inverted"
|
||||||
|
@update:value="handleUpdateMenu"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import type { MenuOption } from 'naive-ui';
|
import type { MenuOption } from 'naive-ui';
|
||||||
import { useRouteStore } from '@/store';
|
import { useRouteStore, useThemeStore } from '@/store';
|
||||||
import { useRouterPush } from '@/composables';
|
import { useRouterPush } from '@/composables';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
|
const theme = useThemeStore();
|
||||||
const { routerPush } = useRouterPush();
|
const { routerPush } = useRouterPush();
|
||||||
|
|
||||||
const menus = computed(() => routeStore.menus as GlobalMenuOption[]);
|
const menus = computed(() => routeStore.menus as GlobalMenuOption[]);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-dropdown :options="options" @select="handleDropdown">
|
<n-dropdown :options="options" @select="handleDropdown">
|
||||||
<hover-container class="px-12px">
|
<hover-container class="px-12px" content-class="hover:text-primary">
|
||||||
<icon-custom-avatar class="text-32px" />
|
<icon-custom-avatar class="text-32px" />
|
||||||
<span class="pl-8px text-16px font-medium">{{ auth.userInfo.userName }}</span>
|
<span class="pl-8px text-16px font-medium">{{ auth.userInfo.userName }}</span>
|
||||||
</hover-container>
|
</hover-container>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<dark-mode-container class="global-header flex-y-center h-full">
|
<dark-mode-container class="global-header flex-y-center h-full" :inverted="inverted">
|
||||||
<global-logo v-if="showLogo" :show-title="true" class="h-full" :style="{ width: theme.sider.width + 'px' }" />
|
<global-logo v-if="showLogo" :show-title="true" class="h-full" :style="{ width: theme.sider.width + 'px' }" />
|
||||||
<div v-if="!showHeaderMenu" class="flex-1-hidden flex-y-center h-full">
|
<div v-if="!showHeaderMenu" class="flex-1-hidden flex-y-center h-full">
|
||||||
<menu-collapse v-if="showMenuCollapse" />
|
<menu-collapse v-if="showMenuCollapse" />
|
||||||
@ -19,6 +19,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
import { useThemeStore } from '@/store';
|
import { useThemeStore } from '@/store';
|
||||||
import GlobalLogo from '../GlobalLogo/index.vue';
|
import GlobalLogo from '../GlobalLogo/index.vue';
|
||||||
import GlobalSearch from '../GlobalSearch/index.vue';
|
import GlobalSearch from '../GlobalSearch/index.vue';
|
||||||
@ -44,6 +45,8 @@ interface Props {
|
|||||||
defineProps<Props>();
|
defineProps<Props>();
|
||||||
|
|
||||||
const theme = useThemeStore();
|
const theme = useThemeStore();
|
||||||
|
|
||||||
|
const inverted = computed(() => theme.layout.inverted && theme.layout.mode.includes('horizontal'));
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.global-header {
|
.global-header {
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<hover-container tooltip-content="搜索" class="w-40px h-full" @click="handleSearch">
|
<hover-container
|
||||||
<icon-uil-search class="text-20px text-[#666]" />
|
tooltip-content="搜索"
|
||||||
|
class="w-40px h-full"
|
||||||
|
content-class="hover:text-primary"
|
||||||
|
@click="handleSearch"
|
||||||
|
>
|
||||||
|
<icon-uil-search class="text-20px" />
|
||||||
</hover-container>
|
</hover-container>
|
||||||
<search-modal v-model:value="show" />
|
<search-modal v-model:value="show" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<dark-mode-container class="flex h-full" @mouseleave="resetFirstDegreeMenus">
|
<dark-mode-container class="flex h-full" :inverted="inverted" @mouseleave="resetFirstDegreeMenus">
|
||||||
<div class="flex-1 flex-col-stretch h-full">
|
<div class="flex-1 flex-col-stretch h-full">
|
||||||
<global-logo :show-title="false" :style="{ height: theme.header.height + 'px' }" />
|
<global-logo :show-title="false" :style="{ height: theme.header.height + 'px' }" />
|
||||||
<n-scrollbar class="flex-1-hidden">
|
<n-scrollbar class="flex-1-hidden">
|
||||||
@ -93,6 +93,8 @@ const activeChildMenus = computed(() => {
|
|||||||
return menus;
|
return menus;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const inverted = computed(() => theme.layout.inverted);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.name,
|
() => route.name,
|
||||||
() => {
|
() => {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
:options="routeStore.menus"
|
:options="routeStore.menus"
|
||||||
:expanded-keys="expandedKeys"
|
:expanded-keys="expandedKeys"
|
||||||
:indent="18"
|
:indent="18"
|
||||||
|
:inverted="inverted"
|
||||||
@update:value="handleUpdateMenu"
|
@update:value="handleUpdateMenu"
|
||||||
@update:expanded-keys="handleUpdateExpandedKeys"
|
@update:expanded-keys="handleUpdateExpandedKeys"
|
||||||
/>
|
/>
|
||||||
@ -30,6 +31,7 @@ const { routerPush } = useRouterPush();
|
|||||||
|
|
||||||
const activeKey = computed(() => route.name as string);
|
const activeKey = computed(() => route.name as string);
|
||||||
const expandedKeys = ref<string[]>([]);
|
const expandedKeys = ref<string[]>([]);
|
||||||
|
const inverted = computed(() => theme.layout.inverted && theme.layout.mode === 'vertical');
|
||||||
|
|
||||||
function handleUpdateMenu(_key: string, item: MenuOption) {
|
function handleUpdateMenu(_key: string, item: MenuOption) {
|
||||||
const menuItem = item as GlobalMenuOption;
|
const menuItem = item as GlobalMenuOption;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<dark-mode-container class="flex-col-stretch h-full">
|
<dark-mode-container class="flex-col-stretch h-full" :inverted="inverted">
|
||||||
<global-logo v-if="!isHorizontalMix" :show-title="showTitle" :style="{ height: theme.header.height + 'px' }" />
|
<global-logo v-if="!isHorizontalMix" :show-title="showTitle" :style="{ height: theme.header.height + 'px' }" />
|
||||||
<vertical-menu />
|
<vertical-menu />
|
||||||
</dark-mode-container>
|
</dark-mode-container>
|
||||||
@ -16,5 +16,6 @@ const theme = useThemeStore();
|
|||||||
|
|
||||||
const isHorizontalMix = computed(() => theme.layout.mode === 'horizontal-mix');
|
const isHorizontalMix = computed(() => theme.layout.mode === 'horizontal-mix');
|
||||||
const showTitle = computed(() => !app.siderCollapse && theme.layout.mode !== 'vertical-mix');
|
const showTitle = computed(() => !app.siderCollapse && theme.layout.mode !== 'vertical-mix');
|
||||||
|
const inverted = computed(() => theme.layout.inverted && theme.layout.mode === 'vertical');
|
||||||
</script>
|
</script>
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-divider title-placement="center">界面功能</n-divider>
|
<n-divider title-placement="center">界面功能</n-divider>
|
||||||
<n-space vertical size="large">
|
<n-space vertical size="large">
|
||||||
|
<setting-menu label="菜单反转色">
|
||||||
|
<n-switch :value="theme.layout.inverted" @update:value="theme.setInvertedMode" />
|
||||||
|
</setting-menu>
|
||||||
<setting-menu label="固定头部和多页签">
|
<setting-menu label="固定头部和多页签">
|
||||||
<n-switch :value="theme.fixedHeaderAndTab" @update:value="theme.setIsFixedHeaderAndTab" />
|
<n-switch :value="theme.fixedHeaderAndTab" @update:value="theme.setIsFixedHeaderAndTab" />
|
||||||
</setting-menu>
|
</setting-menu>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"darkMode": false,
|
"darkMode": false,
|
||||||
"layout": {
|
"layout": {
|
||||||
"minWidth": 900,
|
"minWidth": 900,
|
||||||
|
"inverted": false,
|
||||||
"mode": "vertical",
|
"mode": "vertical",
|
||||||
"modeList": [
|
"modeList": [
|
||||||
{
|
{
|
||||||
|
@ -33,6 +33,7 @@ const defaultThemeSetting: Theme.Setting = {
|
|||||||
layout: {
|
layout: {
|
||||||
minWidth: 900,
|
minWidth: 900,
|
||||||
mode: 'vertical',
|
mode: 'vertical',
|
||||||
|
inverted: false,
|
||||||
modeList: [
|
modeList: [
|
||||||
{ value: 'vertical', label: EnumThemeLayoutMode.vertical },
|
{ value: 'vertical', label: EnumThemeLayoutMode.vertical },
|
||||||
{ value: 'vertical-mix', label: EnumThemeLayoutMode['vertical-mix'] },
|
{ value: 'vertical-mix', label: EnumThemeLayoutMode['vertical-mix'] },
|
||||||
|
@ -38,6 +38,10 @@ export const useThemeStore = defineStore('theme-store', {
|
|||||||
setLayoutMode(mode: EnumType.ThemeLayoutMode) {
|
setLayoutMode(mode: EnumType.ThemeLayoutMode) {
|
||||||
this.layout.mode = mode;
|
this.layout.mode = mode;
|
||||||
},
|
},
|
||||||
|
/** 切换菜单反转模式 */
|
||||||
|
setInvertedMode(isInverted: boolean) {
|
||||||
|
this.layout.inverted = isInverted;
|
||||||
|
},
|
||||||
/** 设置系统主题颜色 */
|
/** 设置系统主题颜色 */
|
||||||
setThemeColor(themeColor: string) {
|
setThemeColor(themeColor: string) {
|
||||||
this.themeColor = themeColor;
|
this.themeColor = themeColor;
|
||||||
|
2
src/typings/system.d.ts
vendored
2
src/typings/system.d.ts
vendored
@ -125,6 +125,8 @@ declare namespace Theme {
|
|||||||
minWidth: number;
|
minWidth: number;
|
||||||
/** 布局模式 */
|
/** 布局模式 */
|
||||||
mode: EnumType.ThemeLayoutMode;
|
mode: EnumType.ThemeLayoutMode;
|
||||||
|
/** 菜单反转增加对比 */
|
||||||
|
inverted: boolean;
|
||||||
/** 布局模式列表 */
|
/** 布局模式列表 */
|
||||||
modeList: LayoutModeList[];
|
modeList: LayoutModeList[];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user