- ty-search-form 折叠默认数 2 → 3 - login/register/forgot/home/ty-header/ty-sidebar/ty-mixbar/ty-tabs/ty-footer/ty-setting-panel/icon/default 布局裸 CSS 转 @apply - 修复背景色工具类误写(bg-base→bg-bg-base、bg-page→bg-bg-page) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
124 lines
3.2 KiB
Vue
124 lines
3.2 KiB
Vue
<template>
|
||
<aside class="ty-sidebar" :style="{ width: `${collapsed ? COLLAPSED_WIDTH : width}px` }">
|
||
<el-scrollbar>
|
||
<el-menu
|
||
:default-active="activePath"
|
||
:collapse="collapsed"
|
||
:unique-opened="accordion"
|
||
:collapse-transition="false"
|
||
popper-class="ty-menu-popper"
|
||
@select="onSelect"
|
||
>
|
||
<template v-for="item in menus" :key="item.code">
|
||
<el-sub-menu v-if="item.children?.length" :index="item.code">
|
||
<template #title>
|
||
<icon type="iconify" :icon="item.icon ?? 'mdi:menu'" />
|
||
<span>{{ item.name }}</span>
|
||
</template>
|
||
<el-menu-item v-for="child in item.children" :key="child.code" :index="child.path ?? child.code">
|
||
<icon v-if="child.icon" type="iconify" :icon="child.icon" />
|
||
<span>{{ child.name }}</span>
|
||
</el-menu-item>
|
||
</el-sub-menu>
|
||
<el-menu-item v-else :index="item.path ?? item.code">
|
||
<icon type="iconify" :icon="item.icon ?? 'mdi:menu'" />
|
||
<span>{{ item.name }}</span>
|
||
</el-menu-item>
|
||
</template>
|
||
</el-menu>
|
||
</el-scrollbar>
|
||
</aside>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import type { ResourceNode } from '@/types/resource'
|
||
|
||
defineOptions({ name: 'TySidebar' })
|
||
|
||
const COLLAPSED_WIDTH = 64
|
||
|
||
withDefaults(
|
||
defineProps<{
|
||
/** 菜单树(字段对齐后端 resource)。 */
|
||
menus: ResourceNode[]
|
||
/** 是否折叠。 */
|
||
collapsed?: boolean
|
||
/** 展开时的宽度。 */
|
||
width?: number
|
||
/** 手风琴模式。 */
|
||
accordion?: boolean
|
||
/** 当前激活路径。 */
|
||
activePath?: string
|
||
}>(),
|
||
{
|
||
collapsed: false,
|
||
width: 210,
|
||
accordion: false,
|
||
activePath: '',
|
||
},
|
||
)
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'select', path: string): void
|
||
}>()
|
||
|
||
function onSelect(index: string): void {
|
||
emit('select', index)
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.ty-sidebar {
|
||
@apply sticky self-start shrink-0 overflow-hidden bg-bg-base border-r border-solid;
|
||
top: var(--ty-sidebar-top, 0);
|
||
height: var(--ty-sidebar-height, 100vh);
|
||
border-color: var(--wm-border-color-light);
|
||
@apply transition-[width] duration-200;
|
||
|
||
.el-menu {
|
||
@apply border-r-0;
|
||
--el-menu-bg-color: transparent;
|
||
--el-menu-text-color: var(--wm-color-text-regular);
|
||
--el-menu-hover-bg-color: var(--wm-bg-color-page);
|
||
--el-menu-active-color: var(--el-color-primary);
|
||
|
||
:deep(.el-menu-item),
|
||
:deep(.el-sub-menu__title) {
|
||
@apply my-0.5 mx-2 h-11 rounded-base;
|
||
line-height: 44px;
|
||
}
|
||
|
||
:deep(.el-menu-item.is-active) {
|
||
@apply font-medium;
|
||
background: var(--el-color-primary-light-9);
|
||
color: var(--el-color-primary);
|
||
}
|
||
|
||
:deep(.el-menu-item:hover),
|
||
:deep(.el-sub-menu__title:hover) {
|
||
@apply bg-bg-page;
|
||
}
|
||
|
||
:deep(.icon) {
|
||
@apply mr-2;
|
||
}
|
||
}
|
||
|
||
.el-menu--collapse {
|
||
:deep(.el-menu-item),
|
||
:deep(.el-sub-menu__title) {
|
||
@apply my-0.5 mx-1;
|
||
}
|
||
|
||
:deep(.icon) {
|
||
@apply mr-0 text-[24px];
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 折叠时弹出的子菜单(teleport 到 body,需全局样式)图标与文字间距 */
|
||
:global(.ty-menu-popper .el-menu-item .icon) {
|
||
@apply mr-2;
|
||
}
|
||
</style>
|