feat(plugin-layout): 支持配置 403、404 的 navigation (#224)

* feat: 升级 eslint 配置及版本

* feat(plugin-layout): 支持配置 403、404  的 navigation

* docs: 补充文档
This commit is contained in:
1zumii 2024-01-12 12:43:57 +08:00 committed by GitHub
parent 14d7f6eaad
commit 74fa0ba122
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 605 additions and 400 deletions

71
.vscode/settings.json vendored
View File

@ -1,48 +1,35 @@
{ {
// Enable the ESlint flat config support // Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true, "eslint.experimental.useFlatConfig": true,
// Disable the default formatter, use eslint instead // Disable the default formatter, use eslint instead
"prettier.enable": false, "prettier.enable": false,
"editor.formatOnSave": false, "editor.formatOnSave": false,
// Auto fix // Auto fix
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit", "source.fixAll.eslint": "explicit",
"source.organizeImports": "never" "source.organizeImports": "never"
}, },
// Silent the stylistic rules in you IDE, but still auto fix them // Enable eslint for all supported languages
"eslint.rules.customizations": [ "eslint.validate": [
{ "rule": "style/*", "severity": "off" }, "javascript",
{ "rule": "*-indent", "severity": "off" }, "javascriptreact",
{ "rule": "*-spacing", "severity": "off" }, "typescript",
{ "rule": "*-spaces", "severity": "off" }, "typescriptreact",
{ "rule": "*-order", "severity": "off" }, "vue",
{ "rule": "*-dangle", "severity": "off" }, "html",
{ "rule": "*-newline", "severity": "off" }, "markdown",
{ "rule": "*quotes", "severity": "off" }, "json",
{ "rule": "*semi", "severity": "off" } "jsonc",
], "yaml"
],
// Enable eslint for all supported languages "pair-diff.patterns": [
"eslint.validate": [ {
"javascript", "source": "./fixtures/output/**/*.*",
"javascriptreact", "target": "./fixtures/input/<base>"
"typescript", }
"typescriptreact", ]
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
],
"pair-diff.patterns": [
{
"source": "./fixtures/output/**/*.*",
"target": "./fixtures/input/<base>"
}
]
} }

View File

