98 lines
No EOL
1.9 KiB
Vue
98 lines
No EOL
1.9 KiB
Vue
<script setup lang="ts">
|
|
import { computed, toRefs } from 'vue'
|
|
import { useRoute, withBase } from 'vitepress'
|
|
|
|
const props = defineProps<{
|
|
item: {
|
|
text: string
|
|
target?: string
|
|
rel?: string
|
|
ariaLabel?: string
|
|
activeMatch?: string
|
|
link: string
|
|
}
|
|
}>()
|
|
|
|
const propsRefs = toRefs(props)
|
|
|
|
const route = useRoute()
|
|
const linkProps = computed(() => {
|
|
const routePath = normalizePath(`/${route.data.relativePath}`)
|
|
|
|
let active = false
|
|
if (propsRefs.item.value.activeMatch) {
|
|
active = new RegExp(propsRefs.item.value.activeMatch).test(routePath)
|
|
} else {
|
|
const itemPath = normalizePath(propsRefs.item.value.link)
|
|
active =
|
|
itemPath === '/'
|
|
? itemPath === routePath
|
|
: routePath.startsWith(itemPath)
|
|
}
|
|
|
|
return {
|
|
class: {
|
|
active
|
|
},
|
|
href: withBase(propsRefs.item.value.link),
|
|
target: propsRefs.item.value.target || null,
|
|
rel: propsRefs.item.value.rel || null,
|
|
'aria-label': propsRefs.item.value.ariaLabel
|
|
}
|
|
})
|
|
|
|
function normalizePath(path: string): string {
|
|
return path
|
|
.replace(/#.*$/, '')
|
|
.replace(/\?.*$/, '')
|
|
.replace(/\.(html|md)$/, '')
|
|
.replace(/\/index$/, '/')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="nav-link">
|
|
<a class="item" v-bind="linkProps">
|
|
{{ item.text }}
|
|
</a>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.item {
|
|
display: block;
|
|
padding: 0 1.5rem;
|
|
line-height: 36px;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: var(--c-text);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.item:hover,
|
|
.item.active {
|
|
text-decoration: none;
|
|
color: var(--c-brand);
|
|
}
|
|
|
|
.item.external:hover {
|
|
border-bottom-color: transparent;
|
|
color: var(--c-text);
|
|
}
|
|
|
|
@media (min-width: 720px) {
|
|
.item {
|
|
border-bottom: 2px solid transparent;
|
|
padding: 0;
|
|
line-height: 24px;
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.item:hover,
|
|
.item.active {
|
|
border-bottom-color: var(--c-brand);
|
|
color: var(--c-text);
|
|
}
|
|
}
|
|
</style> |