feat(projects): 添加头部折叠按钮

This commit is contained in:
Soybean
2022-01-10 12:43:04 +08:00
parent 6d132c5977
commit a090d398fc
15 changed files with 548 additions and 396 deletions

View File

@ -0,0 +1,38 @@
<template>
<div v-if="showTooltip">
<n-tooltip :placement="placement" trigger="hover">
<template #trigger>
<div class="flex-center h-full cursor-pointer hover:bg-[#f6f6f6] dark:hover:bg-[#333]" :class="contentClass">
<slot></slot>
</div>
</template>
{{ tooltipContent }}
</n-tooltip>
</div>
<div v-else class="flex-center cursor-pointer hover:bg-[#f6f6f6] dark:hover:bg-[#333]" :class="contentClass">
<slot></slot>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import { NTooltip } from 'naive-ui';
import type { FollowerPlacement } from 'vueuc';
interface Props {
/** tooltip显示文本 */
tooltipContent?: string;
/** tooltip的位置 */
placement?: FollowerPlacement;
/** class类 */
contentClass?: string;
}
const props = withDefaults(defineProps<Props>(), {
tooltipContent: '',
placement: 'bottom',
contentClass: ''
});
const showTooltip = computed(() => Boolean(props.tooltipContent));
</script>
<style scoped></style>

View File

@ -2,5 +2,6 @@ import NaiveProvider from './NaiveProvider/index.vue';
import SystemLogo from './SystemLogo/index.vue';
import DarkModeSwitch from './DarkModeSwitch/index.vue';
import DarkModeContainer from './DarkModeContainer/index.vue';
import HoverContainer from './HoverContainer/index.vue';
export { NaiveProvider, SystemLogo, DarkModeSwitch, DarkModeContainer };
export { NaiveProvider, SystemLogo, DarkModeSwitch, DarkModeContainer, HoverContainer };

View File

@ -1,2 +1,3 @@
export * from './system';
export * from './router';
export * from './layout';

View File

@ -0,0 +1,70 @@
import { computed } from 'vue';
import { useAppStore, useThemeStore } from '@/store';
import type { ThemeLayoutMode, GlobalHeaderProps } from '@/interface';
type LayoutHeaderProps = Record<ThemeLayoutMode, GlobalHeaderProps>;
export function useBasicLayout() {
const app = useAppStore();
const theme = useThemeStore();
type LayoutMode = 'vertical' | 'horizontal';
const mode = computed(() => {
const vertical: LayoutMode = 'vertical';
const horizontal: LayoutMode = 'horizontal';
return theme.layout.mode.includes(vertical) ? vertical : horizontal;
});
const layoutHeaderProps: LayoutHeaderProps = {
vertical: {
showLogo: false,
showHeaderMenu: false,
showMenuCollape: true
},
'vertical-mix': {
showLogo: false,
showHeaderMenu: false,
showMenuCollape: false
},
horizontal: {
showLogo: true,
showHeaderMenu: true,
showMenuCollape: false
},
'horizontal-mix': {
showLogo: true,
showHeaderMenu: false,
showMenuCollape: true
}
};
const headerProps = computed(() => layoutHeaderProps[theme.layout.mode]);
const siderVisible = computed(() => theme.layout.mode !== 'horizontal');
const siderWidth = computed(() => {
const { width, mixWidth, mixChildMenuWidth } = theme.sider;
const isVerticalMix = theme.layout.mode === 'vertical-mix';
let w = isVerticalMix ? mixWidth : width;
if (isVerticalMix && app.mixSiderFixed) {
w += mixChildMenuWidth;
}
return w;
});
const siderCollapsedWidth = computed(() => {
const { collapsedWidth, mixCollapsedWidth, mixChildMenuWidth } = theme.sider;
const isVerticalMix = theme.layout.mode === 'vertical-mix';
let w = isVerticalMix ? mixCollapsedWidth : collapsedWidth;
if (isVerticalMix && app.mixSiderFixed) {
w += mixChildMenuWidth;
}
return w;
});
return {
mode,
headerProps,
siderVisible,
siderWidth,
siderCollapsedWidth
};
}

View File

@ -1,3 +1,4 @@
export * from './enum';
export * from './theme';
export * from './system';
export * from './layout';

9
src/interface/layout.ts Normal file
View File

@ -0,0 +1,9 @@
/** 全局头部属性 */
export interface GlobalHeaderProps {
/** 显示logo */
showLogo: boolean;
/** 显示头部菜单 */
showHeaderMenu: boolean;
/** 显示菜单折叠按钮 */
showMenuCollape: boolean;
}

View File

