feat: add external link support for nav items (#46)

pull/50/head
Kia King Ishii 5 years ago committed by GitHub
parent 583f02e488
commit 44e91bb986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

@ -13,16 +13,11 @@
<span>{{ $site.title }}</span>
</a>
<nav class="nav-links" v-if="navData">
<a
class="nav-link"
v-for="{ text, link, target, rel, ariaLabel } of navData"
:class="{ active: isActiveLink(link) }"
:href="withBase(link)"
:target="target"
:rel="rel"
:aria-label="ariaLabel"
>{{ text }}</a
>
<NavBarLink
v-for="item of navData"
:key="item.link"
:item="item"
/>
</nav>
</template>
@ -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);
}
</style>

@ -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<DefaultTheme.NavItemWithLink>,
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
}
}
})

@ -0,0 +1,35 @@
<template>
<a
class="nav-link"
:class="classes"
:href="href"
:target="target"
:rel="rel"
:aria-label="item.ariaLabel"
>
{{ item.text }}
<OutboundLink v-if="isExternalLink" />
</a>
</template>
<script src="./NavBarLink"></script>
<style>
.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);
}
.nav-link.external:hover {
border-bottom: 0;
}
</style>

@ -0,0 +1,31 @@
<template functional>
<svg
class="icon outbound"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
x="0px"
y="0px"
viewBox="0 0 100 100"
width="15"
height="15"
>
<path
fill="currentColor"
d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"
/>
<polygon
fill="currentColor"
points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"
/>
</svg>
</template>
<style>
.icon.outbound {
color: #aaa;
display: inline-block;
vertical-align: middle;
position: relative;
top: -1px;
}
</style>

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

Loading…
Cancel
Save