From f4cd0aeb6919bbb5a3ca27b7d6f295427e75998c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=83=BD=E5=AE=81?= <994718917@qq.com>
Date: Tue, 9 May 2023 00:23:23 +0800
Subject: [PATCH 01/33] refactor: resolve duplicate function definitions
(#2350)
---
src/node/markdown/plugins/link.ts | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/node/markdown/plugins/link.ts b/src/node/markdown/plugins/link.ts
index cab9a6ea..d742f678 100644
--- a/src/node/markdown/plugins/link.ts
+++ b/src/node/markdown/plugins/link.ts
@@ -5,7 +5,7 @@
import type MarkdownIt from 'markdown-it'
import type { MarkdownEnv } from '../env'
import { URL } from 'url'
-import { EXTERNAL_URL_RE, PATHNAME_PROTOCOL_RE } from '../../shared'
+import { EXTERNAL_URL_RE, PATHNAME_PROTOCOL_RE, isExternal } from '../../shared'
const indexRE = /(^|.*\/)index.md(#?.*)$/i
@@ -26,8 +26,7 @@ export const linkPlugin = (
if (hrefIndex >= 0) {
const hrefAttr = token.attrs![hrefIndex]
const url = hrefAttr[1]
- const isExternal = EXTERNAL_URL_RE.test(url)
- if (isExternal) {
+ if (isExternal(url)) {
Object.entries(externalAttrs).forEach(([key, val]) => {
token.attrSet(key, val)
})
From 58795d2f938d39989a48dd04df27c43fa2cb62a9 Mon Sep 17 00:00:00 2001
From: engvuchen <31369318+engvuchen@users.noreply.github.com>
Date: Tue, 9 May 2023 00:32:21 +0800
Subject: [PATCH 02/33] docs: add warning about using block elements in footer
config (#2341)
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
---
docs/reference/default-theme-footer.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/docs/reference/default-theme-footer.md b/docs/reference/default-theme-footer.md
index e363537f..6457798e 100644
--- a/docs/reference/default-theme-footer.md
+++ b/docs/reference/default-theme-footer.md
@@ -36,4 +36,8 @@ export default {
}
```
+::: warning
+Only inline elements can be used in `message` and `copyright` as they are rendered inside a `
` element. If you want to add block elements, consider using [`layout-bottom`](../guide/extending-default-theme#layout-slots) slot instead.
+:::
+
Note that footer will not be displayed when the [SideBar](./default-theme-sidebar) is visible.
From c20bd283319158135e2d850485970dfc5fe82812 Mon Sep 17 00:00:00 2001
From: Vinicius Teixeira Dias
<69281620+viniciusteixeiradias@users.noreply.github.com>
Date: Tue, 9 May 2023 02:55:32 +1000
Subject: [PATCH 03/33] feat(theme): open search box on pressing slash too
(#2328)
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
---
.../components/VPNavBarSearch.vue | 28 +++++++++++++++++--
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/src/client/theme-default/components/VPNavBarSearch.vue b/src/client/theme-default/components/VPNavBarSearch.vue
index dfa5e588..12c3929e 100644
--- a/src/client/theme-default/components/VPNavBarSearch.vue
+++ b/src/client/theme-default/components/VPNavBarSearch.vue
@@ -61,9 +61,12 @@ onMounted(() => {
preconnect()
- const handleSearchHotKey = (e: KeyboardEvent) => {
- if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
- e.preventDefault()
+ const handleSearchHotKey = (event: KeyboardEvent) => {
+ if (
+ (event.key.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) ||
+ (!isEditingContent(event) && event.key === '/')
+ ) {
+ event.preventDefault()
load()
remove()
}
@@ -101,6 +104,18 @@ function poll() {
}, 16)
}
+function isEditingContent(event: KeyboardEvent): boolean {
+ const element = event.target as HTMLElement
+ const tagName = element.tagName
+
+ return (
+ element.isContentEditable ||
+ tagName === 'INPUT' ||
+ tagName === 'SELECT' ||
+ tagName === 'TEXTAREA'
+ )
+}
+
// Local search
const showSearch = ref(false)
@@ -112,6 +127,13 @@ if (__VP_LOCAL_SEARCH__) {
showSearch.value = true
}
})
+
+ onKeyStroke('/', (event) => {
+ if (!isEditingContent(event)) {
+ event.preventDefault()
+ showSearch.value = true
+ }
+ })
}
const metaKey = ref(`'Meta'`)
From 35f8b896372e75e62882df613a49e8945e7bc832 Mon Sep 17 00:00:00 2001
From: JD Solanki
Date: Mon, 8 May 2023 22:31:10 +0530
Subject: [PATCH 04/33] fix(theme): don't update opacity on hover (#2326)
---
src/client/theme-default/components/VPNavBarTitle.vue | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/client/theme-default/components/VPNavBarTitle.vue b/src/client/theme-default/components/VPNavBarTitle.vue
index 0da14c90..805bc7fa 100644
--- a/src/client/theme-default/components/VPNavBarTitle.vue
+++ b/src/client/theme-default/components/VPNavBarTitle.vue
@@ -35,10 +35,6 @@ const { currentLang } = useLangs()
transition: opacity 0.25s;
}
-.title:hover {
- opacity: 0.6;
-}
-
@media (min-width: 960px) {
.title {
flex-shrink: 0;
From 2f482afaabdb4206b87e2453d0099257693c4653 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?=
Date: Mon, 8 May 2023 19:22:47 +0200
Subject: [PATCH 05/33] feat(theme): add focus trap to local search dialog
(#2324)
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
---
package.json | 2 +
pnpm-lock.yaml | 66 +++++++++++++++++++
.../components/VPLocalSearchBox.vue | 22 +++++--
3 files changed, 84 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 9eba1f2e..cf967e5d 100644
--- a/package.json
+++ b/package.json
@@ -92,7 +92,9 @@
"@vitejs/plugin-vue": "^4.2.1",
"@vue/devtools-api": "^6.5.0",
"@vueuse/core": "^10.1.0",
+ "@vueuse/integrations": "^10.1.0",
"body-scroll-lock": "4.0.0-beta.0",
+ "focus-trap": "^7.4.0",
"mark.js": "8.11.1",
"minisearch": "^6.0.1",
"shiki": "^0.14.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 75561cd3..98a9864f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,9 +19,15 @@ importers:
'@vueuse/core':
specifier: ^10.1.0
version: 10.1.0(vue@3.2.47)
+ '@vueuse/integrations':
+ specifier: ^10.1.0
+ version: 10.1.0(focus-trap@7.4.0)(vue@3.2.47)
body-scroll-lock:
specifier: 4.0.0-beta.0
version: 4.0.0-beta.0
+ focus-trap:
+ specifier: ^7.4.0
+ version: 7.4.0
mark.js:
specifier: 8.11.1
version: 8.11.1
@@ -1276,6 +1282,56 @@ packages:
- vue
dev: false
+ /@vueuse/integrations@10.1.0(focus-trap@7.4.0)(vue@3.2.47):
+ resolution: {integrity: sha512-eSGdRYSFIspSYQIC0hzivi95Jv/BEH9Z47BrpNNKZi6k/LcHDAANmiNeiPN1BxlmO2PovG8dN9Et/AZC4WZ2YQ==}
+ peerDependencies:
+ async-validator: '*'
+ axios: '*'
+ change-case: '*'
+ drauu: '*'
+ focus-trap: '*'
+ fuse.js: '*'
+ idb-keyval: '*'
+ jwt-decode: '*'
+ nprogress: '*'
+ qrcode: '*'
+ sortablejs: '*'
+ universal-cookie: '*'
+ peerDependenciesMeta:
+ async-validator:
+ optional: true
+ axios:
+ optional: true
+ change-case:
+ optional: true
+ drauu:
+ optional: true
+ focus-trap:
+ optional: true
+ fuse.js:
+ optional: true
+ idb-keyval:
+ optional: true
+ jwt-decode:
+ optional: true
+ nprogress:
+ optional: true
+ qrcode:
+ optional: true
+ sortablejs:
+ optional: true
+ universal-cookie:
+ optional: true
+ dependencies:
+ '@vueuse/core': 10.1.0(vue@3.2.47)
+ '@vueuse/shared': 10.1.0(vue@3.2.47)
+ focus-trap: 7.4.0
+ vue-demi: 0.14.0(vue@3.2.47)
+ transitivePeerDependencies:
+ - '@vue/composition-api'
+ - vue
+ dev: false
+
/@vueuse/metadata@10.1.0:
resolution: {integrity: sha512-cM28HjDEw5FIrPE9rgSPFZvQ0ZYnOLAOr8hl1XM6tFl80U3WAR5ROdnAqiYybniwP5gt9MKKAJAqd/ab2aHkqg==}
dev: false
@@ -2249,6 +2305,12 @@ packages:
path-exists: 5.0.0
dev: true
+ /focus-trap@7.4.0:
+ resolution: {integrity: sha512-yI7FwUqU4TVb+7t6PaQ3spT/42r/KLEi8mtdGoQo2li/kFzmu9URmalTvw7xCCJtSOyhBxscvEAmvjeN9iHARg==}
+ dependencies:
+ tabbable: 6.1.1
+ dev: false
+
/follow-redirects@1.15.2(debug@4.3.4):
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
@@ -4156,6 +4218,10 @@ packages:
engines: {node: '>= 0.4'}
dev: true
+ /tabbable@6.1.1:
+ resolution: {integrity: sha512-4kl5w+nCB44EVRdO0g/UGoOp3vlwgycUVtkk/7DPyeLZUCuNFFKCFG6/t/DgHLrUPHjrZg6s5tNm+56Q2B0xyg==}
+ dev: false
+
/temp-dir@2.0.0:
resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
engines: {node: '>=8'}
diff --git a/src/client/theme-default/components/VPLocalSearchBox.vue b/src/client/theme-default/components/VPLocalSearchBox.vue
index 8f630248..0230d141 100644
--- a/src/client/theme-default/components/VPLocalSearchBox.vue
+++ b/src/client/theme-default/components/VPLocalSearchBox.vue
@@ -9,6 +9,7 @@ import {
useScrollLock,
useSessionStorage
} from '@vueuse/core'
+import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
import Mark from 'mark.js/src/vanilla.js'
import MiniSearch, { type SearchResult } from 'minisearch'
import { useRouter } from 'vitepress'
@@ -26,11 +27,11 @@ import {
type Ref
} from 'vue'
import type { ModalTranslations } from '../../../../types/local-search'
+import { dataSymbol } from '../../app/data'
import { pathToFile } from '../../app/utils'
import { slash } from '../../shared'
import { useData } from '../composables/data'
import { createTranslate } from '../support/translation'
-import { dataSymbol } from '../../app/data'
defineProps<{
placeholder: string
@@ -64,6 +65,12 @@ interface Result {
}
const vitePressData = useData()
+const { activate } = useFocusTrap(el, {
+ immediate: true,
+ allowOutsideClick: true,
+ clickOutsideDeactivates: true,
+ escapeDeactivates: true
+})
const { localeIndex, theme } = vitePressData
const searchIndex = computedAsync(async () =>
markRaw(
@@ -84,14 +91,14 @@ const searchIndex = computedAsync(async () =>
const disableQueryPersistence = computed(() => {
return (
- theme.value.search?.provider === 'local' &&
- theme.value.search.options?.disableQueryPersistence === true
+ theme.value.search?.provider === 'local' &&
+ theme.value.search.options?.disableQueryPersistence === true
)
})
const filterText = disableQueryPersistence.value
- ? ref('')
- : useSessionStorage('vitepress:local-search-filter', '')
+ ? ref('')
+ : useSessionStorage('vitepress:local-search-filter', '')
const showDetailedList = useLocalStorage(
'vitepress:local-search-detailed-list',
@@ -334,6 +341,7 @@ onMounted(() => {
body.value = document.body
nextTick(() => {
isLocked.value = true
+ nextTick().then(() => activate())
})
})
@@ -474,6 +482,7 @@ function formMarkRegex(terms: Set) {
}"
:aria-label="[...p.titles, p.title].join(' > ')"
@mouseenter="!disableMouseOver && (selectedIndex = index)"
+ @focusin="selectedIndex = index"
@click="$emit('close')"
>
@@ -498,7 +507,7 @@ function formMarkRegex(terms: Set) {
-
+
@@ -727,6 +736,7 @@ function formMarkRegex(terms: Set
) {
transition: none;
line-height: 1rem;
border: solid 2px var(--vp-local-search-result-border);
+ outline: none;
}
.result > div {
From b31933fbdd7aabfe080234407153aefa8f6a3f30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=83=BD=E5=AE=81?=
Date: Wed, 10 May 2023 23:28:59 +0800
Subject: [PATCH 06/33] fix(build): uniform handling of windows slash in
localSearchPlugin (#2358)
---
src/client/theme-default/components/VPLocalSearchBox.vue | 3 +--
src/node/plugins/localSearchPlugin.ts | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/client/theme-default/components/VPLocalSearchBox.vue b/src/client/theme-default/components/VPLocalSearchBox.vue
index 0230d141..0f7349b3 100644
--- a/src/client/theme-default/components/VPLocalSearchBox.vue
+++ b/src/client/theme-default/components/VPLocalSearchBox.vue
@@ -29,7 +29,6 @@ import {
import type { ModalTranslations } from '../../../../types/local-search'
import { dataSymbol } from '../../app/data'
import { pathToFile } from '../../app/utils'
-import { slash } from '../../shared'
import { useData } from '../composables/data'
import { createTranslate } from '../support/translation'
@@ -218,7 +217,7 @@ debouncedWatch(
)
async function fetchExcerpt(id: string) {
- const file = pathToFile(slash(id.slice(0, id.indexOf('#'))))
+ const file = pathToFile(id.slice(0, id.indexOf('#')))
try {
return { id, mod: await import(/*@vite-ignore*/ file) }
} catch (e) {
diff --git a/src/node/plugins/localSearchPlugin.ts b/src/node/plugins/localSearchPlugin.ts
index 0afa1adb..080a8483 100644
--- a/src/node/plugins/localSearchPlugin.ts
+++ b/src/node/plugins/localSearchPlugin.ts
@@ -60,7 +60,7 @@ export async function localSearchPlugin(
}
function getLocaleForPath(file: string) {
- const relativePath = path.relative(siteConfig.srcDir, file)
+ const relativePath = slash(path.relative(siteConfig.srcDir, file))
const siteData = resolveSiteDataByRoute(siteConfig.site, relativePath)
return siteData?.localeIndex ?? 'root'
}
@@ -97,7 +97,7 @@ export async function localSearchPlugin(
function getDocId(file: string) {
let relFile = slash(path.relative(siteConfig.srcDir, file))
relFile = siteConfig.rewrites.map[relFile] || relFile
- let id = path.join(siteConfig.site.base, relFile)
+ let id = slash(path.join(siteConfig.site.base, relFile))
id = id.replace(/\/index\.md$/, '/')
id = id.replace(/\.md$/, siteConfig.cleanUrls ? '' : '.html')
return id
From af4bb52947d9454e71ce63c06c5efe814410209b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=83=BD=E5=AE=81?=
Date: Wed, 10 May 2023 23:30:26 +0800
Subject: [PATCH 07/33] refactor: simplify `hasAside` computed property (#2356)
---
src/client/theme-default/composables/sidebar.ts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/client/theme-default/composables/sidebar.ts b/src/client/theme-default/composables/sidebar.ts
index df307d3c..a99d317e 100644
--- a/src/client/theme-default/composables/sidebar.ts
+++ b/src/client/theme-default/composables/sidebar.ts
@@ -60,8 +60,7 @@ export function useSidebar() {
const hasAside = computed(() => {
if (frontmatter.value.layout === 'home') return false
if (frontmatter.value.aside != null) return !!frontmatter.value.aside
- if (theme.value.aside === false) return false
- return true
+ return theme.value.aside !== false
})
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value)
From 97065cefc22e4772c0295c5ad23a87eea286f46b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?=
Date: Wed, 10 May 2023 23:36:15 +0800
Subject: [PATCH 08/33] feat(cli): add shortcuts (#2353)
---
src/node/cli.ts | 2 +
src/node/shortcuts.ts | 95 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+)
create mode 100644 src/node/shortcuts.ts
diff --git a/src/node/cli.ts b/src/node/cli.ts
index 39be1190..4aef9747 100644
--- a/src/node/cli.ts
+++ b/src/node/cli.ts
@@ -4,6 +4,7 @@ import { createLogger } from 'vite'
import { build, createServer, serve } from '.'
import { init } from './init/init'
import { version } from '../../package.json'
+import { bindShortcuts } from './shortcuts'
const argv: any = minimist(process.argv.slice(2))
@@ -33,6 +34,7 @@ if (!command || command === 'dev') {
await server.listen()
logVersion(server.config.logger)
server.printUrls()
+ bindShortcuts(server)
}
createDevServer().catch((err) => {
createLogger().error(
diff --git a/src/node/shortcuts.ts b/src/node/shortcuts.ts
new file mode 100644
index 00000000..7e27fd65
--- /dev/null
+++ b/src/node/shortcuts.ts
@@ -0,0 +1,95 @@
+import colors from 'picocolors'
+import type { ViteDevServer } from 'vite'
+
+export type CLIShortcut = {
+ key: string
+ description: string
+ action(server: ViteDevServer): void | Promise
+}
+
+export function bindShortcuts(server: ViteDevServer): void {
+ if (!server.httpServer || !process.stdin.isTTY || process.env.CI) {
+ return
+ }
+
+ server.config.logger.info(
+ colors.dim(colors.green(' ➜')) +
+ colors.dim(' press ') +
+ colors.bold('h') +
+ colors.dim(' to show help')
+ )
+
+ let actionRunning = false
+
+ const onInput = async (input: string) => {
+ // ctrl+c or ctrl+d
+ if (input === '\x03' || input === '\x04') {
+ await server.close().finally(() => process.exit(1))
+ return
+ }
+
+ if (actionRunning) return
+
+ if (input === 'h') {
+ server.config.logger.info(
+ [
+ '',
+ colors.bold(' Shortcuts'),
+ ...SHORTCUTS.map(
+ (shortcut) =>
+ colors.dim(' press ') +
+ colors.bold(shortcut.key) +
+ colors.dim(` to ${shortcut.description}`)
+ )
+ ].join('\n')
+ )
+ }
+
+ const shortcut = SHORTCUTS.find((shortcut) => shortcut.key === input)
+ if (!shortcut) return
+
+ actionRunning = true
+ await shortcut.action(server)
+ actionRunning = false
+ }
+
+ process.stdin.setRawMode(true)
+
+ process.stdin.on('data', onInput).setEncoding('utf8').resume()
+
+ server.httpServer.on('close', () => {
+ process.stdin.off('data', onInput).pause()
+ })
+}
+
+const SHORTCUTS: CLIShortcut[] = [
+ {
+ key: 'u',
+ description: 'show server url',
+ action(server) {
+ server.config.logger.info('')
+ server.printUrls()
+ }
+ },
+ {
+ key: 'o',
+ description: 'open in browser',
+ action(server) {
+ server.openBrowser()
+ }
+ },
+ {
+ key: 'c',
+ description: 'clear console',
+ action(server) {
+ server.config.logger.clearScreen('error')
+ }
+ },
+ {
+ key: 'q',
+ description: 'quit',
+ async action(server) {
+ await server.close().finally(() => process.exit())
+ }
+ }
+]
From d6c0985002ee792b1e8e052f71cdd6bd72c315ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?=
Date: Wed, 10 May 2023 17:38:45 +0200
Subject: [PATCH 09/33] fix(a11y): mobile and theme switcher (#2354)
---
.../theme-default/components/VPNavBar.vue | 6 ++++++
.../components/VPNavBarSearchButton.vue | 2 +-
.../components/VPSwitchAppearance.vue | 19 +++++++++----------
3 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/client/theme-default/components/VPNavBar.vue b/src/client/theme-default/components/VPNavBar.vue
index bccf5c68..bcd7d0b4 100644
--- a/src/client/theme-default/components/VPNavBar.vue
+++ b/src/client/theme-default/components/VPNavBar.vue
@@ -175,6 +175,12 @@ const classes = computed(() => ({
}
}
+@media (max-width: 768px) {
+ .content-body {
+ column-gap: 0.5rem;
+ }
+}
+
.menu + .translations::before,
.menu + .appearance::before,
.menu + .social-links::before,
diff --git a/src/client/theme-default/components/VPNavBarSearchButton.vue b/src/client/theme-default/components/VPNavBarSearchButton.vue
index f3436a42..886bce29 100644
--- a/src/client/theme-default/components/VPNavBarSearchButton.vue
+++ b/src/client/theme-default/components/VPNavBarSearchButton.vue
@@ -61,7 +61,7 @@ defineProps<{
align-items: center;
margin: 0;
padding: 0;
- width: 32px;
+ width: 48px;
height: 55px;
background: transparent;
transition: border-color 0.25s;
diff --git a/src/client/theme-default/components/VPSwitchAppearance.vue b/src/client/theme-default/components/VPSwitchAppearance.vue
index f4da3e9e..3a283545 100644
--- a/src/client/theme-default/components/VPSwitchAppearance.vue
+++ b/src/client/theme-default/components/VPSwitchAppearance.vue
@@ -75,16 +75,15 @@ watch(checked, (newIsDark) => {
-
+
+
+
+