feat: add useLayoutMode

This commit is contained in:
pany 2024-02-06 15:25:16 +08:00
parent 0a4d896965
commit 02dca40083
9 changed files with 60 additions and 41 deletions

View File

@ -1,11 +1,12 @@
import { getConfigLayout } from "@/utils/cache/local-storage" import { getConfigLayout } from "@/utils/cache/local-storage"
import { LayoutModeEnum } from "@/constants/app-key"
/** 项目配置类型 */ /** 项目配置类型 */
export interface LayoutSettings { export interface LayoutSettings {
/** 是否显示 Settings Panel */ /** 是否显示 Settings Panel */
showSettings: boolean showSettings: boolean
/** 布局模式 */ /** 布局模式 */
layoutMode: "left" | "top" | "left-top" layoutMode: LayoutModeEnum
/** 是否显示标签栏 */ /** 是否显示标签栏 */
showTagsView: boolean showTagsView: boolean
/** 是否显示 Logo */ /** 是否显示 Logo */
@ -34,7 +35,7 @@ export interface LayoutSettings {
/** 默认配置 */ /** 默认配置 */
const defaultSettings: LayoutSettings = { const defaultSettings: LayoutSettings = {
layoutMode: "left", layoutMode: LayoutModeEnum.Left,
showSettings: true, showSettings: true,
showTagsView: true, showTagsView: true,
fixedHeader: true, fixedHeader: true,

View File

@ -4,6 +4,13 @@ export enum DeviceEnum {
Desktop Desktop
} }
/** 布局模式 */
export enum LayoutModeEnum {
Left = "left",
Top = "top",
LeftTop = "left-top"
}
/** 侧边栏打开状态常量 */ /** 侧边栏打开状态常量 */
export const SIDEBAR_OPENED = "opened" export const SIDEBAR_OPENED = "opened"
/** 侧边栏关闭状态常量 */ /** 侧边栏关闭状态常量 */

View File

@ -0,0 +1,16 @@
import { computed } from "vue"
import { useSettingsStore } from "@/store/modules/settings"
import { LayoutModeEnum } from "@/constants/app-key"
const settingsStore = useSettingsStore()
const isLeft = computed(() => settingsStore.layoutMode === LayoutModeEnum.Left)
const isTop = computed(() => settingsStore.layoutMode === LayoutModeEnum.Top)
const isLeftTop = computed(() => settingsStore.layoutMode === LayoutModeEnum.LeftTop)
const setLayoutMode = (mode: LayoutModeEnum) => {
settingsStore.layoutMode = mode
}
export function useLayoutMode() {
return { isLeft, isTop, isLeftTop, setLayoutMode }
}

View File

@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { storeToRefs } from "pinia" import { useLayoutMode } from "@/hooks/useLayoutMode"
import { useSettingsStore } from "@/store/modules/settings"
import logo from "@/assets/layouts/logo.png?url" import logo from "@/assets/layouts/logo.png?url"
import logoText1 from "@/assets/layouts/logo-text-1.png?url" import logoText1 from "@/assets/layouts/logo-text-1.png?url"
import logoText2 from "@/assets/layouts/logo-text-2.png?url" import logoText2 from "@/assets/layouts/logo-text-2.png?url"
@ -13,18 +12,17 @@ const props = withDefaults(defineProps<Props>(), {
collapse: true collapse: true
}) })
const settingsStore = useSettingsStore() const { isLeft, isTop } = useLayoutMode()
const { layoutMode } = storeToRefs(settingsStore)
</script> </script>
<template> <template>
<div class="layout-logo-container" :class="{ collapse: props.collapse, 'layout-mode-top': layoutMode === 'top' }"> <div class="layout-logo-container" :class="{ collapse: props.collapse, 'layout-mode-top': isTop }">
<transition name="layout-logo-fade"> <transition name="layout-logo-fade">
<router-link v-if="props.collapse" key="collapse" to="/"> <router-link v-if="props.collapse" key="collapse" to="/">
<img :src="logo" class="layout-logo" /> <img :src="logo" class="layout-logo" />
</router-link> </router-link>
<router-link v-else key="expand" to="/"> <router-link v-else key="expand" to="/">
<img :src="layoutMode !== 'left' ? logoText2 : logoText1" class="layout-logo-text" /> <img :src="!isLeft ? logoText2 : logoText1" class="layout-logo-text" />
</router-link> </router-link>
</transition> </transition>
</div> </div>

View File

@ -1,5 +1,4 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from "vue"
import { useRouter } from "vue-router" import { useRouter } from "vue-router"
import { storeToRefs } from "pinia" import { storeToRefs } from "pinia"
import { useAppStore } from "@/store/modules/app" import { useAppStore } from "@/store/modules/app"
@ -14,15 +13,15 @@ import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
import Screenfull from "@/components/Screenfull/index.vue" import Screenfull from "@/components/Screenfull/index.vue"
import SearchMenu from "@/components/SearchMenu/index.vue" import SearchMenu from "@/components/SearchMenu/index.vue"
import { useDevice } from "@/hooks/useDevice" import { useDevice } from "@/hooks/useDevice"
import { useLayoutMode } from "@/hooks/useLayoutMode"
const { isMobile } = useDevice() const { isMobile } = useDevice()
const { isTop } = useLayoutMode()
const router = useRouter() const router = useRouter()
const appStore = useAppStore() const appStore = useAppStore()
const userStore = useUserStore() const userStore = useUserStore()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
const { layoutMode, showNotify, showThemeSwitch, showScreenfull, showSearchMenu } = storeToRefs(settingsStore) const { showNotify, showThemeSwitch, showScreenfull, showSearchMenu } = storeToRefs(settingsStore)
const isTop = computed(() => layoutMode.value === "top")
/** 切换侧边栏 */ /** 切换侧边栏 */
const toggleSidebar = () => { const toggleSidebar = () => {

View File

@ -1,20 +1,14 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from "vue" import { useLayoutMode } from "@/hooks/useLayoutMode"
import { storeToRefs } from "pinia" import { LayoutModeEnum } from "@/constants/app-key"
import { useSettingsStore } from "@/store/modules/settings"
const settingsStore = useSettingsStore() const { isLeft, isTop, isLeftTop, setLayoutMode } = useLayoutMode()
const { layoutMode } = storeToRefs(settingsStore)
const isLeft = computed(() => layoutMode.value === "left")
const isTop = computed(() => layoutMode.value === "top")
const isLeftTop = computed(() => layoutMode.value === "left-top")
</script> </script>
<template> <template>
<div class="select-layout-mode"> <div class="select-layout-mode">
<el-tooltip content="左侧模式"> <el-tooltip content="左侧模式">
<el-container class="layout-mode left" :class="{ active: isLeft }" @click="layoutMode = 'left'"> <el-container class="layout-mode left" :class="{ active: isLeft }" @click="setLayoutMode(LayoutModeEnum.Left)">
<el-aside /> <el-aside />
<el-container> <el-container>
<el-header /> <el-header />
@ -23,13 +17,17 @@ const isLeftTop = computed(() => layoutMode.value === "left-top")
</el-container> </el-container>
</el-tooltip> </el-tooltip>
<el-tooltip content="顶部模式"> <el-tooltip content="顶部模式">
<el-container class="layout-mode top" :class="{ active: isTop }" @click="layoutMode = 'top'"> <el-container class="layout-mode top" :class="{ active: isTop }" @click="setLayoutMode(LayoutModeEnum.Top)">
<el-header /> <el-header />
<el-main /> <el-main />
</el-container> </el-container>
</el-tooltip> </el-tooltip>
<el-tooltip content="混合模式"> <el-tooltip content="混合模式">
<el-container class="layout-mode left-top" :class="{ active: isLeftTop }" @click="layoutMode = 'left-top'"> <el-container
class="layout-mode left-top"
:class="{ active: isLeftTop }"
@click="setLayoutMode(LayoutModeEnum.LeftTop)"
>
<el-header /> <el-header />
<el-container> <el-container>
<el-aside /> <el-aside />

View File

@ -2,15 +2,16 @@
import { watchEffect } from "vue" import { watchEffect } from "vue"
import { storeToRefs } from "pinia" import { storeToRefs } from "pinia"
import { useSettingsStore } from "@/store/modules/settings" import { useSettingsStore } from "@/store/modules/settings"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import { resetConfigLayout } from "@/utils" import { resetConfigLayout } from "@/utils"
import SelectLayoutMode from "./SelectLayoutMode.vue" import SelectLayoutMode from "./SelectLayoutMode.vue"
import { Refresh } from "@element-plus/icons-vue" import { Refresh } from "@element-plus/icons-vue"
const { isLeft } = useLayoutMode()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
/** 使用 storeToRefs 将提取的属性保持其响应性 */ /** 使用 storeToRefs 将提取的属性保持其响应性 */
const { const {
layoutMode,
showTagsView, showTagsView,
showLogo, showLogo,
fixedHeader, fixedHeader,
@ -43,7 +44,7 @@ const switchSettings = {
/** 非左侧模式时Header 都是 fixed 布局 */ /** 非左侧模式时Header 都是 fixed 布局 */
watchEffect(() => { watchEffect(() => {
layoutMode.value !== "left" && (fixedHeader.value = true) isLeft.value && (fixedHeader.value = true)
}) })
</script> </script>
@ -55,7 +56,7 @@ watchEffect(() => {
<h4>功能配置</h4> <h4>功能配置</h4>
<div class="setting-item" v-for="(settingValue, settingName, index) in switchSettings" :key="index"> <div class="setting-item" v-for="(settingValue, settingName, index) in switchSettings" :key="index">
<span class="setting-name">{{ settingName }}</span> <span class="setting-name">{{ settingName }}</span>
<el-switch v-model="settingValue.value" :disabled="layoutMode !== 'left' && settingName === '固定 Header'" /> <el-switch v-model="settingValue.value" :disabled="!isLeft && settingName === '固定 Header'" />
</div> </div>
<el-button type="danger" :icon="Refresh" @click="resetConfigLayout"> </el-button> <el-button type="danger" :icon="Refresh" @click="resetConfigLayout"> </el-button>
</div> </div>

View File

@ -1,13 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from "vue" import { computed } from "vue"
import { useRoute } from "vue-router" import { useRoute } from "vue-router"
import { storeToRefs } from "pinia"
import { useAppStore } from "@/store/modules/app" import { useAppStore } from "@/store/modules/app"
import { usePermissionStore } from "@/store/modules/permission" import { usePermissionStore } from "@/store/modules/permission"
import { useSettingsStore } from "@/store/modules/settings" import { useSettingsStore } from "@/store/modules/settings"
import SidebarItem from "./SidebarItem.vue" import SidebarItem from "./SidebarItem.vue"
import Logo from "../Logo/index.vue" import Logo from "../Logo/index.vue"
import { useDevice } from "@/hooks/useDevice" import { useDevice } from "@/hooks/useDevice"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import { getCssVariableValue } from "@/utils" import { getCssVariableValue } from "@/utils"
const v3SidebarMenuBgColor = getCssVariableValue("--v3-sidebar-menu-bg-color") const v3SidebarMenuBgColor = getCssVariableValue("--v3-sidebar-menu-bg-color")
@ -15,11 +15,11 @@ const v3SidebarMenuTextColor = getCssVariableValue("--v3-sidebar-menu-text-color
const v3SidebarMenuActiveTextColor = getCssVariableValue("--v3-sidebar-menu-active-text-color") const v3SidebarMenuActiveTextColor = getCssVariableValue("--v3-sidebar-menu-active-text-color")
const { isMobile } = useDevice() const { isMobile } = useDevice()
const { isLeft, isTop } = useLayoutMode()
const route = useRoute() const route = useRoute()
const appStore = useAppStore() const appStore = useAppStore()
const permissionStore = usePermissionStore() const permissionStore = usePermissionStore()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
const { layoutMode, showLogo } = storeToRefs(settingsStore)
const activeMenu = computed(() => { const activeMenu = computed(() => {
const { const {
@ -30,24 +30,22 @@ const activeMenu = computed(() => {
}) })
const noHiddenRoutes = computed(() => permissionStore.routes.filter((item) => !item.meta?.hidden)) const noHiddenRoutes = computed(() => permissionStore.routes.filter((item) => !item.meta?.hidden))
const isCollapse = computed(() => !appStore.sidebar.opened) const isCollapse = computed(() => !appStore.sidebar.opened)
const isLeft = computed(() => layoutMode.value === "left") const isLogo = computed(() => isLeft.value && settingsStore.showLogo)
const isTop = computed(() => layoutMode.value === "top")
const isLogo = computed(() => isLeft.value && showLogo.value)
const backgroundColor = computed(() => (isLeft.value ? v3SidebarMenuBgColor : undefined)) const backgroundColor = computed(() => (isLeft.value ? v3SidebarMenuBgColor : undefined))
const textColor = computed(() => (isLeft.value ? v3SidebarMenuTextColor : undefined)) const textColor = computed(() => (isLeft.value ? v3SidebarMenuTextColor : undefined))
const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextColor : undefined)) const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextColor : undefined))
const sidebarMenuItemHeight = computed(() => { const sidebarMenuItemHeight = computed(() => {
return layoutMode.value !== "top" ? "var(--v3-sidebar-menu-item-height)" : "var(--v3-navigationbar-height)" return !isTop.value ? "var(--v3-sidebar-menu-item-height)" : "var(--v3-navigationbar-height)"
}) })
const sidebarMenuHoverBgColor = computed(() => { const sidebarMenuHoverBgColor = computed(() => {
return layoutMode.value !== "top" ? "var(--v3-sidebar-menu-hover-bg-color)" : "transparent" return !isTop.value ? "var(--v3-sidebar-menu-hover-bg-color)" : "transparent"
}) })
const tipLineWidth = computed(() => { const tipLineWidth = computed(() => {
return layoutMode.value !== "top" ? "2px" : "0px" return !isTop.value ? "2px" : "0px"
}) })
// //
const hiddenScrollbarVerticalBar = computed(() => { const hiddenScrollbarVerticalBar = computed(() => {
return layoutMode.value === "top" ? "none" : "block" return isTop.value ? "none" : "block"
}) })
</script> </script>

View File

@ -5,6 +5,7 @@ import { useSettingsStore } from "@/store/modules/settings"
import useResize from "./hooks/useResize" import useResize from "./hooks/useResize"
import { useWatermark } from "@/hooks/useWatermark" import { useWatermark } from "@/hooks/useWatermark"
import { useDevice } from "@/hooks/useDevice" import { useDevice } from "@/hooks/useDevice"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import LeftMode from "./LeftMode.vue" import LeftMode from "./LeftMode.vue"
import TopMode from "./TopMode.vue" import TopMode from "./TopMode.vue"
import LeftTopMode from "./LeftTopMode.vue" import LeftTopMode from "./LeftTopMode.vue"
@ -16,9 +17,9 @@ useResize()
const { setWatermark, clearWatermark } = useWatermark() const { setWatermark, clearWatermark } = useWatermark()
const { isMobile } = useDevice() const { isMobile } = useDevice()
const { isLeft, isTop, isLeftTop } = useLayoutMode()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
const { showSettings, layoutMode, showTagsView, showWatermark, showGreyMode, showColorWeakness } = const { showSettings, showTagsView, showWatermark, showGreyMode, showColorWeakness } = storeToRefs(settingsStore)
storeToRefs(settingsStore)
const classes = computed(() => { const classes = computed(() => {
return { return {
@ -46,11 +47,11 @@ watchEffect(() => {
<template> <template>
<div :class="classes"> <div :class="classes">
<!-- 左侧模式 --> <!-- 左侧模式 -->
<LeftMode v-if="layoutMode === 'left' || isMobile" /> <LeftMode v-if="isLeft || isMobile" />
<!-- 顶部模式 --> <!-- 顶部模式 -->
<TopMode v-else-if="layoutMode === 'top'" /> <TopMode v-else-if="isTop" />
<!-- 混合模式 --> <!-- 混合模式 -->
<LeftTopMode v-else-if="layoutMode === 'left-top'" /> <LeftTopMode v-else-if="isLeftTop" />
<!-- 右侧设置面板 --> <!-- 右侧设置面板 -->
<RightPanel v-if="showSettings"> <RightPanel v-if="showSettings">
<Settings /> <Settings />