Skip to content

Commit

Permalink
feat: add useLayoutMode
Browse files Browse the repository at this point in the history
  • Loading branch information
pany-ang committed Feb 6, 2024
1 parent 0a4d896 commit 02dca40
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 41 deletions.
5 changes: 3 additions & 2 deletions src/config/layouts.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { getConfigLayout } from "@/utils/cache/local-storage"
import { LayoutModeEnum } from "@/constants/app-key"

/** 项目配置类型 */
export interface LayoutSettings {
/** 是否显示 Settings Panel */
showSettings: boolean
/** 布局模式 */
layoutMode: "left" | "top" | "left-top"
layoutMode: LayoutModeEnum
/** 是否显示标签栏 */
showTagsView: boolean
/** 是否显示 Logo */
Expand Down Expand Up @@ -34,7 +35,7 @@ export interface LayoutSettings {

/** 默认配置 */
const defaultSettings: LayoutSettings = {
layoutMode: "left",
layoutMode: LayoutModeEnum.Left,
showSettings: true,
showTagsView: true,
fixedHeader: true,
Expand Down
7 changes: 7 additions & 0 deletions src/constants/app-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ export enum DeviceEnum {
Desktop
}

/** 布局模式 */
export enum LayoutModeEnum {
Left = "left",
Top = "top",
LeftTop = "left-top"
}

/** 侧边栏打开状态常量 */
export const SIDEBAR_OPENED = "opened"
/** 侧边栏关闭状态常量 */
Expand Down
16 changes: 16 additions & 0 deletions src/hooks/useLayoutMode.ts
Original file line number Diff line number Diff line change
@@ -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 }
}
10 changes: 4 additions & 6 deletions src/layouts/components/Logo/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script lang="ts" setup>
import { storeToRefs } from "pinia"
import { useSettingsStore } from "@/store/modules/settings"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import logo from "@/assets/layouts/logo.png?url"
import logoText1 from "@/assets/layouts/logo-text-1.png?url"
import logoText2 from "@/assets/layouts/logo-text-2.png?url"
Expand All @@ -13,18 +12,17 @@ const props = withDefaults(defineProps<Props>(), {
collapse: true
})
const settingsStore = useSettingsStore()
const { layoutMode } = storeToRefs(settingsStore)
const { isLeft, isTop } = useLayoutMode()
</script>

<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">
<router-link v-if="props.collapse" key="collapse" to="/">
<img :src="logo" class="layout-logo" />
</router-link>
<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>
</transition>
</div>
Expand Down
7 changes: 3 additions & 4 deletions src/layouts/components/NavigationBar/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts" setup>
import { computed } from "vue"
import { useRouter } from "vue-router"
import { storeToRefs } from "pinia"
import { useAppStore } from "@/store/modules/app"
Expand All @@ -14,15 +13,15 @@ import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
import Screenfull from "@/components/Screenfull/index.vue"
import SearchMenu from "@/components/SearchMenu/index.vue"
import { useDevice } from "@/hooks/useDevice"
import { useLayoutMode } from "@/hooks/useLayoutMode"
const { isMobile } = useDevice()
const { isTop } = useLayoutMode()
const router = useRouter()
const appStore = useAppStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
const { layoutMode, showNotify, showThemeSwitch, showScreenfull, showSearchMenu } = storeToRefs(settingsStore)
const isTop = computed(() => layoutMode.value === "top")
const { showNotify, showThemeSwitch, showScreenfull, showSearchMenu } = storeToRefs(settingsStore)
/** 切换侧边栏 */
const toggleSidebar = () => {
Expand Down
22 changes: 10 additions & 12 deletions src/layouts/components/Settings/SelectLayoutMode.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
<script lang="ts" setup>
import { computed } from "vue"
import { storeToRefs } from "pinia"
import { useSettingsStore } from "@/store/modules/settings"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import { LayoutModeEnum } from "@/constants/app-key"
const settingsStore = useSettingsStore()
const { layoutMode } = storeToRefs(settingsStore)
const isLeft = computed(() => layoutMode.value === "left")
const isTop = computed(() => layoutMode.value === "top")
const isLeftTop = computed(() => layoutMode.value === "left-top")
const { isLeft, isTop, isLeftTop, setLayoutMode } = useLayoutMode()
</script>

<template>
<div class="select-layout-mode">
<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-container>
<el-header />
Expand All @@ -23,13 +17,17 @@ const isLeftTop = computed(() => layoutMode.value === "left-top")
</el-container>
</el-tooltip>
<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-main />
</el-container>
</el-tooltip>
<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-container>
<el-aside />
Expand Down
7 changes: 4 additions & 3 deletions src/layouts/components/Settings/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
import { watchEffect } from "vue"
import { storeToRefs } from "pinia"
import { useSettingsStore } from "@/store/modules/settings"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import { resetConfigLayout } from "@/utils"
import SelectLayoutMode from "./SelectLayoutMode.vue"
import { Refresh } from "@element-plus/icons-vue"
const { isLeft } = useLayoutMode()
const settingsStore = useSettingsStore()
/** 使用 storeToRefs 将提取的属性保持其响应性 */
const {
layoutMode,
showTagsView,
showLogo,
fixedHeader,
Expand Down Expand Up @@ -43,7 +44,7 @@ const switchSettings = {
/** 非左侧模式时,Header 都是 fixed 布局 */
watchEffect(() => {
layoutMode.value !== "left" && (fixedHeader.value = true)
isLeft.value && (fixedHeader.value = true)
})
</script>

Expand All @@ -55,7 +56,7 @@ watchEffect(() => {
<h4>功能配置</h4>
<div class="setting-item" v-for="(settingValue, settingName, index) in switchSettings" :key="index">
<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>
<el-button type="danger" :icon="Refresh" @click="resetConfigLayout">重 置</el-button>
</div>
Expand Down
16 changes: 7 additions & 9 deletions src/layouts/components/Sidebar/index.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
<script lang="ts" setup>
import { computed } from "vue"
import { useRoute } from "vue-router"
import { storeToRefs } from "pinia"
import { useAppStore } from "@/store/modules/app"
import { usePermissionStore } from "@/store/modules/permission"
import { useSettingsStore } from "@/store/modules/settings"
import SidebarItem from "./SidebarItem.vue"
import Logo from "../Logo/index.vue"
import { useDevice } from "@/hooks/useDevice"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import { getCssVariableValue } from "@/utils"
const v3SidebarMenuBgColor = getCssVariableValue("--v3-sidebar-menu-bg-color")
const v3SidebarMenuTextColor = getCssVariableValue("--v3-sidebar-menu-text-color")
const v3SidebarMenuActiveTextColor = getCssVariableValue("--v3-sidebar-menu-active-text-color")
const { isMobile } = useDevice()
const { isLeft, isTop } = useLayoutMode()
const route = useRoute()
const appStore = useAppStore()
const permissionStore = usePermissionStore()
const settingsStore = useSettingsStore()
const { layoutMode, showLogo } = storeToRefs(settingsStore)
const activeMenu = computed(() => {
const {
Expand All @@ -30,24 +30,22 @@ const activeMenu = computed(() => {
})
const noHiddenRoutes = computed(() => permissionStore.routes.filter((item) => !item.meta?.hidden))
const isCollapse = computed(() => !appStore.sidebar.opened)
const isLeft = computed(() => layoutMode.value === "left")
const isTop = computed(() => layoutMode.value === "top")
const isLogo = computed(() => isLeft.value && showLogo.value)
const isLogo = computed(() => isLeft.value && settingsStore.showLogo)
const backgroundColor = computed(() => (isLeft.value ? v3SidebarMenuBgColor : undefined))
const textColor = computed(() => (isLeft.value ? v3SidebarMenuTextColor : undefined))
const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextColor : undefined))
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(() => {
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(() => {
return layoutMode.value !== "top" ? "2px" : "0px"
return !isTop.value ? "2px" : "0px"
})
// 当为顶部模式时隐藏垂直滚动条
const hiddenScrollbarVerticalBar = computed(() => {
return layoutMode.value === "top" ? "none" : "block"
return isTop.value ? "none" : "block"
})
</script>

Expand Down
11 changes: 6 additions & 5 deletions src/layouts/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useSettingsStore } from "@/store/modules/settings"
import useResize from "./hooks/useResize"
import { useWatermark } from "@/hooks/useWatermark"
import { useDevice } from "@/hooks/useDevice"
import { useLayoutMode } from "@/hooks/useLayoutMode"
import LeftMode from "./LeftMode.vue"
import TopMode from "./TopMode.vue"
import LeftTopMode from "./LeftTopMode.vue"
Expand All @@ -16,9 +17,9 @@ useResize()
const { setWatermark, clearWatermark } = useWatermark()
const { isMobile } = useDevice()
const { isLeft, isTop, isLeftTop } = useLayoutMode()
const settingsStore = useSettingsStore()
const { showSettings, layoutMode, showTagsView, showWatermark, showGreyMode, showColorWeakness } =
storeToRefs(settingsStore)
const { showSettings, showTagsView, showWatermark, showGreyMode, showColorWeakness } = storeToRefs(settingsStore)
const classes = computed(() => {
return {
Expand Down Expand Up @@ -46,11 +47,11 @@ watchEffect(() => {
<template>
<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">
<Settings />
Expand Down

0 comments on commit 02dca40

Please sign in to comment.