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 title: Blogging Like a Hacker
lang: en-US lang: en-US
--- ---
``` ```
This data will be available to the rest of the page, along with all custom and theming components. 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`: 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 ```js
const anchor = require('markdown-it-anchor')
module.exports = { module.exports = {
markdown: { markdown: {
// options for markdown-it-anchor // 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] }, toc: { includeLevel: [1, 2] },
config: (md) => { config: (md) => {

@ -79,7 +79,7 @@
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"lru-cache": "^6.0.0", "lru-cache": "^6.0.0",
"markdown-it": "^12.0.6", "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-container": "^3.0.0",
"markdown-it-emoji": "^2.0.0", "markdown-it-emoji": "^2.0.0",
"markdown-it-table-of-contents": "^0.5.2", "markdown-it-table-of-contents": "^0.5.2",

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

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

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

@ -2,11 +2,14 @@
<div class="theme"> <div class="theme">
<h1>404</h1> <h1>404</h1>
<blockquote>{{ getMsg() }}</blockquote> <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> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useData } from 'vitepress'
const { site } = useData()
const msgs = [ const msgs = [
`There's nothing here.`, `There's nothing here.`,
`How did we get here?`, `How did we get here?`,

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

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

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

@ -1,57 +1,30 @@
import { computed } from 'vue' import { computed } from 'vue'
import { useRoute, useData, inBrowser } from 'vitepress' import { useData, useRoute } from 'vitepress'
import type { DefaultTheme } from '../config' import type { DefaultTheme } from '../config'
export function useLocaleLinks() { export function useLanguageLinks() {
const route = useRoute() const { site, localePath, theme } = useData()
const { site } = useData()
return computed(() => { return computed(() => {
const theme = site.value.themeConfig as DefaultTheme.Config const langs = site.value.langs
const locales = theme.locales const localePaths = Object.keys(langs)
if (!locales) { // one language
if (localePaths.length < 2) {
return null return null
} }
const localeKeys = Object.keys(locales) const route = useRoute()
if (localeKeys.length <= 1) { // intentionally remove the leading slash because each locale has one
return null const currentPath = route.path.replace(localePath.value, '')
}
// 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}`
}
})
const currentLangKey = currentLangBase ? currentLangBase : '/' const candidates = localePaths.map((localePath) => ({
text: langs[localePath].label,
link: `${localePath}${currentPath}`
}))
const selectText = locales[currentLangKey].selectText const selectText = theme.value.selectText || 'Languages'
? locales[currentLangKey].selectText
: 'Languages'
return { return {
text: selectText, text: selectText,

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

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

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

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

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

@ -1,4 +1,4 @@
import { SiteData } from '../../types/shared' import { LocaleConfig, SiteData } from '../../types/shared'
export type { export type {
SiteData, SiteData,
@ -12,7 +12,7 @@ export const EXTERNAL_URL_RE = /^https?:/i
export const inBrowser = typeof window !== 'undefined' 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. // first match to the routes with the most deep level.
roots.sort((a, b) => { roots.sort((a, b) => {
const levelDelta = b.split('/').length - a.split('/').length const levelDelta = b.split('/').length - a.split('/').length
@ -24,9 +24,8 @@ function findMatchRoot(route: string, roots: string[]) {
}) })
for (const r of roots) { for (const r of roots) {
if (route.startsWith(r)) return if (route.startsWith(r)) return r
} }
return undefined
} }
function resolveLocales<T>( function resolveLocales<T>(
@ -37,6 +36,23 @@ function resolveLocales<T>(
return localeRoot ? locales[localeRoot] : undefined 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 // this merges the locales data to the main data by the route
export function resolveSiteDataByRoute( export function resolveSiteDataByRoute(
siteData: SiteData, siteData: SiteData,
@ -44,12 +60,11 @@ export function resolveSiteDataByRoute(
): SiteData { ): SiteData {
route = cleanRoute(siteData, route) route = cleanRoute(siteData, route)
const localeData = resolveLocales(siteData.locales || {}, route) || {} const localeData = resolveLocales(siteData.locales || {}, route)
const localeThemeConfig = const localeThemeConfig = resolveLocales<any>(
resolveLocales<any>( siteData.themeConfig.locales || {},
(siteData.themeConfig && siteData.themeConfig.locales) || {}, route
route )
) || {}
return { return {
...siteData, ...siteData,
@ -60,8 +75,10 @@ export function resolveSiteDataByRoute(
// clean the locales to reduce the bundle size // clean the locales to reduce the bundle size
locales: {} locales: {}
}, },
lang: localeThemeConfig.lang || siteData.lang, lang: (localeData || siteData).lang,
locales: {} // 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> { export interface SiteData<ThemeConfig = any> {
base: string base: string
/**
* Language of the site as it should be set on the `html` element.
* @example `en-US`, `zh-CN`
*/
lang: string lang: string
title: string title: string
description: string description: string
head: HeadConfig[] head: HeadConfig[]
themeConfig: ThemeConfig themeConfig: ThemeConfig
locales: Record<string, LocaleConfig> 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 customData: any
} }

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