@ -8,11 +8,11 @@
:sider-visible="siderVisible"
:sider-width="siderWidth"
:sider-collapsed-width="siderCollapsedWidth"
:sider-collapse="false"
:sider-collapse="app.siderCollapse"
:fixed-footer="theme.footer.fixed"
>
<template #header>
<global-header />
<global-header v-bind="headerProps" />
</template>
<template #tab>
<global-tab />
@ -29,41 +29,14 @@
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useAppStore, useThemeStore } from '@/store';
import { useBasicLayout } from '@/composables';
import { SoybeanLayout } from '@/package';
import { SettingDrawer, GlobalHeader, GlobalTab, GlobalSider, GlobalContent, GlobalFooter } from '../common';
const app = useAppStore();
const theme = useThemeStore();
const siderVisible = computed(() => theme.layout.mode !== 'horizontal');
type LayoutMode = 'vertical' | 'horizontal';
const mode = computed(() => {
const vertical: LayoutMode = 'vertical';
const horizontal: LayoutMode = 'horizontal';
return theme.layout.mode.includes(vertical) ? vertical : horizontal;
});
const siderWidth = computed(() => {
const { width, mixWidth, mixChildMenuWidth } = theme.sider;
const isVerticalMix = theme.layout.mode === 'vertical-mix';
let w = isVerticalMix ? mixWidth : width;
if (isVerticalMix && app.mixSiderFixed) {
w += mixChildMenuWidth;
}
return w;
});
const siderCollapsedWidth = computed(() => {
const { collapsedWidth, mixCollapsedWidth, mixChildMenuWidth } = theme.sider;
const isVerticalMix = theme.layout.mode === 'vertical-mix';
let w = isVerticalMix ? mixCollapsedWidth : collapsedWidth;
if (isVerticalMix && app.mixSiderFixed) {
w += mixChildMenuWidth;
}
return w;
});
const { mode, headerProps, siderVisible, siderWidth, siderCollapsedWidth } = useBasicLayout();
</script>
<style scoped></style>

View File

@ -0,0 +1,14 @@
<template>
<hover-container class="w-40px h-full" @click="app.toggleSiderCollapse">
<icon-line-md-menu-unfold-left v-if="app.siderCollapse" class="text-16px" />
<icon-line-md-menu-fold-left v-else class="text-16px" />
</hover-container>
</template>
<script lang="ts" setup>
import { HoverContainer } from '@/components';
import { useAppStore } from '@/store';
const app = useAppStore();
</script>
<style scoped></style>

View File

@ -0,0 +1,3 @@
import MenuCollapse from './MenuCollapse.vue';
export { MenuCollapse };

View File

@ -1,9 +1,32 @@
<template>
<dark-mode-container class="global-header flex-y-center h-full"></dark-mode-container>
<dark-mode-container class="global-header flex-y-center h-full">
<global-logo v-if="showLogo" :show-title="true" class="h-full" :style="{ width: theme.sider.width + 'px' }" />
<div v-if="!showHeaderMenu" class="flex-1-hidden flex-y-center h-full">
<menu-collapse v-if="showMenuCollape" />
<!-- <global-breadcrumb v-if="theme.header.crumb.visible" /> -->
</div>
</dark-mode-container>
</template>
<script setup lang="ts">
import { DarkModeContainer } from '@/components';
import { useThemeStore } from '@/store';
import type { GlobalHeaderProps } from '@/interface';
import GlobalLogo from '../GlobalLogo/index.vue';
import { MenuCollapse } from './components';
interface Props {
/** 显示logo */
showLogo: GlobalHeaderProps['showLogo'];
/** 显示头部菜单 */
showHeaderMenu: GlobalHeaderProps['showHeaderMenu'];
/** 显示菜单折叠按钮 */
showMenuCollape: GlobalHeaderProps['showMenuCollape'];
}
defineProps<Props>();
const theme = useThemeStore();
</script>
<style scoped>
.global-header {

View File

@ -0,0 +1,23 @@
<template>
<router-link :to="routeHomePath" class="flex-center w-full nowrap-hidden">
<system-logo class="w-32px h-32px text-primary" />
<h2 v-if="showTitle" class="pl-8px text-16px font-bold text-primary">{{ title }}</h2>
</router-link>
</template>
<script setup lang="ts">
import { SystemLogo } from '@/components';
import { routePath } from '@/router';
import { useAppInfo } from '@/composables';
interface Props {
/** 显示名字 */
showTitle: boolean;
}
defineProps<Props>();
const { title } = useAppInfo();
const routeHomePath = routePath('root');
</script>
<style scoped></style>

View File

@ -4,5 +4,6 @@ import GlobalTab from './GlobalTab/index.vue';
import GlobalSider from './GlobalSider/index.vue';
import GlobalContent from './GlobalContent/index.vue';
import GlobalFooter from './GlobalFooter/index.vue';
import GlobalLogo from './GlobalLogo/index.vue';
export { SettingDrawer, GlobalHeader, GlobalTab, GlobalSider, GlobalContent, GlobalFooter };
export { SettingDrawer, GlobalHeader, GlobalTab, GlobalSider, GlobalContent, GlobalFooter, GlobalLogo };

View File

@ -20,6 +20,8 @@ interface AppStore {
toggleSettingdrawerVisible(): void;
/** 侧边栏折叠状态 */
siderCollapse: Ref<boolean>;
/** 折叠/展开 侧边栏折叠状态 */
toggleSiderCollapse(): void;
/** 设置侧边栏折叠状态 */
setSiderCollapse(collapse: boolean): void;
/** vertical-mix模式下 侧边栏的固定状态 */
@ -41,7 +43,7 @@ export const useAppStore = defineStore('app-store', () => {
} = useModalVisible();
// 侧边栏的折叠状态
const { bool: siderCollapse, setBool: setSiderCollapse } = useBoolean();
const { bool: siderCollapse, setBool: setSiderCollapse, toggle: toggleSiderCollapse } = useBoolean();
// vertical-mix模式下 侧边栏的固定状态
const { bool: mixSiderFixed, setBool: setMixSiderIsFixed } = useBoolean();
@ -55,6 +57,7 @@ export const useAppStore = defineStore('app-store', () => {
toggleSettingdrawerVisible,
siderCollapse,
setSiderCollapse,
toggleSiderCollapse,
mixSiderFixed,
setMixSiderIsFixed
};