This commit is contained in:
oneao committed 2026-10-09 22:05:02 +08:00
1 parent 0be0b0767a
commit 5f28a10d89
852 files changed
+8962 -111755

No files matched your search

@@ -0,0 +1,96 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { House } from '@lucide/vue'
import { usePreferencesStore } from '@/preferences'
import { findMenuItemByPath, findParentKeyByPath } from '@/router'
import { menuItems } from '@/constants/menu'
/**
* 面包屑。
* 数据来自菜单常量:父级分组 + 当前页,与侧栏同源,不额外维护。
*/
const route = useRoute()
const prefStore = usePreferencesStore()
const pref = computed(() => prefStore.preferences)
/** 当前路径对应的祖先链:[分组, 当前页] */
const crumbs = computed(() => {
const list: Array<{ title: string; path?: string }> = []
if (pref.value.breadcrumb.showHome) {
list.push({ title: '首页', path: '/' })
}
const current = findMenuItemByPath(route.path)
const parentKey = findParentKeyByPath(route.path)
const parent = parentKey ? menuItems.find((item) => item.key === parentKey) : undefined
if (parent) list.push({ title: parent.title, path: parent.path })
if (current && current.key !== parent?.key) list.push({ title: current.title })
return list
})
/** 只有一个时按偏好隐藏 */
const visible = computed(() => {
if (!pref.value.breadcrumb.enable) return false
if (pref.value.breadcrumb.hideOnlyOne && crumbs.value.length <= 1) return false
return crumbs.value.length > 0
})
</script>
<template>
<nav
v-if="visible"
class="layout-breadcrumb"
:class="{ 'is-background': pref.breadcrumb.styleType === 'background' }"
>
<template v-for="(crumb, index) in crumbs" :key="crumb.title">
<span v-if="index > 0" class="layout-breadcrumb__sep">/</span>
<RouterLink v-if="crumb.path" class="layout-breadcrumb__item" :to="crumb.path">
<House v-if="index === 0 && pref.breadcrumb.showHome" :size="14" />
<span>{{ crumb.title }}</span>
</RouterLink>
<span v-else class="layout-breadcrumb__item is-current">{{ crumb.title }}</span>
</template>
</nav>
</template>
<style lang="scss" scoped>
.layout-breadcrumb {
display: flex;
align-items: center;
gap: 6px;
min-width: 0;
font-size: 13px;
&.is-background {
padding: 4px 10px;
background: var(--g3-color-fill-hover, #f2f3f5);
border-radius: 6px;
}
&__sep {
color: var(--g3-color-text-tertiary, #86909c);
}
&__item {
display: inline-flex;
align-items: center;
gap: 4px;
color: var(--g3-color-text-secondary, #4e5969);
text-decoration: none;
&:hover {
color: var(--g3-color-primary, #165dff);
}
&.is-current {
color: var(--g3-color-text, #1f2329);
}
}
}
</style>