Merge branch 'main' of github.com:vuejs/vitepress

pull/3635/head
zonemeen 2 years ago
commit 43cd9673c3

@ -1,3 +1,15 @@
# [1.0.0-rc.39](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.38...v1.0.0-rc.39) (2024-01-16)
### Bug Fixes
- **theme:** misaligned outline indicator ([#3458](https://github.com/vuejs/vitepress/issues/3458)) ([0ce5ece](https://github.com/vuejs/vitepress/commit/0ce5ece35687bdad7a65d61432419cfe3961a329))
- **theme:** enter key behavior conflict with IME in search box ([#3454](https://github.com/vuejs/vitepress/issues/3454)) ([cd8ee6f](https://github.com/vuejs/vitepress/commit/cd8ee6fb32d8135e78c5827a36b79efad509042c))
- **theme:** use`--vp-c-tip-` CSS variable for badge/block colors with type`tip` ([#3434](https://github.com/vuejs/vitepress/issues/3434)) ([78abf47](https://github.com/vuejs/vitepress/commit/78abf47b8b563d66db9d481a98bbdefac95cc84c))
### Features
- **theme:** export VPBadge ([#3431](https://github.com/vuejs/vitepress/issues/3431)) ([18981c1](https://github.com/vuejs/vitepress/commit/18981c1d1c74a4f4ca379a88b00c02ba5eace6db))
# [1.0.0-rc.36](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.35...v1.0.0-rc.36) (2024-1-8) # [1.0.0-rc.36](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.35...v1.0.0-rc.36) (2024-1-8)
### Bug Fixes ### Bug Fixes

@ -1,64 +1,10 @@
import { defineConfig } from 'vitepress' import { defineConfig } from 'vitepress'
import { shared } from './shared'
import { en } from './en' import { en } from './en'
import { zh, search as zhSearch } from './zh' import { zh } from './zh'
export default defineConfig({ export default defineConfig({
title: 'VitePress', ...shared,
lastUpdated: true,
cleanUrls: true,
markdown: {
math: true,
codeTransformers: [
// We use `[!!code` in demo to prevent transformation, here we revert it back.
{
postprocess(code) {
return code.replace(/\[\!\!code/g, '[!code')
}
}
]
},
sitemap: {
hostname: 'https://vitepress.dev',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
}
},
/* prettier-ignore */
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'en' }],
['meta', { name: 'og:site_name', content: 'VitePress' }],
['meta', { name: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }],
['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]
],
themeConfig: {
logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
search: {
provider: 'algolia',
options: {
appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd',
indexName: 'vitepress',
locales: { ...zhSearch }
}
},
carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }
},
locales: { locales: {
root: { label: 'English', ...en }, root: { label: 'English', ...en },
zh: { label: '简体中文', ...zh } zh: { label: '简体中文', ...zh }

@ -0,0 +1,60 @@
import { defineConfig } from 'vitepress'
import { search as zhSearch } from './zh'
export const shared = defineConfig({
title: 'VitePress',
lastUpdated: true,
cleanUrls: true,
markdown: {
math: true,
codeTransformers: [
// We use `[!!code` in demo to prevent transformation, here we revert it back.
{
postprocess(code) {
return code.replace(/\[\!\!code/g, '[!code')
}
}
]
},
sitemap: {
hostname: 'https://vitepress.dev',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
}
},
/* prettier-ignore */
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'en' }],
['meta', { name: 'og:site_name', content: 'VitePress' }],
['meta', { name: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }],
['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]
],
themeConfig: {
logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
search: {
provider: 'algolia',
options: {
appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd',
indexName: 'vitepress',
locales: { ...zhSearch }
}
},
carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }
}
})

@ -377,7 +377,7 @@ export default { // Highlighted
} }
``` ```
Alternatively, it's possible to highlight directly in the line by using the `// [!code hightlight]` comment. Alternatively, it's possible to highlight directly in the line by using the `// [!code highlight]` comment.
**Input** **Input**

@ -129,9 +129,9 @@ To serve clean URLs with VitePress, server-side support is required.
By default, VitePress resolves inbound links to URLs ending with `.html`. However, some users may prefer "Clean URLs" without the `.html` extension - for example, `example.com/path` instead of `example.com/path.html`. By default, VitePress resolves inbound links to URLs ending with `.html`. However, some users may prefer "Clean URLs" without the `.html` extension - for example, `example.com/path` instead of `example.com/path.html`.
Some servers or hosting platforms (for example Netlify or Vercel) provide the ability to map a URL like `/foo` to `/foo.html` if it exists, without a redirect: Some servers or hosting platforms (for example Netlify, Vercel, GitHub Pages) provide the ability to map a URL like `/foo` to `/foo.html` if it exists, without a redirect:
- Netlify supports this by default. - Netlify and GitHub Pages support this by default.
- Vercel requires enabling the [`cleanUrls` option in `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls). - Vercel requires enabling the [`cleanUrls` option in `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).
If this feature is available to you, you can then also enable VitePress' own [`cleanUrls`](../reference/site-config#cleanurls) config option so that: If this feature is available to you, you can then also enable VitePress' own [`cleanUrls`](../reference/site-config#cleanurls) config option so that:
@ -139,7 +139,7 @@ If this feature is available to you, you can then also enable VitePress' own [`c
- Inbound links between pages are generated without the `.html` extension. - Inbound links between pages are generated without the `.html` extension.
- If current path ends with `.html`, the router will perform a client-side redirect to the extension-less path. - If current path ends with `.html`, the router will perform a client-side redirect to the extension-less path.
If, however, you cannot configure your server with such support (e.g. GitHub pages), you will have to manually resort to the following directory structure: If, however, you cannot configure your server with such support, you will have to manually resort to the following directory structure:
``` ```
. .

@ -7,11 +7,13 @@
"files": [ "files": [
{ {
"location": ".vitepress/config/{en,zh}.ts", "location": ".vitepress/config/{en,zh}.ts",
"pattern": ".vitepress/config/@lang.ts" "pattern": ".vitepress/config/@lang.ts",
"type": "universal"
}, },
{ {
"location": "**/*.md", "location": "**/*.md",
"pattern": "@lang/@path" "pattern": "@lang/@path",
"type": "universal"
} }
], ],
"defaultLocale": { "defaultLocale": {

@ -10,7 +10,7 @@
"lunaria:open": "open-cli .vitepress/dist/_translations/index.html" "lunaria:open": "open-cli .vitepress/dist/_translations/index.html"
}, },
"devDependencies": { "devDependencies": {
"@lunariajs/core": "^0.0.25", "@lunariajs/core": "npm:@brc-dd/lunaria-core@latest",
"markdown-it-mathjax3": "^4.3.2", "markdown-it-mathjax3": "^4.3.2",
"open-cli": "^8.0.0", "open-cli": "^8.0.0",
"vitepress": "workspace:*" "vitepress": "workspace:*"

@ -377,7 +377,7 @@ export default { // Highlighted
} }
``` ```
也可以使用 `// [!code hl]` 注释实现行高亮。 也可以使用 `// [!code highlight]` 注释实现行高亮。
**输入** **输入**
@ -386,7 +386,7 @@ export default { // Highlighted
export default { export default {
data () { data () {
return { return {
msg: 'Highlighted!' // [!code hl] msg: 'Highlighted!' // [!!code highlight]
} }
} }
} }
@ -399,7 +399,7 @@ export default {
export default { export default {
data() { data() {
return { return {
msg: 'Highlighted!' // [!code hl] msg: 'Highlighted!' // [!code highlight]
} }
} }
} }
@ -413,14 +413,12 @@ export default {
**输入** **输入**
`!code` 后面只需要一个空格,为了展示原始的代码而不被实际渲染,这里有两个空格:
```` ````
```js ```js
export default { export default {
data () { data () {
return { return {
msg: 'Focused!' // [!code focus] msg: 'Focused!' // [!!code focus]
} }
} }
} }
@ -445,15 +443,13 @@ export default {
**输入** **输入**
`!code` 后面只需要一个空格,为了展示原始的代码而不被实际渲染,这里有两个空格。
```` ````
```js ```js
export default { export default {
data () { data () {
return { return {
msg: 'Removed' // [!code --] msg: 'Removed' // [!!code --]
msg: 'Added' // [!code ++] msg: 'Added' // [!!code ++]
} }
} }
} }
@ -479,15 +475,13 @@ export default {
**输入** **输入**
`!code` 后面只需要一个空格,为了展示原始的代码而不被实际渲染,这里有两个空格。
```` ````
```js ```js
export default { export default {
data () { data () {
return { return {
msg: 'Error', // [!code error] msg: 'Error', // [!!code error]
msg: 'Warning' // [!code warning] msg: 'Warning' // [!!code warning]
} }
} }
} }

@ -1,6 +1,6 @@
{ {
"name": "vitepress", "name": "vitepress",
"version": "1.0.0-rc.36", "version": "1.0.0-rc.39",
"description": "Vite & Vue powered static site generator", "description": "Vite & Vue powered static site generator",
"type": "module", "type": "module",
"packageManager": "pnpm@8.14.1", "packageManager": "pnpm@8.14.1",
@ -97,8 +97,8 @@
"@types/markdown-it": "^13.0.7", "@types/markdown-it": "^13.0.7",
"@vitejs/plugin-vue": "^5.0.3", "@vitejs/plugin-vue": "^5.0.3",
"@vue/devtools-api": "^6.5.1", "@vue/devtools-api": "^6.5.1",
"@vueuse/core": "^10.7.1", "@vueuse/core": "^10.7.2",
"@vueuse/integrations": "^10.7.1", "@vueuse/integrations": "^10.7.2",
"focus-trap": "^7.5.4", "focus-trap": "^7.5.4",
"mark.js": "8.11.1", "mark.js": "8.11.1",
"minisearch": "^6.3.0", "minisearch": "^6.3.0",
@ -106,7 +106,7 @@
"shikiji-core": "^0.9.19", "shikiji-core": "^0.9.19",
"shikiji-transformers": "^0.9.19", "shikiji-transformers": "^0.9.19",
"vite": "^5.0.11", "vite": "^5.0.11",
"vue": "^3.4.11" "vue": "^3.4.14"
}, },
"peerDependencies": { "peerDependencies": {
"markdown-it-mathjax3": "^4.3.2", "markdown-it-mathjax3": "^4.3.2",
@ -146,10 +146,10 @@
"@types/markdown-it-emoji": "^2.0.4", "@types/markdown-it-emoji": "^2.0.4",
"@types/micromatch": "^4.0.6", "@types/micromatch": "^4.0.6",
"@types/minimist": "^1.2.5", "@types/minimist": "^1.2.5",
"@types/node": "^20.11.0", "@types/node": "^20.11.2",
"@types/postcss-prefix-selector": "^1.16.3", "@types/postcss-prefix-selector": "^1.16.3",
"@types/prompts": "^2.4.9", "@types/prompts": "^2.4.9",
"@vue/shared": "^3.4.11", "@vue/shared": "^3.4.14",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"compression": "^1.7.4", "compression": "^1.7.4",
"conventional-changelog-cli": "^4.1.0", "conventional-changelog-cli": "^4.1.0",
@ -183,7 +183,7 @@
"playwright-chromium": "^1.40.1", "playwright-chromium": "^1.40.1",
"polka": "1.0.0-next.23", "polka": "1.0.0-next.23",
"postcss-prefix-selector": "^1.16.0", "postcss-prefix-selector": "^1.16.0",
"prettier": "^3.2.0", "prettier": "^3.2.2",
"prompts": "^2.4.2", "prompts": "^2.4.2",
"punycode": "^2.3.1", "punycode": "^2.3.1",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",

File diff suppressed because it is too large Load Diff

@ -1,9 +1,9 @@
import { reactive, inject, markRaw, nextTick, readonly } from 'vue'
import type { Component, InjectionKey } from 'vue' import type { Component, InjectionKey } from 'vue'
import { inject, markRaw, nextTick, reactive, readonly } from 'vue'
import type { Awaitable, PageData, PageDataPayload } from '../shared'
import { notFoundPageData, treatAsHtml } from '../shared' import { notFoundPageData, treatAsHtml } from '../shared'
import type { PageData, PageDataPayload, Awaitable } from '../shared'
import { inBrowser, withBase } from './utils'
import { siteDataRef } from './data' import { siteDataRef } from './data'
import { getScrollOffset, inBrowser, withBase } from './utils'
export interface Route { export interface Route {
path: string path: string
@ -261,26 +261,6 @@ export function scrollTo(el: Element, hash: string, smooth = false) {
} }
if (target) { if (target) {
let scrollOffset = siteDataRef.value.scrollOffset
let offset = 0
let padding = 24
if (typeof scrollOffset === 'object' && 'padding' in scrollOffset) {
padding = scrollOffset.padding
scrollOffset = scrollOffset.selector
}
if (typeof scrollOffset === 'number') {
offset = scrollOffset
} else if (typeof scrollOffset === 'string') {
offset = tryOffsetSelector(scrollOffset, padding)
} else if (Array.isArray(scrollOffset)) {
for (const selector of scrollOffset) {
const res = tryOffsetSelector(selector, padding)
if (res) {
offset = res
break
}
}
}
const targetPadding = parseInt( const targetPadding = parseInt(
window.getComputedStyle(target).paddingTop, window.getComputedStyle(target).paddingTop,
10 10
@ -288,7 +268,7 @@ export function scrollTo(el: Element, hash: string, smooth = false) {
const targetTop = const targetTop =
window.scrollY + window.scrollY +
target.getBoundingClientRect().top - target.getBoundingClientRect().top -
offset + getScrollOffset() +
targetPadding targetPadding
function scrollToTarget() { function scrollToTarget() {
// only smooth scroll if distance is smaller than screen height. // only smooth scroll if distance is smaller than screen height.
@ -300,14 +280,6 @@ export function scrollTo(el: Element, hash: string, smooth = false) {
} }
} }
function tryOffsetSelector(selector: string, padding: number): number {
const el = document.querySelector(selector)
if (!el) return 0
const bot = el.getBoundingClientRect().bottom
if (bot < 0) return 0
return bot + padding
}
function handleHMR(route: Route): void { function handleHMR(route: Route): void {
// update route.data on HMR updates of active page // update route.data on HMR updates of active page
if (import.meta.hot) { if (import.meta.hot) {

@ -107,3 +107,36 @@ export function defineClientComponent(
} }
} }
} }
export function getScrollOffset() {
let scrollOffset = siteDataRef.value.scrollOffset
let offset = 0
let padding = 24
if (typeof scrollOffset === 'object' && 'padding' in scrollOffset) {
padding = scrollOffset.padding
scrollOffset = scrollOffset.selector
}
if (typeof scrollOffset === 'number') {
offset = scrollOffset
} else if (typeof scrollOffset === 'string') {
offset = tryOffsetSelector(scrollOffset, padding)
} else if (Array.isArray(scrollOffset)) {
for (const selector of scrollOffset) {
const res = tryOffsetSelector(selector, padding)
if (res) {
offset = res
break
}
}
}
return offset
}
function tryOffsetSelector(selector: string, padding: number): number {
const el = document.querySelector(selector)
if (!el) return 0
const bot = el.getBoundingClientRect().bottom
if (bot < 0) return 0
return bot + padding
}

@ -20,7 +20,8 @@ export {
inBrowser, inBrowser,
onContentUpdated, onContentUpdated,
defineClientComponent, defineClientComponent,
withBase withBase,
getScrollOffset
} from './app/utils' } from './app/utils'
// components // components

@ -322,6 +322,8 @@ onKeyStroke('ArrowDown', (event) => {
const router = useRouter() const router = useRouter()
onKeyStroke('Enter', (e) => { onKeyStroke('Enter', (e) => {
if (e.isComposing) return
if (e.target instanceof HTMLButtonElement && e.target.type !== 'submit') if (e.target instanceof HTMLButtonElement && e.target.type !== 'submit')
return return

@ -1,8 +1,9 @@
import { getScrollOffset } from 'vitepress'
import type { DefaultTheme } from 'vitepress/theme' import type { DefaultTheme } from 'vitepress/theme'
import { onMounted, onUnmounted, onUpdated, type Ref } from 'vue' import { onMounted, onUnmounted, onUpdated, type Ref } from 'vue'
import type { Header } from '../../shared' import type { Header } from '../../shared'
import { useAside } from './aside'
import { throttleAndDebounce } from '../support/utils' import { throttleAndDebounce } from '../support/utils'
import { useAside } from './aside'
// cached list of anchor elements from resolveHeaders // cached list of anchor elements from resolveHeaders
const resolvedHeaders: { element: HTMLHeadElement; link: string }[] = [] const resolvedHeaders: { element: HTMLHeadElement; link: string }[] = []
@ -136,14 +137,6 @@ export function useActiveAnchor(
return return
} }
// pixel offset, start of main content
const offsetDocTop = (() => {
const container =
document.querySelector('#VPContent .VPDoc')?.firstElementChild
if (container) return getAbsoluteTop(container as HTMLElement)
else return 78
})()
const scrollY = window.scrollY const scrollY = window.scrollY
const innerHeight = window.innerHeight const innerHeight = window.innerHeight
const offsetHeight = document.body.offsetHeight const offsetHeight = document.body.offsetHeight
@ -179,7 +172,7 @@ export function useActiveAnchor(
// find the last header above the top of viewport // find the last header above the top of viewport
let activeLink: string | null = null let activeLink: string | null = null
for (const { link, top } of headers) { for (const { link, top } of headers) {
if (top > scrollY + offsetDocTop) { if (top > scrollY + getScrollOffset() + 4) {
break break
} }
activeLink = link activeLink = link

@ -18,7 +18,8 @@
color: var(--vp-c-brand-1); color: var(--vp-c-brand-1);
} }
.custom-block.info a:hover { .custom-block.info a:hover,
.custom-block.info a:hover > code {
color: var(--vp-c-brand-2); color: var(--vp-c-brand-2);
} }
@ -37,7 +38,8 @@
color: var(--vp-c-tip-1); color: var(--vp-c-tip-1);
} }
.custom-block.tip a:hover { .custom-block.tip a:hover,
.custom-block.tip a:hover > code {
color: var(--vp-c-tip-2); color: var(--vp-c-tip-2);
} }
@ -56,7 +58,8 @@
color: var(--vp-c-warning-1); color: var(--vp-c-warning-1);
} }
.custom-block.warning a:hover { .custom-block.warning a:hover,
.custom-block.warning a:hover > code {
color: var(--vp-c-warning-2); color: var(--vp-c-warning-2);
} }
@ -75,7 +78,8 @@
color: var(--vp-c-danger-1); color: var(--vp-c-danger-1);
} }
.custom-block.danger a:hover { .custom-block.danger a:hover,
.custom-block.danger a:hover > code {
color: var(--vp-c-danger-2); color: var(--vp-c-danger-2);
} }
@ -93,7 +97,8 @@
color: var(--vp-c-brand-1); color: var(--vp-c-brand-1);
} }
.custom-block.details a:hover { .custom-block.details a:hover,
.custom-block.details a:hover > code {
color: var(--vp-c-brand-2); color: var(--vp-c-brand-2);
} }

@ -182,18 +182,20 @@ export function slash(p: string): string {
return p.replace(/\\/g, '/') return p.replace(/\\/g, '/')
} }
const extraExts =
(typeof process === 'object' && process.env.VITE_EXTRA_EXTENSIONS) ||
(import.meta as any).env?.VITE_EXTRA_EXTENSIONS ||
''
// md, html? are intentionally omitted, see treatAsHtml // md, html? are intentionally omitted, see treatAsHtml
const KNOWN_EXTENSIONS = new Set( const KNOWN_EXTENSIONS = new Set(
( (
'3g2,3gp,7z,aac,abw,ai,aif,aifc,aiff,apng,arc,asf,asr,asx,au,avi,avif,axs,' + '3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,doc,' +
'azw,bin,bmp,bz,bz2,c,cda,cer,class,crl,crt,csh,css,csv,dcr,der,dll,doc,docx,' + 'eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,man,' +
'eot,eps,epub,exe,flac,gif,gtar,gz,gzip,ico,ics,ief,jar,jfif,jpe,jpeg,jpg,' + 'mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,opus,otf,' +
'js,json,jsonld,latex,m3u,m4a,man,mdb,mht,mhtml,mid,midi,mjs,mov,mp2,mp3,mp4,' + 'p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,tiff,tr,ts,' +
'mpa,mpe,mpeg,mpg,mpkg,mpp,odp,ods,odt,oga,ogg,ogv,ogx,opus,otf,p10,p12,p7b,' + 'tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,yaml,yml,zip' +
'p7c,p7m,p7r,p7s,pbm,pdf,pfx,php,pjp,pjpeg,png,ppt,pptx,ps,pub,qt,rar,roff,' + (extraExts && typeof extraExts === 'string' ? ',' + extraExts : '')
'rtf,rtx,ser,sh,spc,svg,swf,t,tar,tcl,tex,texi,texinfo,tgz,tif,tiff,tr,ts,' +
'tsv,ttf,txt,ua,viv,vivo,vsd,vtt,wav,weba,webm,webp,woff,woff2,xbm,xhtml,' +
'xls,xlsx,xml,xul,yaml,yml,zip,conf'
).split(',') ).split(',')
) )

Loading…
Cancel
Save