diff --git a/src/client/theme-default/components/NavBar.ts b/src/client/theme-default/components/NavBar.ts index b0e961942cfc..e64fc5fce1e1 100644 --- a/src/client/theme-default/components/NavBar.ts +++ b/src/client/theme-default/components/NavBar.ts @@ -1,29 +1,14 @@ -// TODO dropdowns import { computed } from 'vue' -import { useSiteData, useRoute } from 'vitepress' -import { withBase } from '../utils' - -const normalizePath = (path: string): string => { - path = path - .replace(/#.*$/, '') - .replace(/\?.*$/, '') - .replace(/\.html$/, '') - if (path.endsWith('/')) { - path += 'index' - } - return path -} +import { useSiteData } from 'vitepress' +import NavBarLink from './NavBarLink.vue' export default { - setup() { - const route = useRoute() - const isActiveLink = (link: string): boolean => { - return normalizePath(withBase(link)) === normalizePath(route.path) - } + components: { + NavBarLink + }, + setup() { return { - withBase, - isActiveLink, navData: process.env.NODE_ENV === 'production' ? // navbar items do not change in production diff --git a/src/client/theme-default/components/NavBar.vue b/src/client/theme-default/components/NavBar.vue index e7af130b7ad5..5c34229d4422 100644 --- a/src/client/theme-default/components/NavBar.vue +++ b/src/client/theme-default/components/NavBar.vue @@ -13,16 +13,11 @@ {{ $site.title }} @@ -44,18 +39,4 @@ .nav-links { list-style-type: none; } - -.nav-link { - color: var(--text-color); - margin-left: 1.5rem; - font-weight: 600; - display: inline-block; - height: 1.75rem; - line-height: 1.75rem; -} - -.nav-link:hover, -.nav-link.active { - border-bottom: 2px solid var(--accent-color); -} diff --git a/src/client/theme-default/components/NavBarLink.ts b/src/client/theme-default/components/NavBarLink.ts new file mode 100644 index 000000000000..973fd48044a6 --- /dev/null +++ b/src/client/theme-default/components/NavBarLink.ts @@ -0,0 +1,78 @@ +// TODO dropdowns +import { defineComponent, computed, PropType } from 'vue' +import { useRoute } from 'vitepress' +import { withBase, isExternal } from '../utils' +import { DefaultTheme } from '../config' +import OutboundLink from './icons/OutboundLink.vue' + +const normalizePath = (path: string): string => { + path = path + .replace(/#.*$/, '') + .replace(/\?.*$/, '') + .replace(/\.html$/, '') + if (path.endsWith('/')) { + path += 'index' + } + return path +} + +export default defineComponent({ + components: { + OutboundLink + }, + + props: { + item: { + type: Object as PropType, + required: true + } + }, + + setup(props) { + const item = props.item + + const route = useRoute() + + const classes = computed(() => ({ + active: isActiveLink.value, + external: isExternalLink.value + })) + + const isActiveLink = computed(() => { + return normalizePath(withBase(item.link)) === normalizePath(route.path) + }) + + const isExternalLink = computed(() => { + return isExternal(item.link) + }) + + const href = computed(() => { + return isExternalLink.value ? item.link : withBase(item.link) + }) + + const target = computed(() => { + if (item.target) { + return item.target + } + + return isExternalLink.value ? '_blank' : '' + }) + + const rel = computed(() => { + if (item.rel) { + return item.rel + } + + return isExternalLink.value ? 'noopener noreferrer' : '' + }) + + return { + classes, + isActiveLink, + isExternalLink, + href, + target, + rel + } + } +}) diff --git a/src/client/theme-default/components/NavBarLink.vue b/src/client/theme-default/components/NavBarLink.vue new file mode 100644 index 000000000000..4a5f57caed4e --- /dev/null +++ b/src/client/theme-default/components/NavBarLink.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/src/client/theme-default/components/icons/OutboundLink.vue b/src/client/theme-default/components/icons/OutboundLink.vue new file mode 100644 index 000000000000..06f8ba08b093 --- /dev/null +++ b/src/client/theme-default/components/icons/OutboundLink.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/client/theme-default/utils.ts b/src/client/theme-default/utils.ts index 4c6aee47dca2..a743905817cd 100644 --- a/src/client/theme-default/utils.ts +++ b/src/client/theme-default/utils.ts @@ -2,11 +2,16 @@ import { useSiteData, Route } from 'vitepress' export const hashRE = /#.*$/ export const extRE = /\.(md|html)$/ +export const outboundRE = /^[a-z]+:/i export function withBase(path: string) { return (useSiteData().value.base + path).replace(/\/+/g, '/') } +export function isExternal(path: string): boolean { + return outboundRE.test(path) +} + export function isActive(route: Route, path?: string): boolean { if (path === undefined) { return false