mirror of
https://github.com/un-pany/v3-admin-vite.git
synced 2025-04-21 11:29:20 +08:00
wip: 顶部布局模式开发中
This commit is contained in:
parent
d5afb53c25
commit
8a0b8c5b3a
77
src/layouts/TopMode.vue
Normal file
77
src/layouts/TopMode.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<script lang="ts" setup>
|
||||
import { storeToRefs } from "pinia"
|
||||
import { useSettingsStore } from "@/store/modules/settings"
|
||||
import { AppMain, NavigationBar, TagsView, Logo } from "./components"
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
const { showTagsView, showLogo } = storeToRefs(settingsStore)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-wrapper">
|
||||
<!-- 头部导航栏和标签栏 -->
|
||||
<div class="fixed-header layout-header">
|
||||
<div class="content">
|
||||
<Logo v-if="showLogo" :collapse="false" class="logo" />
|
||||
<NavigationBar class="navigation-bar" />
|
||||
</div>
|
||||
<TagsView v-show="showTagsView" />
|
||||
</div>
|
||||
<!-- 主容器 -->
|
||||
<div :class="{ hasTagsView: showTagsView }" class="main-container">
|
||||
<!-- 页面主体内容 -->
|
||||
<AppMain class="app-main" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/mixins.scss";
|
||||
$transition-time: 0.35s;
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 1002;
|
||||
width: 100%;
|
||||
.logo {
|
||||
width: var(--v3-sidebar-width);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
.navigation-bar {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-header {
|
||||
box-shadow: var(--el-box-shadow-lighter);
|
||||
}
|
||||
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
transition: padding-left $transition-time;
|
||||
padding-top: var(--v3-navigationbar-height);
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.hasTagsView {
|
||||
.sidebar-container {
|
||||
padding-top: var(--v3-header-height);
|
||||
}
|
||||
.app-main {
|
||||
padding-top: var(--v3-header-height);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -23,6 +23,12 @@ const bgCloor = computed(() => {
|
||||
? getCssVariableValue("--v3-header-bg-color")
|
||||
: getCssVariableValue("--v3-sidebar-menu-bg-color")
|
||||
})
|
||||
|
||||
const logoHeight = computed(() => {
|
||||
return layoutMode.value !== "top"
|
||||
? getCssVariableValue("--v3-header-height")
|
||||
: getCssVariableValue("--v3-navigationbar-height")
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -42,8 +48,8 @@ const bgCloor = computed(() => {
|
||||
.layout-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: var(--v3-header-height);
|
||||
line-height: var(--v3-header-height);
|
||||
height: v-bind(logoHeight);
|
||||
line-height: v-bind(logoHeight);
|
||||
background-color: v-bind(bgCloor);
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
@ -1,4 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue"
|
||||
import { useRouter } from "vue-router"
|
||||
import { storeToRefs } from "pinia"
|
||||
import { useAppStore } from "@/store/modules/app"
|
||||
@ -7,22 +8,28 @@ import { useUserStore } from "@/store/modules/user"
|
||||
import { UserFilled } from "@element-plus/icons-vue"
|
||||
import Hamburger from "../Hamburger/index.vue"
|
||||
import Breadcrumb from "../Breadcrumb/index.vue"
|
||||
import Sidebar from "../Sidebar/index.vue"
|
||||
import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
|
||||
import Screenfull from "@/components/Screenfull/index.vue"
|
||||
import Notify from "@/components/Notify/index.vue"
|
||||
import { DeviceEnum } from "@/constants/app-key"
|
||||
|
||||
const router = useRouter()
|
||||
const appStore = useAppStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const { sidebar } = storeToRefs(appStore)
|
||||
const { showNotify, showThemeSwitch, showScreenfull } = storeToRefs(settingsStore)
|
||||
const { sidebar, device } = storeToRefs(appStore)
|
||||
const { layoutMode, showNotify, showThemeSwitch, showScreenfull } = storeToRefs(settingsStore)
|
||||
|
||||
const isTop = computed(() => layoutMode.value === "top")
|
||||
const isMobile = computed(() => device.value === DeviceEnum.Mobile)
|
||||
|
||||
/** 切换侧边栏 */
|
||||
const toggleSidebar = () => {
|
||||
appStore.toggleSidebar(false)
|
||||
}
|
||||
|
||||
/** 登出 */
|
||||
const logout = () => {
|
||||
userStore.logout()
|
||||
@ -32,8 +39,9 @@ const logout = () => {
|
||||
|
||||
<template>
|
||||
<div class="navigation-bar">
|
||||
<Hamburger :is-active="sidebar.opened" class="hamburger" @toggle-click="toggleSidebar" />
|
||||
<Breadcrumb class="breadcrumb" />
|
||||
<Hamburger v-if="!isTop || isMobile" :is-active="sidebar.opened" class="hamburger" @toggle-click="toggleSidebar" />
|
||||
<Breadcrumb v-if="!isTop || isMobile" class="breadcrumb" />
|
||||
<Sidebar v-if="isTop && !isMobile" class="sidebar" />
|
||||
<div class="right-menu">
|
||||
<Screenfull v-if="showScreenfull" class="right-menu-item" />
|
||||
<ThemeSwitch v-if="showThemeSwitch" class="right-menu-item" />
|
||||
@ -84,6 +92,11 @@ const logout = () => {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.sidebar {
|
||||
float: left;
|
||||
width: 992px;
|
||||
height: 100%;
|
||||
}
|
||||
.right-menu {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
|
@ -8,12 +8,14 @@ import path from "path-browserify"
|
||||
interface Props {
|
||||
item: RouteRecordRaw
|
||||
isCollapse?: boolean
|
||||
isTop?: boolean
|
||||
isFirstLevel?: boolean
|
||||
basePath?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
isCollapse: false,
|
||||
isTop: false,
|
||||
isFirstLevel: true,
|
||||
basePath: ""
|
||||
})
|
||||
@ -58,7 +60,10 @@ const resolvePath = (routePath: string) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!props.item.meta?.hidden" :class="{ 'simple-mode': props.isCollapse, 'first-level': props.isFirstLevel }">
|
||||
<div
|
||||
v-if="!props.item.meta?.hidden"
|
||||
:class="{ 'simple-mode': props.isCollapse && !isTop, 'first-level': props.isFirstLevel }"
|
||||
>
|
||||
<template v-if="!alwaysShowRootMenu && theOnlyOneChild && !theOnlyOneChild.children">
|
||||
<SidebarItemLink v-if="theOnlyOneChild.meta" :to="resolvePath(theOnlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(theOnlyOneChild.path)">
|
||||
|
@ -8,6 +8,7 @@ import { useSettingsStore } from "@/store/modules/settings"
|
||||
import SidebarItem from "./SidebarItem.vue"
|
||||
import Logo from "../Logo/index.vue"
|
||||
import { getCssVariableValue } from "@/utils"
|
||||
import { DeviceEnum } from "@/constants/app-key"
|
||||
|
||||
const v3SidebarMenuBgColor = getCssVariableValue("--v3-sidebar-menu-bg-color")
|
||||
const v3SidebarMenuTextColor = getCssVariableValue("--v3-sidebar-menu-text-color")
|
||||
@ -18,6 +19,7 @@ const appStore = useAppStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
const { sidebar, device } = storeToRefs(appStore)
|
||||
const { layoutMode, showLogo } = storeToRefs(settingsStore)
|
||||
|
||||
const activeMenu = computed(() => {
|
||||
@ -28,12 +30,25 @@ const activeMenu = computed(() => {
|
||||
return activeMenu ? activeMenu : path
|
||||
})
|
||||
|
||||
const isCollapse = computed(() => !appStore.sidebar.opened)
|
||||
const isCollapse = computed(() => !sidebar.value.opened)
|
||||
const isLeft = computed(() => layoutMode.value === "left")
|
||||
const isTop = computed(() => layoutMode.value === "top")
|
||||
const isMobile = computed(() => device.value === DeviceEnum.Mobile)
|
||||
const isLogo = computed(() => isLeft.value && showLogo.value)
|
||||
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"
|
||||
? getCssVariableValue("--v3-sidebar-menu-item-height")
|
||||
: getCssVariableValue("--v3-navigationbar-height")
|
||||
})
|
||||
const sidebarMenuHoverBgColor = computed(() => {
|
||||
return layoutMode.value !== "top" ? getCssVariableValue("--v3-sidebar-menu-hover-bg-color") : "transparent"
|
||||
})
|
||||
const tipLineWidth = computed(() => {
|
||||
return layoutMode.value !== "top" ? "2px" : "0px"
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -42,13 +57,13 @@ const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextCo
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:collapse="isCollapse && !isTop"
|
||||
:background-color="backgroundColor"
|
||||
:text-color="textColor"
|
||||
:active-text-color="activeTextColor"
|
||||
:unique-opened="true"
|
||||
:collapse-transition="false"
|
||||
mode="vertical"
|
||||
:mode="isTop && !isMobile ? 'horizontal' : 'vertical'"
|
||||
>
|
||||
<SidebarItem
|
||||
v-for="route in permissionStore.routes"
|
||||
@ -56,6 +71,7 @@ const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextCo
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
:is-collapse="isCollapse"
|
||||
:is-top="isTop"
|
||||
/>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
@ -69,7 +85,7 @@ const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextCo
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
width: v-bind(tipLineWidth);
|
||||
height: 100%;
|
||||
background-color: var(--v3-sidebar-menu-tip-line-bg-color);
|
||||
}
|
||||
@ -107,12 +123,13 @@ const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextCo
|
||||
|
||||
:deep(.el-menu-item),
|
||||
:deep(.el-sub-menu__title),
|
||||
:deep(.el-sub-menu .el-menu-item) {
|
||||
height: var(--v3-sidebar-menu-item-height);
|
||||
line-height: var(--v3-sidebar-menu-item-height);
|
||||
:deep(.el-sub-menu .el-menu-item),
|
||||
:deep(.el-menu--horizontal .el-menu-item) {
|
||||
height: v-bind(sidebarMenuItemHeight);
|
||||
line-height: v-bind(sidebarMenuItemHeight);
|
||||
&.is-active,
|
||||
&:hover {
|
||||
background-color: var(--v3-sidebar-menu-hover-bg-color);
|
||||
background-color: v-bind(sidebarMenuHoverBgColor);
|
||||
}
|
||||
display: block;
|
||||
* {
|
||||
@ -120,6 +137,14 @@ const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextCo
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu) {
|
||||
&.is-active {
|
||||
.el-sub-menu__title {
|
||||
color: v-bind(activeTextColor) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-menu-item) {
|
||||
&.is-active {
|
||||
@include tip-line;
|
||||
|
@ -5,6 +5,7 @@ import { useAppStore } from "@/store/modules/app"
|
||||
import { useSettingsStore } from "@/store/modules/settings"
|
||||
import useResize from "./hooks/useResize"
|
||||
import LeftMode from "./LeftMode.vue"
|
||||
import TopMode from "./TopMode.vue"
|
||||
import LeftTopMode from "./LeftTopMode.vue"
|
||||
import { Settings, RightPanel } from "./components"
|
||||
import { DeviceEnum } from "@/constants/app-key"
|
||||
@ -40,6 +41,8 @@ watchEffect(() => {
|
||||
<div :class="classes">
|
||||
<!-- 左侧模式 -->
|
||||
<LeftMode v-if="layoutMode === 'left' || appStore.device === DeviceEnum.Mobile" />
|
||||
<!-- 顶部模式 -->
|
||||
<TopMode v-else-if="layoutMode === 'top'" />
|
||||
<!-- 混合模式 -->
|
||||
<LeftTopMode v-else-if="layoutMode === 'left-top'" />
|
||||
<!-- 右侧设置面板 -->
|
||||
|
@ -16,5 +16,12 @@
|
||||
.el-sub-menu__title {
|
||||
background-color: lighten($theme-bg-color, 4%) !important;
|
||||
}
|
||||
.el-sub-menu {
|
||||
&.is-active {
|
||||
.el-sub-menu__title {
|
||||
color: $active-font-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,13 @@
|
||||
.el-sub-menu__title {
|
||||
background-color: lighten($theme-bg-color, 4%) !important;
|
||||
}
|
||||
.el-sub-menu {
|
||||
&.is-active {
|
||||
.el-sub-menu__title {
|
||||
color: $active-font-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Header
|
||||
|
Loading…
x
Reference in New Issue
Block a user