Merge branch 'vuejs:master' into release

pull/371/head
Sabertaz 4 years ago committed by GitHub
commit 9470b3315f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -60,7 +60,6 @@ Outbound links automatically get `target="_blank" rel="noopener noreferrer"`:
title: Blogging Like a Hacker
lang: en-US
---
```
This data will be available to the rest of the page, along with all custom and theming components.
@ -404,12 +403,17 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co
VitePress uses [markdown-it](https://github.com/markdown-it/markdown-it) as the Markdown renderer. A lot of the extensions above are implemented via custom plugins. You can further customize the `markdown-it` instance using the `markdown` option in `.vitepress/config.js`:
```js
const anchor = require('markdown-it-anchor')
module.exports = {
markdown: {
// options for markdown-it-anchor
anchor: { permalink: false },
// https://github.com/valeriangalliat/markdown-it-anchor#permalinks
anchor: {
permalink: anchor.permalink.headerLink()
},
// options for markdown-it-toc
// options for markdown-it-table-of-contents
toc: { includeLevel: [1, 2] },
config: (md) => {

@ -79,7 +79,7 @@
"gray-matter": "^4.0.3",
"lru-cache": "^6.0.0",
"markdown-it": "^12.0.6",
"markdown-it-anchor": "^7.1.0",
"markdown-it-anchor": "^8.1.2",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.0",
"markdown-it-table-of-contents": "^0.5.2",

@ -1,13 +1,16 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ref, watch, reactive } from 'vue'
import { useData } from '../data'
const data = useData()
const el = ref<HTMLElement | null>(null)
const open = ref(false)
// FIXME: remove in next Vue release
const tempData = reactive(data)
watch(open, (value) => {
if (value === false) {
if (!value) {
el.value!.scrollTop = 0
}
})
@ -16,7 +19,7 @@ watch(open, (value) => {
<template>
<div class="debug" :class="{ open }" ref="el" @click="open = !open">
<p class="title">Debug</p>
<pre class="block">{{ data }}</pre>
<pre class="block">{{ tempData }}</pre>
</div>
</template>

@ -46,9 +46,11 @@ export function initData(route: Route): VitePressData {
frontmatter: computed(() => route.data.frontmatter),
lang: computed(() => site.value.lang),
localePath: computed(() => {
const { locales, lang } = site.value
const path = Object.keys(locales).find((lp) => locales[lp].lang === lang)
return withBase((locales && path) || '/')
const { langs, lang } = site.value
const path = Object.keys(langs).find(
(langPath) => langs[langPath].lang === lang
)
return withBase(path || '/')
}),
title: computed(() => {
return route.data.title

@ -32,9 +32,7 @@ const isCustomLayout = computed(() => !!frontmatter.value.customLayout)
const enableHome = computed(() => !!frontmatter.value.home)
// automatic multilang check for AlgoliaSearchBox
const isMultiLang = computed(
() => Object.keys(theme.value.locales || {}).length > 0
)
const isMultiLang = computed(() => Object.keys(site.value.langs).length > 1)
// navbar
const showNavbar = computed(() => {

@ -2,11 +2,14 @@
<div class="theme">
<h1>404</h1>
<blockquote>{{ getMsg() }}</blockquote>
<a :href="$site.base" aria-label="go to home">Take me home.</a>
<a :href="site.base" aria-label="go to home">Take me home.</a>
</div>
</template>
<script setup lang="ts">
import { useData } from 'vitepress'
const { site } = useData()
const msgs = [
`There's nothing here.`,
`How did we get here?`,

@ -24,6 +24,7 @@ onMounted(() => {
.carbon-ads {
border-radius: 4px;
margin: 0 auto;
padding: 8px;
max-width: 280px;
font-size: 0.75rem;
background-color: var(--c-bg-accent);
@ -41,7 +42,6 @@ onMounted(() => {
z-index: 1;
float: right;
margin: -8px -8px 24px 24px;
padding: 8px;
width: 146px;
max-width: 100%;
min-height: 200px;

@ -28,11 +28,4 @@ import HomeFooter from './HomeFooter.vue'
margin: 0px auto;
padding: 0 1.5rem;
}
@media (max-width: 720px) {
.home-content {
max-width: 392px;
padding: 0;
}
}
</style>

@ -1,13 +1,13 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useData } from 'vitepress'
import { useLocaleLinks } from '../composables/nav'
import { useLanguageLinks } from '../composables/nav'
import { useRepo } from '../composables/repo'
import NavLink from './NavLink.vue'
import NavDropdownLink from './NavDropdownLink.vue'
const { theme } = useData()
const localeLinks = useLocaleLinks()
const localeLinks = useLanguageLinks()
const repo = useRepo()
const show = computed(() => theme.value.nav || repo.value || localeLinks.value)
</script>

@ -1,57 +1,30 @@
import { computed } from 'vue'
import { useRoute, useData, inBrowser } from 'vitepress'
import { useData, useRoute } from 'vitepress'
import type { DefaultTheme } from '../config'
export function useLocaleLinks() {
const route = useRoute()
const { site } = useData()
export function useLanguageLinks() {
const { site, localePath, theme } = useData()
return computed(() => {
const theme = site.value.themeConfig as DefaultTheme.Config
const locales = theme.locales
const langs = site.value.langs
const localePaths = Object.keys(langs)
if (!locales) {
// one language
if (localePaths.length < 2) {
return null
}
const localeKeys = Object.keys(locales)
const route = useRoute()
if (localeKeys.length <= 1) {
return null
}
// handle site base
const siteBase = inBrowser ? site.value.base : '/'
const siteBaseWithoutSuffix = siteBase.endsWith('/')
? siteBase.slice(0, -1)
: siteBase
// remove site base in browser env
const routerPath = route.path.slice(siteBaseWithoutSuffix.length)
const currentLangBase = localeKeys.find((key) => {
return key === '/' ? false : routerPath.startsWith(key)
})
const currentContentPath = currentLangBase
? routerPath.substring(currentLangBase.length - 1)
: routerPath
const candidates = localeKeys.map((v) => {
const localePath = v.endsWith('/') ? v.slice(0, -1) : v
return {
text: locales[v].label,
link: `${localePath}${currentContentPath}`
}
})
// intentionally remove the leading slash because each locale has one
const currentPath = route.path.replace(localePath.value, '')
const currentLangKey = currentLangBase ? currentLangBase : '/'
const candidates = localePaths.map((localePath) => ({
text: langs[localePath].label,
link: `${localePath}${currentPath}`
}))
const selectText = locales[currentLangKey].selectText
? locales[currentLangKey].selectText
: 'Languages'
const selectText = theme.value.selectText || 'Languages'
return {
text: selectText,

@ -26,6 +26,7 @@ div[class*='language-'] {
li > div[class*='language-'] {
border-radius: 6px 0 0 6px;
margin: 1rem -1.5rem 1rem -1.25rem;
line-height: initial;
}
@media (min-width: 420px) {

@ -4,7 +4,12 @@ import chalk from 'chalk'
import globby from 'globby'
import { AliasOptions, UserConfig as ViteConfig } from 'vite'
import { Options as VuePluginOptions } from '@vitejs/plugin-vue'
import { SiteData, HeadConfig, LocaleConfig } from './shared'
import {
SiteData,
HeadConfig,
LocaleConfig,
createLangDictionary
} from './shared'
import { resolveAliases, APP_PATH, DEFAULT_THEME_PATH } from './alias'
import { MarkdownOptions } from './markdown/markdown'
@ -142,6 +147,7 @@ export async function resolveSiteData(
head: userConfig.head || [],
themeConfig: userConfig.themeConfig || {},
locales: userConfig.locales || {},
langs: createLangDictionary(userConfig),
customData: userConfig.customData || {}
}
}

@ -12,18 +12,16 @@ import { preWrapperPlugin } from './plugins/preWrapper'
import { linkPlugin } from './plugins/link'
import { extractHeaderPlugin } from './plugins/header'
import { Header } from '../shared'
import anchor, { AnchorOptions } from 'markdown-it-anchor'
const emoji = require('markdown-it-emoji')
const anchor = require('markdown-it-anchor')
const toc = require('markdown-it-table-of-contents')
export interface MarkdownOptions extends MarkdownIt.Options {
lineNumbers?: boolean
config?: (md: MarkdownIt) => void
anchor?: {
permalink?: boolean
permalinkBefore?: boolean
permalinkSymbol?: string
permalink?: AnchorOptions['permalink']
}
// https://github.com/Oktavilla/markdown-it-table-of-contents
toc?: any
@ -67,13 +65,9 @@ export const createMarkdownRenderer = (
})
// 3rd party plugins
.use(emoji)
.use(anchor, {
slugify,
permalink: true,
permalinkBefore: true,
permalinkSymbol: '#',
permalinkAttrs: () => ({ 'aria-hidden': true }),
permalink: anchor.permalink.ariaHidden({}),
...options.anchor
})
.use(toc, {
@ -82,6 +76,7 @@ export const createMarkdownRenderer = (
format: parseHeader,
...options.toc
})
.use(emoji)
// apply user config
if (options.config) {

@ -14,7 +14,7 @@ export const slugify = (str: string): string => {
.replace(rSpecial, '-')
// Remove continuos separators
.replace(/\-{2,}/g, '-')
// Remove prefixing and trailing separtors
// Remove prefixing and trailing separators
.replace(/^\-+|\-+$/g, '')
// ensure it doesn't start with a number (#121)
.replace(/^(\d)/, '_$1')

@ -1,5 +1,5 @@
import path from 'path'
import { mergeConfig, Plugin, ResolvedConfig } from 'vite'
import { defineConfig, mergeConfig, Plugin, ResolvedConfig } from 'vite'
import { SiteConfig, resolveSiteData } from './config'
import {
createMarkdownToVueRenderFn,
@ -71,7 +71,7 @@ export function createVitePressPlugin(
},
config() {
const baseConfig = {
const baseConfig = defineConfig({
resolve: {
alias
},
@ -84,8 +84,13 @@ export function createVitePressPlugin(
// force include vue to avoid duplicated copies when linked + optimized
include: ['vue'],
exclude: ['@docsearch/js']
},
server: {
fs: {
allow: [APP_PATH, srcDir]
}
}
}
})
return userViteConfig
? mergeConfig(userViteConfig, baseConfig)
: baseConfig

@ -1,4 +1,4 @@
import { SiteData } from '../../types/shared'
import { LocaleConfig, SiteData } from '../../types/shared'
export type {
SiteData,
@ -12,7 +12,7 @@ export const EXTERNAL_URL_RE = /^https?:/i
export const inBrowser = typeof window !== 'undefined'
function findMatchRoot(route: string, roots: string[]) {
function findMatchRoot(route: string, roots: string[]): string | undefined {
// first match to the routes with the most deep level.
roots.sort((a, b) => {
const levelDelta = b.split('/').length - a.split('/').length
@ -24,9 +24,8 @@ function findMatchRoot(route: string, roots: string[]) {
})
for (const r of roots) {
if (route.startsWith(r)) return
if (route.startsWith(r)) return r
}
return undefined
}
function resolveLocales<T>(
@ -37,6 +36,23 @@ function resolveLocales<T>(
return localeRoot ? locales[localeRoot] : undefined
}
export function createLangDictionary(siteData: {
themeConfig?: any
locales?: Record<string, LocaleConfig>
}) {
const { locales } = siteData.themeConfig
const siteLocales = siteData.locales
return locales && siteLocales
? Object.keys(locales).reduce((langs, path) => {
langs[path] = {
label: locales![path].label,
lang: siteLocales[path].lang
}
return langs
}, {} as Record<string, { lang: string; label: string }>)
: {}
}
// this merges the locales data to the main data by the route
export function resolveSiteDataByRoute(
siteData: SiteData,
@ -44,12 +60,11 @@ export function resolveSiteDataByRoute(
): SiteData {
route = cleanRoute(siteData, route)
const localeData = resolveLocales(siteData.locales || {}, route) || {}
const localeThemeConfig =
resolveLocales<any>(
(siteData.themeConfig && siteData.themeConfig.locales) || {},
route
) || {}
const localeData = resolveLocales(siteData.locales || {}, route)
const localeThemeConfig = resolveLocales<any>(
siteData.themeConfig.locales || {},
route
)
return {
...siteData,
@ -60,8 +75,10 @@ export function resolveSiteDataByRoute(
// clean the locales to reduce the bundle size
locales: {}
},
lang: localeThemeConfig.lang || siteData.lang,
locales: {}
lang: (localeData || siteData).lang,
// clean the locales to reduce the bundle size
locales: {},
langs: createLangDictionary(siteData)
}
}

24
types/shared.d.ts vendored

@ -11,12 +11,36 @@ export interface LocaleConfig {
export interface SiteData<ThemeConfig = any> {
base: string
/**
* Language of the site as it should be set on the `html` element.
* @example `en-US`, `zh-CN`
*/
lang: string
title: string
description: string
head: HeadConfig[]
themeConfig: ThemeConfig
locales: Record<string, LocaleConfig>
/**
* Available locales for the site when it has defined `locales` in its
* `themeConfig`. This object is otherwise empty. Keys are paths like `/` or
* `/zh/`.
*/
langs: Record<
string,
{
/**
* Lang attribute as set on the `<html>` element.
* @example `en-US`, `zh-CN`
*/
lang: string
/**
* Label to display in the language menu.
* @example `English', ``
*/
label: string
}
>
customData: any
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save