ec-admin/src/components/ty-sidebar.vue
liuyun c96151d2ae refactor: convert raw CSS to Tailwind @apply + search collapseCount=3
- 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>
2026-10-11 13:18:45 +08:00

124 lines
3.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>