51 lines
1.0 KiB
Vue
51 lines
1.0 KiB
Vue
<!-- components/TreeNode.vue -->
|
|
<script setup>
|
|
defineProps({ nodes: Array, depth: { type: Number, default: 0 } })
|
|
|
|
const router = useRouter()
|
|
|
|
function getTitle(node) {
|
|
if (node.title == "index") return "Index"
|
|
return node.title || node._path?.split('/').pop() || 'Home';
|
|
}
|
|
|
|
function navigate(path) {
|
|
if (!path) return
|
|
router.push(path)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ul :style="{ paddingLeft: depth ? '1rem' : '0' }">
|
|
<li v-for="node in nodes" :key="node.path ?? node.title">
|
|
|
|
<template v-if="!node.children?.length">
|
|
<a v-if="node.path" :href="node.path" @click.prevent="navigate(node.path)">
|
|
{{ getTitle(node) }}
|
|
</a>
|
|
<span v-else>{{ getTitle(node) }}</span>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<span>📁 {{ getTitle(node) }}</span>
|
|
<TreeNode :nodes="node.children" :depth="depth + 1" />
|
|
</template>
|
|
|
|
</li>
|
|
</ul>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
ul {
|
|
list-style: none;
|
|
padding-left: 0;
|
|
}
|
|
|
|
li {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
a {
|
|
color: var(--text-link);
|
|
}
|
|
</style> |