mirror of https://github.com/vuejs/vitepress
parent
796a1a6730
commit
255a2c4853
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div class="theme">
|
||||||
|
<h1>404</h1>
|
||||||
|
<blockquote>{{ getMsg() }}</blockquote>
|
||||||
|
<a :href="$site.base" aria-label="go to home">
|
||||||
|
Take me home.
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const msgs = [
|
||||||
|
`There's nothing here.`,
|
||||||
|
`How did we get here?`,
|
||||||
|
`That's a Four-Oh-Four.`,
|
||||||
|
`Looks like we've got some broken links.`
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup: () => ({
|
||||||
|
getMsg() {
|
||||||
|
return msgs[Math.floor(Math.random() * msgs.length)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,19 +1,94 @@
|
|||||||
<template>
|
<template>
|
||||||
<a
|
<a
|
||||||
class="site-title"
|
class="title"
|
||||||
:aria-label="$site.title + ', back to home'"
|
:aria-label="$site.title + ', back to home'"
|
||||||
:href="$site.base"
|
:href="$site.base"
|
||||||
>{{ $site.title }}</a
|
|
||||||
>
|
>
|
||||||
<ul class="nav-links">
|
<img
|
||||||
<li><a href="/hello/index">hello</a></li>
|
class="logo"
|
||||||
</ul>
|
v-if="$theme.logo"
|
||||||
|
:src="withBase($theme.logo)"
|
||||||
|
alt="logo"
|
||||||
|
/>
|
||||||
|
<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
|
||||||
|
>
|
||||||
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useSiteData, useRoute } from 'vitepress'
|
||||||
|
import { withBase } from '../utils'
|
||||||
|
|
||||||
|
const normalizePath = (path) => {
|
||||||
|
path = path
|
||||||
|
.replace(/#.*$/, '')
|
||||||
|
.replace(/\?.*$/, '')
|
||||||
|
.replace(/\.html$/, '')
|
||||||
|
if (path.endsWith('/')) {
|
||||||
|
path += 'index'
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const route = useRoute()
|
||||||
|
const isActiveLink = (link) => {
|
||||||
|
return normalizePath(withBase(link)) === normalizePath(route.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
withBase,
|
||||||
|
isActiveLink,
|
||||||
|
// use computed in dev for hot reload
|
||||||
|
navData: __DEV__
|
||||||
|
? computed(() => useSiteData().value.themeConfig.nav)
|
||||||
|
: useSiteData().value.themeConfig.nav
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.site-title {
|
.title {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
height: 1.3rem;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
color: var(--text-color);
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
font-weight: 500;
|
||||||
|
display: inline-block;
|
||||||
|
height: 1.75rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover,
|
||||||
|
.nav-link.active {
|
||||||
|
border-bottom: 2px solid var(--accent-color);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
export namespace DefaultTheme {
|
||||||
|
export interface Config {
|
||||||
|
logo?: string
|
||||||
|
nav?: NavItem[] | false
|
||||||
|
sidebar?: SideBarConfig | MultiSideBarConfig
|
||||||
|
search?: SearchConfig | false
|
||||||
|
editLink?: EditLinkConfig | false
|
||||||
|
lastUpdated?: string | boolean
|
||||||
|
prevLink?: boolean
|
||||||
|
nextLink?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// navbar --------------------------------------------------------------------
|
||||||
|
|
||||||
|
export type NavItem = NavItemWithLink | NavItemWithChildren
|
||||||
|
|
||||||
|
export interface NavItemWithLink extends NavItemBase {
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NavItemWithChildren extends NavItemBase {
|
||||||
|
items: NavItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NavItemBase {
|
||||||
|
text: string
|
||||||
|
target?: string
|
||||||
|
rel?: string
|
||||||
|
ariaLabel?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// sidebar -------------------------------------------------------------------
|
||||||
|
|
||||||
|
export type SideBarConfig = SideBarItem[] | 'auto' | false
|
||||||
|
|
||||||
|
export interface MultiSideBarConfig {
|
||||||
|
[path: string]: SideBarConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SideBarItem = string | [string, string] | SideBarGroup
|
||||||
|
|
||||||
|
export interface SideBarGroup {
|
||||||
|
title: string
|
||||||
|
path?: string
|
||||||
|
/**
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
collapsable?: boolean
|
||||||
|
children: SideBarItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// search --------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface SearchConfig {
|
||||||
|
/**
|
||||||
|
* @default 5
|
||||||
|
*/
|
||||||
|
maxSuggestions?: number
|
||||||
|
/**
|
||||||
|
* @default ''
|
||||||
|
*/
|
||||||
|
placeholder?: string
|
||||||
|
algolia?: {
|
||||||
|
apiKey: string
|
||||||
|
indexName: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// edit link -----------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface EditLinkConfig {
|
||||||
|
repo: string
|
||||||
|
dir?: string
|
||||||
|
branch?: string
|
||||||
|
text?: string
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
|
import './layout.css'
|
||||||
import Layout from './Layout.vue'
|
import Layout from './Layout.vue'
|
||||||
|
import NotFound from './NotFound.vue'
|
||||||
import { Theme } from '../app/theme'
|
import { Theme } from '../app/theme'
|
||||||
|
|
||||||
const theme: Theme = {
|
const theme: Theme = {
|
||||||
Layout
|
Layout,
|
||||||
|
NotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
export default theme
|
export default theme
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
|
||||||
|
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
||||||
|
--border-color: rgb(226, 232, 240);
|
||||||
|
--header-height: 4rem;
|
||||||
|
--sidebar-width: 18rem;
|
||||||
|
--text-color: #2c3e50;
|
||||||
|
--accent-color: #3eaf7c;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: var(--header-height);
|
||||||
|
background-color: #fff;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
z-index: 4;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 1.75rem 0 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: var(--sidebar-width);
|
||||||
|
padding-top: calc(var(--header-height) + 1.5rem);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 3;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
margin-top: var(--header-height);
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6, strong, b {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import { useSiteData } from 'vitepress'
|
||||||
|
|
||||||
|
export function withBase(path: string) {
|
||||||
|
return (useSiteData().value.base + path).replace(/\/+/g, '/')
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
export * from './shared'
|
export * from './shared'
|
||||||
export * from '../dist/client/app/exports'
|
|
||||||
export * from '../dist/node/index'
|
export * from '../dist/node/index'
|
||||||
|
export * from '../dist/client/app/exports'
|
||||||
|
export * from '../dist/client/theme-default/config'
|
||||||
|
Loading…
Reference in new issue