mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-04-05 04:22:49 +08:00
feat: add multi layout
This commit is contained in:
parent
3d29e0df5b
commit
4d27fe76d6
@ -52,7 +52,10 @@
|
||||
"closeLeft": "Close left",
|
||||
"closeRight": "Close right",
|
||||
"backHome": "Back to the homepage",
|
||||
"getRouteError": "Failed to obtain route, please try again later."
|
||||
"getRouteError": "Failed to obtain route, please try again later.",
|
||||
"layoutSetting": "Layout settings",
|
||||
"leftMenu": "Left menu",
|
||||
"topMenu": "Top menu"
|
||||
},
|
||||
"login": {
|
||||
"signInTitle": "Login",
|
||||
|
@ -52,11 +52,12 @@
|
||||
"closeRight": "关闭右侧",
|
||||
"closeAll": "全部关闭",
|
||||
"backHome": "回到首页",
|
||||
"getRouteError": "获取路由失败,请稍后再试"
|
||||
|
||||
"getRouteError": "获取路由失败,请稍后再试",
|
||||
"layoutSetting": "布局设置",
|
||||
"leftMenu": "左侧菜单",
|
||||
"topMenu": "顶部菜单"
|
||||
},
|
||||
"http": {
|
||||
"defaultTip": "请求错误",
|
||||
"400": "请求出现语法错误",
|
||||
"401": "用户未授权",
|
||||
"403": "服务器拒绝访问",
|
||||
@ -68,7 +69,8 @@
|
||||
"502": "错误网关",
|
||||
"503": "服务不可用",
|
||||
"504": "网关超时",
|
||||
"505": "http版本不支持该请求"
|
||||
"505": "http版本不支持该请求",
|
||||
"defaultTip": "请求错误"
|
||||
},
|
||||
"components": {
|
||||
"iconSelector": {
|
||||
|
56
src/layouts/components/common/LayoutSelector.vue
Normal file
56
src/layouts/components/common/LayoutSelector.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutMode } from '@/store/app'
|
||||
|
||||
const value = defineModel<LayoutMode>('value', { required: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-center gap-4">
|
||||
<n-tooltip placement="bottom" trigger="hover">
|
||||
<template #trigger>
|
||||
<n-el
|
||||
:class="{
|
||||
'outline outline-2': value === 'leftMenu',
|
||||
}"
|
||||
class="grid grid-cols-[20%_1fr] grid-rows-[20%_1fr] outline-[var(--primary-color)] hover:(outline outline-2)"
|
||||
@click="value = 'leftMenu'"
|
||||
>
|
||||
<div class="bg-[var(--primary-color)] row-span-2" />
|
||||
<div class="bg-[var(--primary-color-suppl)]" />
|
||||
<div class="bg-[var(--divider-color)]" />
|
||||
</n-el>
|
||||
</template>
|
||||
<span> {{ $t('app.leftMenu') }} </span>
|
||||
</n-tooltip>
|
||||
|
||||
<n-tooltip placement="bottom" trigger="hover">
|
||||
<template #trigger>
|
||||
<n-el
|
||||
:class="{
|
||||
'outline outline-2': value === 'topMenu',
|
||||
}"
|
||||
class="grid grid-rows-[30%_1fr] outline-[var(--primary-color)] hover:(outline outline-2)"
|
||||
@click="value = 'topMenu'"
|
||||
>
|
||||
<div class="bg-[var(--primary-color)]" />
|
||||
<div class="bg-[var(--divider-color)]" />
|
||||
</n-el>
|
||||
</template>
|
||||
<span> {{ $t('app.topMenu') }} </span>
|
||||
</n-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.grid{
|
||||
height: 60px;
|
||||
width: 86px;
|
||||
gap:0.4em;
|
||||
padding: 0.4em;
|
||||
box-shadow: var(--box-shadow-1);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.grid > div{
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
</style>
|
@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import LayoutSelector from '../common/LayoutSelector.vue'
|
||||
import { useAppStore } from '@/store'
|
||||
|
||||
const appStore = useAppStore()
|
||||
@ -85,6 +86,8 @@ function resetSetting() {
|
||||
<n-drawer v-model:show="drawerActive" :width="360">
|
||||
<n-drawer-content :title="t('app.systemSetting')" closable>
|
||||
<n-space vertical>
|
||||
<n-divider>{{ $t('app.layoutSetting') }}</n-divider>
|
||||
<LayoutSelector v-model:value="appStore.layoutMode" />
|
||||
<n-divider>{{ $t('app.themeSetting') }}</n-divider>
|
||||
<n-space justify="space-between">
|
||||
{{ $t('app.colorWeak') }}
|
||||
@ -97,14 +100,16 @@ function resetSetting() {
|
||||
<n-space align="center" justify="space-between">
|
||||
{{ $t('app.themeColor') }}
|
||||
<n-color-picker
|
||||
v-model:value="appStore.primaryColor"
|
||||
class="w-10em" :swatches="palette"
|
||||
v-model:value="appStore.primaryColor" class="w-10em" :swatches="palette"
|
||||
@update:value="appStore.setPrimaryColor"
|
||||
/>
|
||||
</n-space>
|
||||
<n-space align="center" justify="space-between">
|
||||
{{ $t('app.pageTransition') }}
|
||||
<n-select v-model:value="appStore.transitionAnimation" class="w-10em" :options="transitionSelectorOptions" @update:value="appStore.reloadPage" />
|
||||
<n-select
|
||||
v-model:value="appStore.transitionAnimation" class="w-10em"
|
||||
:options="transitionSelectorOptions" @update:value="appStore.reloadPage"
|
||||
/>
|
||||
</n-space>
|
||||
|
||||
<n-divider>{{ $t('app.interfaceDisplay') }}</n-divider>
|
||||
|
@ -9,13 +9,13 @@ const name = import.meta.env.VITE_APP_NAME
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="h-60px text-xl flex-center cursor-pointer"
|
||||
class="h-60px text-xl flex-center cursor-pointer gap-2 p-x-2"
|
||||
@click="router.push('/')"
|
||||
>
|
||||
<svg-icons-logo class="text-1.5em" />
|
||||
<span
|
||||
v-show="!appStore.collapsed"
|
||||
class="mx-3 text-ellipsis overflow-hidden whitespace-nowrap"
|
||||
class="text-ellipsis overflow-hidden whitespace-nowrap"
|
||||
>{{ name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,3 +0,0 @@
|
||||
const BasicLayout = () => import('./BasicLayout/index.vue')
|
||||
|
||||
export { BasicLayout }
|
15
src/layouts/index.vue
Normal file
15
src/layouts/index.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import leftMenu from './leftMenu.layout.vue'
|
||||
import topMenu from './topMenu.layout.vue'
|
||||
import { useAppStore } from '@/store/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const layoutMap = {
|
||||
leftMenu,
|
||||
topMenu,
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="layoutMap[appStore.layoutMode]" />
|
||||
</template>
|
@ -11,7 +11,7 @@ import {
|
||||
Setting,
|
||||
TabBar,
|
||||
UserCenter,
|
||||
} from '../components'
|
||||
} from './components'
|
||||
import { useAppStore, useRouteStore } from '@/store'
|
||||
|
||||
const routeStore = useRouteStore()
|
59
src/layouts/topMenu.layout.vue
Normal file
59
src/layouts/topMenu.layout.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
BackTop,
|
||||
FullScreen,
|
||||
Logo,
|
||||
Menu,
|
||||
Notices,
|
||||
Search,
|
||||
Setting,
|
||||
TabBar,
|
||||
UserCenter,
|
||||
} from './components'
|
||||
import { useAppStore, useRouteStore } from '@/store'
|
||||
|
||||
const routeStore = useRouteStore()
|
||||
const appStore = useAppStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-layout class="wh-full" embedded>
|
||||
<n-layout
|
||||
class="h-full flex flex-col" content-style="display: flex;flex-direction: column;min-height:100%;"
|
||||
embedded :native-scrollbar="false"
|
||||
>
|
||||
<n-layout-header bordered position="absolute" class="z-1">
|
||||
<div class="h-60px flex-y-center justify-between shrink-0">
|
||||
<Logo v-if="appStore.showLogo" />
|
||||
<Menu mode="horizontal" responsive />
|
||||
<div class="flex-y-center gap-1 h-full p-x-xl">
|
||||
<Search />
|
||||
<Notices />
|
||||
<FullScreen />
|
||||
<DarkModeSwitch />
|
||||
<LangsSwitch />
|
||||
<Setting />
|
||||
<UserCenter />
|
||||
</div>
|
||||
</div>
|
||||
<TabBar v-if="appStore.showTabs" class="h-45px" />
|
||||
</n-layout-header>
|
||||
<div class="flex-1 p-16px flex flex-col">
|
||||
<div class="h-60px" />
|
||||
<div v-if="appStore.showTabs" class="h-45px" />
|
||||
<router-view v-slot="{ Component, route }" class="flex-1">
|
||||
<transition :name="appStore.transitionAnimation" mode="out-in">
|
||||
<keep-alive :include="routeStore.cacheRoutes">
|
||||
<component :is="Component" v-if="appStore.loadFlag" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
<div v-if="appStore.showFooter" class="h-40px" />
|
||||
</div>
|
||||
<n-layout-footer v-if="appStore.showFooter" bordered position="absolute" class="h-40px flex-center">
|
||||
{{ appStore.footerText }}
|
||||
</n-layout-footer>
|
||||
<BackTop />
|
||||
</n-layout>
|
||||
</n-layout>
|
||||
</template>
|
@ -6,7 +6,7 @@ import { local } from '@/utils'
|
||||
|
||||
export const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: local.get('lang') || 'zhCN', // 默认显示语言
|
||||
locale: local.get('lang') || 'enUS', // 默认显示语言
|
||||
fallbackLocale: 'enUS',
|
||||
messages: {
|
||||
zhCN,
|
||||
|
@ -6,7 +6,7 @@ export const routes: RouteRecordRaw[] = [
|
||||
path: '/',
|
||||
name: 'root',
|
||||
redirect: '/appRoot',
|
||||
component: () => import('@/layouts/index'),
|
||||
// component: () => import('@/layouts/index'),
|
||||
children: [
|
||||
],
|
||||
},
|
||||
|
@ -5,6 +5,7 @@ import themeConfig from './theme.json'
|
||||
import { local, setLocale } from '@/utils'
|
||||
|
||||
type TransitionAnimation = '' | 'fade-slide' | 'fade-bottom' | 'fade-scale' | 'zoom-fade' | 'zoom-out'
|
||||
export type LayoutMode = 'leftMenu' | 'topMenu'
|
||||
|
||||
const docEle = ref(document.documentElement)
|
||||
|
||||
@ -33,6 +34,7 @@ export const useAppStore = defineStore('app-store', {
|
||||
showBreadcrumbIcon: true,
|
||||
showWatermark: false,
|
||||
transitionAnimation: 'fade-slide' as TransitionAnimation,
|
||||
layoutMode: 'leftMenu' as LayoutMode,
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@ -63,6 +65,7 @@ export const useAppStore = defineStore('app-store', {
|
||||
this.showBreadcrumbIcon = true
|
||||
this.showWatermark = false
|
||||
this.transitionAnimation = 'fade-slide'
|
||||
this.layoutMode = 'leftMenu'
|
||||
|
||||
// 重置所有配色
|
||||
this.setPrimaryColor(this.primaryColor)
|
||||
|
@ -8,7 +8,7 @@ import { router } from '@/router'
|
||||
import { fetchUserRoutes } from '@/service'
|
||||
import { staticRoutes } from '@/router/routes.static'
|
||||
import { usePermission } from '@/hooks'
|
||||
import { BasicLayout } from '@/layouts/index'
|
||||
import Layout from '@/layouts/index.vue'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
|
||||
interface RoutesStatus {
|
||||
@ -121,7 +121,7 @@ export const useRouteStore = defineStore('route-store', {
|
||||
path: '/appRoot',
|
||||
name: 'appRoot',
|
||||
redirect: import.meta.env.VITE_HOME_PATH,
|
||||
component: BasicLayout,
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '',
|
||||
icon: 'icon-park-outline:home',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineConfig, presetAttributify, presetUno } from 'unocss'
|
||||
import { defineConfig, presetAttributify, presetUno, transformerVariantGroup } from 'unocss'
|
||||
|
||||
// https://github.com/unocss/unocss
|
||||
|
||||
@ -11,4 +11,7 @@ export default defineConfig({
|
||||
'flex-x-center': 'flex justify-center',
|
||||
'flex-y-center': 'flex items-center',
|
||||
},
|
||||
transformers: [
|
||||
transformerVariantGroup(),
|
||||
],
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user