@ -90,8 +90,9 @@ Fes.js 里约定目录下有 `layout.vue` 时会生成嵌套路由,以 `layout
```vue ```vue
<template> <template>
<Page></Page> <Page />
</template> </template>
<script> <script>
import { Page } from '@fesjs/fes'; import { Page } from '@fesjs/fes';
export default { export default {
@ -112,7 +113,7 @@ export default {
export default { export default {
layout: { layout: {
// 标题 // 标题
title: "Fes.js", title: 'Fes.js',
// 底部文字 // 底部文字
footer: 'Created by MumbleFE', footer: 'Created by MumbleFE',
// 主题light // 主题light
@ -128,6 +129,7 @@ export default {
}], }],
}, },
};
``` ```
#### 运行时配置方式 #### 运行时配置方式
@ -146,27 +148,29 @@ export const layout = {
}; };
``` ```
在`fes.js`中,运行时配置有定义对象和函数两种方式,当使用函数配置`layout`时,`layoutConfig`是编译时配置结果,`initialState`是 `beforeRender.action`执行后创建的应用初始状态数据。 在`fes.js`中,运行时配置有定义对象和函数两种方式,当使用函数配置`layout`时,`layoutConfig`是编译时配置结果,`initialState`是 `beforeRender.action`执行后创建的应用初始状态数据。
```js ```js
export const layout = (layoutConfig, { initialState }) => ({ export function layout(layoutConfig, { initialState }) {
renderCustom: () => <UserCenter />, return {
menus: () => { renderCustom: () => <UserCenter />,
const menusRef = ref(layoutConfig.menus); menus: () => {
watch( const menusRef = ref(layoutConfig.menus);
() => initialState.userName, watch(
() => { () => initialState.userName,
menusRef.value = [ () => {
{ menusRef.value = [
name: 'store', {
}, name: 'store',
]; },
}, ];
); },
return menusRef; );
}, return menusRef;
}); },
};
}
``` ```
最终配置结果是运行时配置跟编译时配置合并的结果,运行时配置优先于编译时配置。 最终配置结果是运行时配置跟编译时配置合并的结果,运行时配置优先于编译时配置。
@ -194,6 +198,12 @@ export const layout = (layoutConfig, { initialState }) => ({
- **详情**:页面布局类型,可选有 `side``top``mixin` - **详情**:页面布局类型,可选有 `side``top``mixin`
### navigationOnError
- **类型**`String`、`Function`
- **详情**:指定 `403`、`404` 时,页面的布局类型。值同 `navigation`。也支持函数返回。
### isFixedHeader ### isFixedHeader
- **类型**`Boolean` - **类型**`Boolean`
@ -382,7 +392,7 @@ import { useRoute, useTabTitle } from '@fesjs/fes';
const titleRef = useTabTitle(`详情-${route.params?.id}`); const titleRef = useTabTitle(`详情-${route.params?.id}`);
//如果要更新 // 如果要更新
titleRef.value = 'changed'; titleRef.value = 'changed';
</script> </script>
``` ```

View File

@ -2,19 +2,36 @@
import antfu from '@antfu/eslint-config'; import antfu from '@antfu/eslint-config';
export default await antfu({ export default await antfu({
files: ['**/*.js', '**/*.jsx', '**/*.vue', '**/*.ts'],
// TODO: 使用 ignore 代替 cli 命令中的配置
stylistic: { stylistic: {
indent: 4, // 4, or 'tab' indent: 4,
quotes: 'single', // or 'double' quotes: 'single',
semi: 'always', semi: 'always',
}, },
typescript: true, typescript: true,
vue: true, vue: true,
rules: { rules: {
'curly': ['error', 'multi-line'],
'vue/block-order': [ 'vue/block-order': [
'error', 'error',
{ {
order: ['template', 'script', 'style'], order: ['template', 'script', 'style'],
}, },
], ],
'style/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'semi',
requireLast: true,
},
singleline: {
delimiter: 'semi',
requireLast: false,
},
multilineDetection: 'brackets',
},
],
}, },
}); });

View File

@ -1,13 +1,21 @@
{ {
"name": "fes.js", "name": "fes.js",
"type": "module",
"version": "3.1.1", "version": "3.1.1",
"private": true,
"description": "一个好用的前端管理台快速开发框架", "description": "一个好用的前端管理台快速开发框架",
"preferGlobal": true, "preferGlobal": true,
"private": true,
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],
"type": "module", "license": "MIT",
"keywords": [
"管理端",
"fes",
"fast",
"easy",
"strong"
],
"scripts": { "scripts": {
"bootstrap": "pnpm i", "bootstrap": "pnpm i",
"dev": "node scripts/build.mjs --watch", "dev": "node scripts/build.mjs --watch",
@ -18,17 +26,10 @@
"docs:build": "vitepress build docs", "docs:build": "vitepress build docs",
"docs:build-pages": "BASE=fes.js vitepress build docs", "docs:build-pages": "BASE=fes.js vitepress build docs",
"test": "fes test", "test": "fes test",
"lint": "eslint -c ./.eslintrc.js --ignore-pattern='templates' --ext .js,.jsx,.vue,.ts", "lint": "eslint --ignore-pattern='templates'",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"hooks:sync": "simple-git-hooks"
}, },
"license": "MIT",
"keywords": [
"管理端",
"fes",
"fast",
"easy",
"strong"
],
"dependencies": { "dependencies": {
"chalk": "^5.0.1", "chalk": "^5.0.1",
"conventional-changelog-cli": "^4.1.0", "conventional-changelog-cli": "^4.1.0",
@ -38,14 +39,14 @@
"semver": "^7.3.6" "semver": "^7.3.6"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^2.1.1", "@antfu/eslint-config": "^2.6.2",
"@commitlint/cli": "^11.0.0", "@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0", "@commitlint/config-conventional": "^11.0.0",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"commitizen": "^4.3.0", "commitizen": "^4.3.0",
"cz-conventional-changelog": "^3.3.0", "cz-conventional-changelog": "^3.3.0",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"eslint": "^8.54.0", "eslint": "^8.56.0",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"lint-staged": "^13.2.0", "lint-staged": "^13.2.0",
"simple-git-hooks": "^2.9.0", "simple-git-hooks": "^2.9.0",
@ -54,15 +55,15 @@
"vue": "^3.3.4", "vue": "^3.3.4",
"yargs-parser": "^21.1.1" "yargs-parser": "^21.1.1"
}, },
"simple-git-hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint"
},
"lint-staged": { "lint-staged": {
"*.{js,jsx,vue,ts}": [ "*.{js,jsx,vue,ts}": [
"npm run lint" "npm run lint"
] ]
}, },
"simple-git-hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
},
"config": { "config": {
"commitizen": { "commitizen": {
"path": "./node_modules/cz-conventional-changelog" "path": "./node_modules/cz-conventional-changelog"

View File

@ -1,7 +1,7 @@
<template> <template>
<f-layout class="main-layout"> <FLayout class="main-layout">
<template v-if="currentNavigation === 'side'"> <template v-if="currentNavigation === 'side'">
<f-aside <FAside
v-model:collapsed="collapsedRef" v-model:collapsed="collapsedRef"
:fixed="isFixedSidebar" :fixed="isFixedSidebar"
:width="`${sideWidth}px`" :width="`${sideWidth}px`"
@ -10,41 +10,43 @@
:inverted="theme === 'dark'" :inverted="theme === 'dark'"
> >
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img" /> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="title" class="logo-name">{{ title }}</div> <div v-if="title" class="logo-name">
{{ title }}
</div>
</div> </div>
<Menu <LayoutMenu
class="layout-menu" class="layout-menu"
:menus="menus" :menus="menus"
:collapsed="collapsedRef" :collapsed="collapsedRef"
mode="vertical" mode="vertical"
:inverted="theme === 'dark'" :inverted="theme === 'dark'"
:expandedKeys="menuProps?.expandedKeys" :expanded-keys="menuProps?.expandedKeys"
:defaultExpandAll="menuProps?.defaultExpandAll" :default-expand-all="menuProps?.defaultExpandAll"
:accordion="menuProps?.accordion" :accordion="menuProps?.accordion"
/> />
</f-aside> </FAside>
<f-layout :fixed="isFixedSidebar" :style="sideStyleRef"> <FLayout :fixed="isFixedSidebar" :style="sideStyleRef">
<f-header ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef"> <FHeader ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef">
<div class="layout-header-custom"> <div class="layout-header-custom">
<slot name="renderCustom" :menus="menus"></slot> <slot name="renderCustom" :menus="menus" />
</div> </div>
<template v-if="locale"> <template v-if="locale">
<slot name="locale"></slot> <slot name="locale" />
</template> </template>
</f-header> </FHeader>
<f-layout :embedded="!multiTabs" :fixed="currentFixedHeaderRef" :style="headerStyleRef"> <FLayout :embedded="!multiTabs" :fixed="currentFixedHeaderRef" :style="headerStyleRef">
<f-main class="layout-main"> <FMain class="layout-main">
<MultiTabProvider :multiTabs="multiTabs" /> <MultiTabProvider :multi-tabs="multiTabs" />
</f-main> </FMain>
<f-footer v-if="footer" class="layout-footer"> <FFooter v-if="footer" class="layout-footer">
{{ footer }} {{ footer }}
</f-footer> </FFooter>
</f-layout> </FLayout>
</f-layout> </FLayout>
</template> </template>
<template v-else-if="currentNavigation === 'left-right'"> <template v-else-if="currentNavigation === 'left-right'">
<f-aside <FAside
v-model:collapsed="collapsedRef" v-model:collapsed="collapsedRef"
:fixed="isFixedSidebar" :fixed="isFixedSidebar"
:width="`${sideWidth}px`" :width="`${sideWidth}px`"
@ -55,121 +57,127 @@
<div class="flex-between"> <div class="flex-between">
<div> <div>
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img" /> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="title" class="logo-name">{{ title }}</div> <div v-if="title" class="logo-name">
{{ title }}
</div>
</div> </div>
<Menu <LayoutMenu
class="layout-menu" class="layout-menu"
:menus="menus" :menus="menus"
:collapsed="collapsedRef" :collapsed="collapsedRef"
mode="vertical" mode="vertical"
:inverted="theme === 'dark'" :inverted="theme === 'dark'"
:expandedKeys="menuProps?.expandedKeys" :expanded-keys="menuProps?.expandedKeys"
:defaultExpandAll="menuProps?.defaultExpandAll" :default-expand-all="menuProps?.defaultExpandAll"
:accordion="menuProps?.accordion" :accordion="menuProps?.accordion"
/> />
</div> </div>
<div> <div>
<div class="layout-aside-custom"> <div class="layout-aside-custom">
<slot name="renderCustom" :menus="menus"></slot> <slot name="renderCustom" :menus="menus" />
</div> </div>
<div v-if="locale" class="layout-aside-locale"> <div v-if="locale" class="layout-aside-locale">
<slot name="locale"></slot> <slot name="locale" />
</div> </div>
</div> </div>
</div> </div>
</f-aside> </FAside>
<f-layout :fixed="isFixedSidebar" :style="sideStyleRef"> <FLayout :fixed="isFixedSidebar" :style="sideStyleRef">
<f-layout :embedded="!multiTabs"> <FLayout :embedded="!multiTabs">
<f-main class="layout-main"> <FMain class="layout-main">
<MultiTabProvider :multiTabs="multiTabs" /> <MultiTabProvider :multi-tabs="multiTabs" />
</f-main> </FMain>
<f-footer v-if="footer" class="layout-footer"> <FFooter v-if="footer" class="layout-footer">
{{ footer }} {{ footer }}
</f-footer> </FFooter>
</f-layout> </FLayout>
</f-layout> </FLayout>
</template> </template>
<template v-else-if="currentNavigation === 'top'"> <template v-else-if="currentNavigation === 'top'">
<f-header ref="headerRef" class="layout-header" :inverted="theme === 'dark'" :fixed="currentFixedHeaderRef"> <FHeader ref="headerRef" class="layout-header" :inverted="theme === 'dark'" :fixed="currentFixedHeaderRef">
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img" /> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="title" class="logo-name">{{ title }}</div> <div v-if="title" class="logo-name">
{{ title }}
</div>
</div> </div>
<Menu <LayoutMenu
class="layout-menu" class="layout-menu"
:menus="menus" :menus="menus"
mode="horizontal" mode="horizontal"
:inverted="theme === 'dark'" :inverted="theme === 'dark'"
:expandedKeys="menuProps?.expandedKeys" :expanded-keys="menuProps?.expandedKeys"
:defaultExpandAll="menuProps?.defaultExpandAll" :default-expand-all="menuProps?.defaultExpandAll"
:accordion="menuProps?.accordion" :accordion="menuProps?.accordion"
/> />
<div class="layout-header-custom"> <div class="layout-header-custom">
<slot name="renderCustom" :menus="menus"></slot> <slot name="renderCustom" :menus="menus" />
</div> </div>
<template v-if="locale"> <template v-if="locale">
<slot name="locale"></slot> <slot name="locale" />
</template> </template>
</f-header> </FHeader>
<f-layout :embedded="!multiTabs" :fixed="currentFixedHeaderRef" :style="headerStyleRef"> <FLayout :embedded="!multiTabs" :fixed="currentFixedHeaderRef" :style="headerStyleRef">
<f-main class="layout-main"> <FMain class="layout-main">
<MultiTabProvider :multiTabs="multiTabs" /> <MultiTabProvider :multi-tabs="multiTabs" />
</f-main> </FMain>
<f-footer v-if="footer" class="layout-footer"> <FFooter v-if="footer" class="layout-footer">
{{ footer }} {{ footer }}
</f-footer> </FFooter>
</f-layout> </FLayout>
</template> </template>
<template v-else-if="currentNavigation === 'mixin'"> <template v-else-if="currentNavigation === 'mixin'">
<f-header ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef" :inverted="theme === 'dark'"> <FHeader ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef" :inverted="theme === 'dark'">
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img" /> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="title" class="logo-name">{{ title }}</div> <div v-if="title" class="logo-name">
{{ title }}
</div>
</div> </div>
<div class="layout-header-custom"> <div class="layout-header-custom">
<slot name="renderCustom" :menus="menus"></slot> <slot name="renderCustom" :menus="menus" />
</div> </div>
<template v-if="locale"> <template v-if="locale">
<slot name="locale"></slot> <slot name="locale" />
</template> </template>
</f-header> </FHeader>
<f-layout :fixed="currentFixedHeaderRef" :style="headerStyleRef"> <FLayout :fixed="currentFixedHeaderRef" :style="headerStyleRef">
<f-aside v-model:collapsed="collapsedRef" :fixed="isFixedSidebar" :width="`${sideWidth}px`" collapsible class="layout-aside"> <FAside v-model:collapsed="collapsedRef" :fixed="isFixedSidebar" :width="`${sideWidth}px`" collapsible class="layout-aside">
<Menu <LayoutMenu
class="layout-menu" class="layout-menu"
:menus="menus" :menus="menus"
:collapsed="collapsedRef" :collapsed="collapsedRef"
mode="vertical" mode="vertical"
:expandedKeys="menuProps?.expandedKeys" :expanded-keys="menuProps?.expandedKeys"
:defaultExpandAll="menuProps?.defaultExpandAll" :default-expand-all="menuProps?.defaultExpandAll"
:accordion="menuProps?.accordion" :accordion="menuProps?.accordion"
/> />
</f-aside> </FAside>
<f-layout :embedded="!multiTabs" :fixed="isFixedSidebar" :style="sideStyleRef"> <FLayout :embedded="!multiTabs" :fixed="isFixedSidebar" :style="sideStyleRef">
<f-main class="layout-main"> <FMain class="layout-main">
<MultiTabProvider :multiTabs="multiTabs" /> <MultiTabProvider :multi-tabs="multiTabs" />
</f-main> </FMain>
<f-footer v-if="footer" class="layout-footer"> <FFooter v-if="footer" class="layout-footer">
{{ footer }} {{ footer }}
</f-footer> </FFooter>
</f-layout> </FLayout>
</f-layout> </FLayout>
</template> </template>
<template v-else> <template v-else>
<f-main class="layout-main"> <FMain class="layout-main">
<router-view></router-view> <router-view />
</f-main> </FMain>
</template> </template>
</f-layout> </FLayout>
</template> </template>
<script> <script>
import { ref, computed, watch, nextTick } from 'vue';
import { useRoute, useRouter } from '@@/core/coreExports'; import { useRoute, useRouter } from '@@/core/coreExports';
import { FLayout, FAside, FMain, FFooter, FHeader } from '@fesjs/fes-design'; import { FAside, FFooter, FHeader, FLayout, FMain } from '@fesjs/fes-design';
import { computed, nextTick, ref, watch } from 'vue';
import defaultLogo from '../assets/logo.png'; import defaultLogo from '../assets/logo.png';
import Menu from './Menu.vue'; import LayoutMenu from './Menu.vue';
import MultiTabProvider from './MultiTabProvider.vue'; import MultiTabProvider from './MultiTabProvider.vue';
export default { export default {
@ -179,7 +187,7 @@ export default {
FMain, FMain,
FFooter, FFooter,
FHeader, FHeader,
Menu, LayoutMenu,
MultiTabProvider, MultiTabProvider,
}, },
props: { props: {
@ -209,6 +217,9 @@ export default {
type: String, type: String,
default: 'side', // side / top / mixin // default: 'side', // side / top / mixin //
}, },
navigationOnError: {
type: [String, Function], // 403, 404 navigation
},
isFixedHeader: { isFixedHeader: {
type: Boolean, type: Boolean,
default: false, default: false,
@ -241,6 +252,12 @@ export default {
if (route.meta.layout && route.meta.layout.navigation !== undefined) { if (route.meta.layout && route.meta.layout.navigation !== undefined) {
return route.meta.layout.navigation; return route.meta.layout.navigation;
} }
if (props.navigationOnError !== undefined && ['/403', '/404'].includes(route.path)) {
if (typeof props.navigationOnError === 'function') {
return props.navigationOnError(route);
}
return props.navigationOnError;
}
return props.navigation; return props.navigation;
}); });
@ -278,6 +295,7 @@ export default {
}, },
}; };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.main-layout { .main-layout {
height: 100vh; height: 100vh;

View File

@ -1,9 +1,9 @@
import { unref, defineComponent, computed } from 'vue';
import { plugin } from '@@/core/coreExports'; import { plugin } from '@@/core/coreExports';
import { getRoutes } from '@@/core/routes/routes'; import { getRoutes } from '@@/core/routes/routes';
// eslint-disable-next-line import/extensions import { computed, defineComponent, unref } from 'vue';
import getConfig from '../helpers/getConfig';
import fillMenu from '../helpers/fillMenu'; import fillMenu from '../helpers/fillMenu';
import getConfig from '../helpers/getConfig';
import BaseLayout from './BaseLayout.vue'; import BaseLayout from './BaseLayout.vue';
const Layout = defineComponent({ const Layout = defineComponent({
@ -33,11 +33,12 @@ const Layout = defineComponent({
return ( return (
<BaseLayout <BaseLayout
menus={filledMenuRef.value} menus={filledMenuRef.value}
locale={localeShared ? true : false} locale={!!localeShared}
title={config.title} title={config.title}
logo={config.logo} logo={config.logo}
theme={config.theme} theme={config.theme}
navigation={config.navigation} navigation={config.navigation}
navigationOnError={config.navigationOnError}
isFixedHeader={config.isFixedHeader} isFixedHeader={config.isFixedHeader}
isFixedSidebar={config.isFixedSidebar} isFixedSidebar={config.isFixedSidebar}
multiTabs={config.multiTabs} multiTabs={config.multiTabs}
@ -45,7 +46,7 @@ const Layout = defineComponent({
footer={config.footer} footer={config.footer}
menuProps={config.menuProps} menuProps={config.menuProps}
v-slots={slots} v-slots={slots}
></BaseLayout> />
); );
}; };
}, },

View File

@ -1,6 +1,6 @@
import { Component, VNode, Ref } from 'vue'; import type { MenuOption } from '@fesjs/fes-design/es/menu/interface';
import { Router, RouteLocationNormalized, NavigationGuardNext, NavigationGuard } from 'vue-router'; import type { Component, Ref, VNode } from 'vue';
import { MenuOption } from '@fesjs/fes-design/es/menu/interface'; import type { NavigationGuard, NavigationGuardNext, RouteLocationNormalized, Router } from 'vue-router';
interface CustomNavigationGuardOption { interface CustomNavigationGuardOption {
router: Router; router: Router;
@ -22,6 +22,8 @@ interface Menu {
children?: Menu[]; children?: Menu[];
} }
type Navigation = 'side' | 'mixin' | 'top' | 'left-right';
export const Page: Component; export const Page: Component;
export function useTabTitle(title: string | Ref<string>): void; export function useTabTitle(title: string | Ref<string>): void;
@ -29,7 +31,8 @@ export function useTabTitle(title: string | Ref<string>): void;
interface LayoutRuntimeConfig { interface LayoutRuntimeConfig {
footer?: string; footer?: string;
theme?: 'dark' | 'light'; theme?: 'dark' | 'light';
navigation?: 'side' | 'top' | 'mixin' | 'left-right'; navigation?: Navigation;
navigationOnError?: Navigation | ((route: RouteLocationNormalized) => Navigation | null);
title?: string; title?: string;
isFixedHeader?: boolean; isFixedHeader?: boolean;
isFixedSidebar?: boolean; isFixedSidebar?: boolean;
@ -51,28 +54,29 @@ declare module '@fesjs/fes' {
interface RouteMeta { interface RouteMeta {
'keep-alive'?: boolean; 'keep-alive'?: boolean;
layout?: { layout?: {
navigation?: 'side' | 'mixin' | 'top' | 'left-right' | null; navigation?: Navigation | null;
}; };
} }
interface PluginBuildConfig { interface PluginBuildConfig {
layout?: layout?:
| { | {
footer: string; footer: string;
theme: 'dark' | 'light'; theme: 'dark' | 'light';
navigation: 'side' | 'top' | 'mixin' | 'left-right'; navigation: Navigation;
title: string; navigationOnError: Navigation;
isFixedHeader: boolean; title: string;
isFixedSidebar: boolean; isFixedHeader: boolean;
logo: string; isFixedSidebar: boolean;
multiTabs: boolean; logo: string;
sideWidth: number; multiTabs: boolean;
menus: Menu[]; sideWidth: number;
menuProps: { menus: Menu[];
expandedKeys: string[]; menuProps: {
defaultExpandAll: boolean; expandedKeys: string[];
accordion: boolean; defaultExpandAll: boolean;
}; accordion: boolean;
} };
}
| false; | false;
} }
interface PluginRuntimeConfig { interface PluginRuntimeConfig {

File diff suppressed because it is too large Load Diff