vitepress 2.0.0-alpha.12 → 2.0.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.d.ts +9 -0
- package/dist/client/app/composables/codeGroups.js +6 -2
- package/dist/client/app/composables/copyCode.js +5 -3
- package/dist/client/app/router.js +39 -17
- package/dist/client/shared.js +4 -0
- package/dist/client/theme-default/components/VPBadge.vue +1 -0
- package/dist/client/theme-default/components/VPContent.vue +2 -2
- package/dist/client/theme-default/components/VPDocFooterLastUpdated.vue +22 -10
- package/dist/client/theme-default/components/VPDocOutlineItem.vue +1 -7
- package/dist/client/theme-default/components/VPLocalNav.vue +0 -6
- package/dist/client/theme-default/components/VPMenuLink.vue +14 -3
- package/dist/client/theme-default/components/VPNavBar.vue +5 -9
- package/dist/client/theme-default/components/VPNavBarExtra.vue +1 -1
- package/dist/client/theme-default/components/VPNavBarMenuGroup.vue +1 -1
- package/dist/client/theme-default/components/VPNavBarMenuLink.vue +10 -3
- package/dist/client/theme-default/components/VPNavBarTranslations.vue +1 -1
- package/dist/client/theme-default/components/VPNavScreenMenuGroupLink.vue +12 -3
- package/dist/client/theme-default/components/VPNavScreenMenuLink.vue +12 -3
- package/dist/client/theme-default/components/VPNavScreenTranslations.vue +8 -1
- package/dist/client/theme-default/components/VPSidebar.vue +3 -3
- package/dist/client/theme-default/components/VPSkipLink.vue +2 -23
- package/dist/client/theme-default/composables/langs.js +3 -1
- package/dist/client/theme-default/composables/outline.js +1 -1
- package/dist/client/theme-default/styles/components/vp-doc.css +1 -1
- package/dist/node/{chunk-3d7P_gGE.js → chunk-BvyEjT9v.js} +3152 -3647
- package/dist/node/cli.js +12 -10
- package/dist/node/index.d.ts +48 -10
- package/dist/node/index.js +13 -11
- package/package.json +46 -46
- package/types/default-theme.d.ts +1 -1
package/client.d.ts
CHANGED
|
@@ -3,3 +3,12 @@
|
|
|
3
3
|
/// <reference types="vite/client" />
|
|
4
4
|
|
|
5
5
|
export * from './dist/client/index.js'
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
interface WindowEventMap {
|
|
9
|
+
'vitepress:codeGroupTabActivate': Event & {
|
|
10
|
+
/** code block element that was activated */
|
|
11
|
+
detail: Element
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -6,7 +6,7 @@ export function useCodeGroups() {
|
|
|
6
6
|
Array.from(el.children).forEach((child) => {
|
|
7
7
|
child.classList.remove('active');
|
|
8
8
|
});
|
|
9
|
-
el.children[0]
|
|
9
|
+
activate(el.children[0]);
|
|
10
10
|
});
|
|
11
11
|
});
|
|
12
12
|
}
|
|
@@ -31,10 +31,14 @@ export function useCodeGroups() {
|
|
|
31
31
|
if (!next || current === next)
|
|
32
32
|
return;
|
|
33
33
|
current.classList.remove('active');
|
|
34
|
-
next
|
|
34
|
+
activate(next);
|
|
35
35
|
const label = group?.querySelector(`label[for="${el.id}"]`);
|
|
36
36
|
label?.scrollIntoView({ block: 'nearest' });
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
function activate(el) {
|
|
42
|
+
el.classList.add('active');
|
|
43
|
+
window.dispatchEvent(new CustomEvent('vitepress:codeGroupTabActivate', { detail: el }));
|
|
44
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { inBrowser } from 'vitepress';
|
|
2
|
-
|
|
2
|
+
import { isShell } from '../../shared';
|
|
3
3
|
const ignoredNodes = ['.vp-copy-ignore', '.diff.remove'].join(', ');
|
|
4
4
|
export function useCopyCode() {
|
|
5
5
|
if (inBrowser) {
|
|
@@ -12,7 +12,6 @@ export function useCopyCode() {
|
|
|
12
12
|
if (!parent || !sibling) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
const isShell = shellRE.test(parent.className);
|
|
16
15
|
// Clone the node and remove the ignored nodes
|
|
17
16
|
const clone = sibling.cloneNode(true);
|
|
18
17
|
clone.querySelectorAll(ignoredNodes).forEach((node) => node.remove());
|
|
@@ -20,7 +19,10 @@ export function useCopyCode() {
|
|
|
20
19
|
// doesn't affect the newlines already in the code because they are rendered as `\n<span class="line"></span>`
|
|
21
20
|
clone.innerHTML = clone.innerHTML.replace(/\n+/g, '\n');
|
|
22
21
|
let text = clone.textContent || '';
|
|
23
|
-
|
|
22
|
+
// NOTE: Any changes to this the code here may also need to update
|
|
23
|
+
// `transformerDisableShellSymbolSelect` in `src/node/markdown/plugins/highlight.ts`
|
|
24
|
+
const lang = /language-(\w+)/.exec(parent.className)?.[1] || '';
|
|
25
|
+
if (isShell(lang)) {
|
|
24
26
|
text = text.replace(/^ *(\$|>) /gm, '').trim();
|
|
25
27
|
}
|
|
26
28
|
copyToClipboard(text).then(() => {
|
|
@@ -4,7 +4,7 @@ import { siteDataRef } from './data';
|
|
|
4
4
|
import { getScrollOffset, inBrowser, withBase } from './utils';
|
|
5
5
|
export const RouterSymbol = Symbol();
|
|
6
6
|
// we are just using URL to parse the pathname and hash - the base doesn't
|
|
7
|
-
// matter and is only passed to support same-host hrefs
|
|
7
|
+
// matter and is only passed to support same-host hrefs
|
|
8
8
|
const fakeHost = 'http://a.com';
|
|
9
9
|
const getDefaultRoute = () => ({
|
|
10
10
|
path: '/',
|
|
@@ -177,21 +177,43 @@ export function scrollTo(hash, smooth = false, scrollPosition = 0) {
|
|
|
177
177
|
catch (e) {
|
|
178
178
|
console.warn(e);
|
|
179
179
|
}
|
|
180
|
-
if (target)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
180
|
+
if (!target)
|
|
181
|
+
return;
|
|
182
|
+
const targetTop = window.scrollY +
|
|
183
|
+
target.getBoundingClientRect().top -
|
|
184
|
+
getScrollOffset() +
|
|
185
|
+
Number.parseInt(window.getComputedStyle(target).paddingTop, 10) || 0;
|
|
186
|
+
const behavior = window.matchMedia('(prefers-reduced-motion)').matches
|
|
187
|
+
? 'instant'
|
|
188
|
+
: // only smooth scroll if distance is smaller than screen height
|
|
189
|
+
smooth && Math.abs(targetTop - window.scrollY) <= window.innerHeight
|
|
190
|
+
? 'smooth'
|
|
191
|
+
: 'auto';
|
|
192
|
+
const scrollToTarget = () => {
|
|
193
|
+
window.scrollTo({ left: 0, top: targetTop, behavior });
|
|
194
|
+
// focus the target element for better accessibility
|
|
195
|
+
target.focus({ preventScroll: true });
|
|
196
|
+
// return if focus worked
|
|
197
|
+
if (document.activeElement === target)
|
|
198
|
+
return;
|
|
199
|
+
// element has tabindex already, likely not focusable
|
|
200
|
+
// because of some other reason, bail out
|
|
201
|
+
if (target.hasAttribute('tabindex'))
|
|
202
|
+
return;
|
|
203
|
+
const restoreTabindex = () => {
|
|
204
|
+
target.removeAttribute('tabindex');
|
|
205
|
+
target.removeEventListener('blur', restoreTabindex);
|
|
206
|
+
};
|
|
207
|
+
// temporarily make the target element focusable
|
|
208
|
+
target.setAttribute('tabindex', '-1');
|
|
209
|
+
target.addEventListener('blur', restoreTabindex);
|
|
210
|
+
// try to focus again
|
|
211
|
+
target.focus({ preventScroll: true });
|
|
212
|
+
// remove tabindex and event listener if focus still not worked
|
|
213
|
+
if (document.activeElement !== target)
|
|
214
|
+
restoreTabindex();
|
|
215
|
+
};
|
|
216
|
+
requestAnimationFrame(scrollToTarget);
|
|
195
217
|
}
|
|
196
218
|
function handleHMR(route) {
|
|
197
219
|
// update route.data on HMR updates of active page
|
|
@@ -213,7 +235,7 @@ function shouldHotReload(payload) {
|
|
|
213
235
|
function normalizeHref(href) {
|
|
214
236
|
const url = new URL(href, fakeHost);
|
|
215
237
|
url.pathname = url.pathname.replace(/(^|\/)index(\.html)?$/, '$1');
|
|
216
|
-
// ensure correct deep link so page refresh lands on correct files
|
|
238
|
+
// ensure correct deep link so page refresh lands on correct files
|
|
217
239
|
if (siteDataRef.value.cleanUrls) {
|
|
218
240
|
url.pathname = url.pathname.replace(/\.html$/, '');
|
|
219
241
|
}
|
package/dist/client/shared.js
CHANGED
|
@@ -237,3 +237,7 @@ stackView.unpack = function (obj) {
|
|
|
237
237
|
export function isObject(value) {
|
|
238
238
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
239
239
|
}
|
|
240
|
+
const shellLangs = ['shellscript', 'shell', 'bash', 'sh', 'zsh'];
|
|
241
|
+
export function isShell(lang) {
|
|
242
|
+
return shellLangs.includes(lang);
|
|
243
|
+
}
|
|
@@ -88,8 +88,8 @@ const { isHome, hasSidebar } = useLayout()
|
|
|
88
88
|
|
|
89
89
|
@media (min-width: 1440px) {
|
|
90
90
|
.VPContent.has-sidebar {
|
|
91
|
-
padding-right: calc((
|
|
92
|
-
padding-left: calc((
|
|
91
|
+
padding-right: calc((100% - var(--vp-layout-max-width)) / 2);
|
|
92
|
+
padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
</style>
|
|
@@ -1,26 +1,38 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { useNavigatorLanguage } from '@vueuse/core'
|
|
3
|
+
import { computed, onMounted, shallowRef, useTemplateRef, watchEffect } from 'vue'
|
|
3
4
|
import { useData } from '../composables/data'
|
|
4
5
|
|
|
5
|
-
const { theme, page, lang } = useData()
|
|
6
|
+
const { theme, page, lang: pageLang } = useData()
|
|
7
|
+
const { language: browserLang } = useNavigatorLanguage()
|
|
6
8
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
)
|
|
9
|
+
const timeRef = useTemplateRef('timeRef')
|
|
10
|
+
|
|
11
|
+
const date = computed(() => new Date(page.value.lastUpdated!))
|
|
10
12
|
const isoDatetime = computed(() => date.value.toISOString())
|
|
11
|
-
const datetime =
|
|
13
|
+
const datetime = shallowRef('')
|
|
12
14
|
|
|
13
15
|
// set time on mounted hook to avoid hydration mismatch due to
|
|
14
16
|
// potential differences in timezones of the server and clients
|
|
15
17
|
onMounted(() => {
|
|
16
18
|
watchEffect(() => {
|
|
19
|
+
const lang = theme.value.lastUpdated?.formatOptions?.forceLocale
|
|
20
|
+
? pageLang.value
|
|
21
|
+
: browserLang.value
|
|
22
|
+
|
|
17
23
|
datetime.value = new Intl.DateTimeFormat(
|
|
18
|
-
|
|
24
|
+
lang,
|
|
19
25
|
theme.value.lastUpdated?.formatOptions ?? {
|
|
20
|
-
dateStyle: '
|
|
21
|
-
timeStyle: '
|
|
26
|
+
dateStyle: 'medium',
|
|
27
|
+
timeStyle: 'medium'
|
|
22
28
|
}
|
|
23
29
|
).format(date.value)
|
|
30
|
+
|
|
31
|
+
if (lang && pageLang.value !== lang) {
|
|
32
|
+
timeRef.value?.setAttribute('lang', lang)
|
|
33
|
+
} else {
|
|
34
|
+
timeRef.value?.removeAttribute('lang')
|
|
35
|
+
}
|
|
24
36
|
})
|
|
25
37
|
})
|
|
26
38
|
</script>
|
|
@@ -28,7 +40,7 @@ onMounted(() => {
|
|
|
28
40
|
<template>
|
|
29
41
|
<p class="VPLastUpdated">
|
|
30
42
|
{{ theme.lastUpdated?.text || theme.lastUpdatedText || 'Last updated' }}:
|
|
31
|
-
<time :datetime="isoDatetime">{{ datetime }}</time>
|
|
43
|
+
<time ref="timeRef" :datetime="isoDatetime">{{ datetime }}</time>
|
|
32
44
|
</p>
|
|
33
45
|
</template>
|
|
34
46
|
|
|
@@ -5,18 +5,12 @@ defineProps<{
|
|
|
5
5
|
headers: DefaultTheme.OutlineItem[]
|
|
6
6
|
root?: boolean
|
|
7
7
|
}>()
|
|
8
|
-
|
|
9
|
-
function onClick({ target: el }: Event) {
|
|
10
|
-
const id = (el as HTMLAnchorElement).href!.split('#')[1]
|
|
11
|
-
const heading = document.getElementById(decodeURIComponent(id))
|
|
12
|
-
heading?.focus({ preventScroll: true })
|
|
13
|
-
}
|
|
14
8
|
</script>
|
|
15
9
|
|
|
16
10
|
<template>
|
|
17
11
|
<ul class="VPDocOutlineItem" :class="root ? 'root' : 'nested'">
|
|
18
12
|
<li v-for="{ children, link, title } in headers">
|
|
19
|
-
<a class="outline-link" :href="link"
|
|
13
|
+
<a class="outline-link" :href="link" :title>
|
|
20
14
|
{{ title }}
|
|
21
15
|
</a>
|
|
22
16
|
<template v-if="children?.length">
|
|
@@ -98,12 +98,6 @@ const classes = computed(() => {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
@media (min-width: 1440px) {
|
|
102
|
-
.VPLocalNav.has-sidebar {
|
|
103
|
-
padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
101
|
.container {
|
|
108
102
|
display: flex;
|
|
109
103
|
justify-content: space-between;
|
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
<script lang="ts" setup generic="T extends DefaultTheme.NavItemWithLink">
|
|
2
2
|
import type { DefaultTheme } from 'vitepress/theme'
|
|
3
|
+
import { computed } from 'vue'
|
|
3
4
|
import { useData } from '../composables/data'
|
|
4
5
|
import { isActive } from '../../shared'
|
|
5
6
|
import VPLink from './VPLink.vue'
|
|
6
7
|
|
|
7
|
-
defineProps<{
|
|
8
|
+
const props = defineProps<{
|
|
8
9
|
item: T
|
|
9
10
|
}>()
|
|
10
11
|
|
|
11
12
|
const { page } = useData()
|
|
13
|
+
|
|
14
|
+
const href = computed(() =>
|
|
15
|
+
typeof props.item.link === 'function'
|
|
16
|
+
? props.item.link(page.value)
|
|
17
|
+
: props.item.link
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
defineOptions({ inheritAttrs: false })
|
|
12
21
|
</script>
|
|
13
22
|
|
|
14
23
|
<template>
|
|
15
24
|
<div class="VPMenuLink">
|
|
16
25
|
<VPLink
|
|
26
|
+
v-bind="$attrs"
|
|
17
27
|
:class="{
|
|
18
28
|
active: isActive(
|
|
19
29
|
page.relativePath,
|
|
20
|
-
item.activeMatch ||
|
|
30
|
+
item.activeMatch || href,
|
|
21
31
|
!!item.activeMatch
|
|
22
32
|
)
|
|
23
33
|
}"
|
|
24
|
-
:href
|
|
34
|
+
:href
|
|
25
35
|
:target="item.target"
|
|
26
36
|
:rel="item.rel"
|
|
27
37
|
:no-icon="item.noIcon"
|
|
@@ -46,6 +56,7 @@ const { page } = useData()
|
|
|
46
56
|
font-size: 14px;
|
|
47
57
|
font-weight: 500;
|
|
48
58
|
color: var(--vp-c-text-1);
|
|
59
|
+
text-align: left;
|
|
49
60
|
white-space: nowrap;
|
|
50
61
|
transition:
|
|
51
62
|
background-color 0.25s,
|
|
@@ -171,20 +171,14 @@ watchPostEffect(() => {
|
|
|
171
171
|
position: relative;
|
|
172
172
|
z-index: 1;
|
|
173
173
|
padding-left: var(--vp-sidebar-width);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.VPNavBar.has-sidebar .content-body {
|
|
177
174
|
padding-right: 32px;
|
|
178
175
|
}
|
|
179
176
|
}
|
|
180
177
|
|
|
181
178
|
@media (min-width: 1440px) {
|
|
182
179
|
.VPNavBar.has-sidebar .content {
|
|
183
|
-
padding-left: calc((
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
.VPNavBar.has-sidebar .content-body {
|
|
187
|
-
padding-right: calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);
|
|
180
|
+
padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
|
|
181
|
+
padding-right: calc((100% - var(--vp-layout-max-width)) / 2 + 32px);
|
|
188
182
|
}
|
|
189
183
|
}
|
|
190
184
|
|
|
@@ -193,6 +187,8 @@ watchPostEffect(() => {
|
|
|
193
187
|
justify-content: flex-end;
|
|
194
188
|
align-items: center;
|
|
195
189
|
height: var(--vp-nav-height);
|
|
190
|
+
margin-right: -100vw;
|
|
191
|
+
padding-right: 100vw;
|
|
196
192
|
transition: background-color 0.5s;
|
|
197
193
|
}
|
|
198
194
|
|
|
@@ -252,7 +248,7 @@ watchPostEffect(() => {
|
|
|
252
248
|
|
|
253
249
|
@media (min-width: 1440px) {
|
|
254
250
|
.VPNavBar.has-sidebar .divider {
|
|
255
|
-
padding-left: calc((
|
|
251
|
+
padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
|
|
256
252
|
}
|
|
257
253
|
}
|
|
258
254
|
|
|
@@ -31,7 +31,7 @@ const hasExtraContent = computed(
|
|
|
31
31
|
<p class="trans-title">{{ currentLang.label }}</p>
|
|
32
32
|
|
|
33
33
|
<template v-for="locale in localeLinks" :key="locale.link">
|
|
34
|
-
<VPMenuLink :item="locale" />
|
|
34
|
+
<VPMenuLink :item="locale" :lang="locale.lang" :dir="locale.dir" />
|
|
35
35
|
</template>
|
|
36
36
|
</div>
|
|
37
37
|
|
|
@@ -17,7 +17,7 @@ const isChildActive = (navItem: DefaultTheme.NavItem) => {
|
|
|
17
17
|
if ('link' in navItem) {
|
|
18
18
|
return isActive(
|
|
19
19
|
page.value.relativePath,
|
|
20
|
-
navItem.link,
|
|
20
|
+
typeof navItem.link === "function" ? navItem.link(page.value) : navItem.link,
|
|
21
21
|
!!props.item.activeMatch
|
|
22
22
|
)
|
|
23
23
|
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { DefaultTheme } from 'vitepress/theme'
|
|
3
|
+
import { computed } from 'vue'
|
|
3
4
|
import { useData } from '../composables/data'
|
|
4
5
|
import { isActive } from '../../shared'
|
|
5
6
|
import VPLink from './VPLink.vue'
|
|
6
7
|
|
|
7
|
-
defineProps<{
|
|
8
|
+
const props = defineProps<{
|
|
8
9
|
item: DefaultTheme.NavItemWithLink
|
|
9
10
|
}>()
|
|
10
11
|
|
|
11
12
|
const { page } = useData()
|
|
13
|
+
|
|
14
|
+
const href = computed(() =>
|
|
15
|
+
typeof props.item.link === 'function'
|
|
16
|
+
? props.item.link(page.value)
|
|
17
|
+
: props.item.link
|
|
18
|
+
)
|
|
12
19
|
</script>
|
|
13
20
|
|
|
14
21
|
<template>
|
|
@@ -17,11 +24,11 @@ const { page } = useData()
|
|
|
17
24
|
VPNavBarMenuLink: true,
|
|
18
25
|
active: isActive(
|
|
19
26
|
page.relativePath,
|
|
20
|
-
item.activeMatch ||
|
|
27
|
+
item.activeMatch || href,
|
|
21
28
|
!!item.activeMatch
|
|
22
29
|
)
|
|
23
30
|
}"
|
|
24
|
-
:href
|
|
31
|
+
:href
|
|
25
32
|
:target="item.target"
|
|
26
33
|
:rel="item.rel"
|
|
27
34
|
:no-icon="item.noIcon"
|
|
@@ -19,7 +19,7 @@ const { localeLinks, currentLang } = useLangs({ correspondingLink: true })
|
|
|
19
19
|
<p class="title">{{ currentLang.label }}</p>
|
|
20
20
|
|
|
21
21
|
<template v-for="locale in localeLinks" :key="locale.link">
|
|
22
|
-
<VPMenuLink :item="locale" />
|
|
22
|
+
<VPMenuLink :item="locale" :lang="locale.lang" :dir="locale.dir" />
|
|
23
23
|
</template>
|
|
24
24
|
</div>
|
|
25
25
|
</VPFlyout>
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { DefaultTheme } from 'vitepress/theme'
|
|
3
|
-
import { inject } from 'vue'
|
|
3
|
+
import { computed, inject } from 'vue'
|
|
4
|
+
import { useData } from '../composables/data'
|
|
4
5
|
import { navInjectionKey } from '../composables/nav'
|
|
5
6
|
import VPLink from './VPLink.vue'
|
|
6
7
|
|
|
7
|
-
defineProps<{
|
|
8
|
+
const props = defineProps<{
|
|
8
9
|
item: DefaultTheme.NavItemWithLink
|
|
9
10
|
}>()
|
|
10
11
|
|
|
12
|
+
const { page } = useData()
|
|
13
|
+
|
|
14
|
+
const href = computed(() =>
|
|
15
|
+
typeof props.item.link === 'function'
|
|
16
|
+
? props.item.link(page.value)
|
|
17
|
+
: props.item.link
|
|
18
|
+
)
|
|
19
|
+
|
|
11
20
|
const { closeScreen } = inject(navInjectionKey)!
|
|
12
21
|
</script>
|
|
13
22
|
|
|
14
23
|
<template>
|
|
15
24
|
<VPLink
|
|
16
25
|
class="VPNavScreenMenuGroupLink"
|
|
17
|
-
:href
|
|
26
|
+
:href
|
|
18
27
|
:target="item.target"
|
|
19
28
|
:rel="item.rel"
|
|
20
29
|
:no-icon="item.noIcon"
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { DefaultTheme } from 'vitepress/theme'
|
|
3
|
-
import { inject } from 'vue'
|
|
3
|
+
import { computed, inject } from 'vue'
|
|
4
|
+
import { useData } from '../composables/data'
|
|
4
5
|
import { navInjectionKey } from '../composables/nav'
|
|
5
6
|
import VPLink from './VPLink.vue'
|
|
6
7
|
|
|
7
|
-
defineProps<{
|
|
8
|
+
const props = defineProps<{
|
|
8
9
|
item: DefaultTheme.NavItemWithLink
|
|
9
10
|
}>()
|
|
10
11
|
|
|
12
|
+
const { page } = useData()
|
|
13
|
+
|
|
14
|
+
const href = computed(() =>
|
|
15
|
+
typeof props.item.link === 'function'
|
|
16
|
+
? props.item.link(page.value)
|
|
17
|
+
: props.item.link
|
|
18
|
+
)
|
|
19
|
+
|
|
11
20
|
const { closeScreen } = inject(navInjectionKey)!
|
|
12
21
|
</script>
|
|
13
22
|
|
|
14
23
|
<template>
|
|
15
24
|
<VPLink
|
|
16
25
|
class="VPNavScreenMenuLink"
|
|
17
|
-
:href
|
|
26
|
+
:href
|
|
18
27
|
:target="item.target"
|
|
19
28
|
:rel="item.rel"
|
|
20
29
|
:no-icon="item.noIcon"
|
|
@@ -25,7 +25,14 @@ function toggle() {
|
|
|
25
25
|
|
|
26
26
|
<ul class="list">
|
|
27
27
|
<li v-for="locale in localeLinks" :key="locale.link" class="item">
|
|
28
|
-
<VPLink
|
|
28
|
+
<VPLink
|
|
29
|
+
class="link"
|
|
30
|
+
:href="locale.link"
|
|
31
|
+
:lang="locale.lang"
|
|
32
|
+
:dir="locale.dir"
|
|
33
|
+
>
|
|
34
|
+
{{ locale.text }}
|
|
35
|
+
</VPLink>
|
|
29
36
|
</li>
|
|
30
37
|
</ul>
|
|
31
38
|
</div>
|
|
@@ -111,15 +111,15 @@ watch(
|
|
|
111
111
|
|
|
112
112
|
@media (min-width: 1440px) {
|
|
113
113
|
.VPSidebar {
|
|
114
|
-
padding-left: max(32px, calc((
|
|
115
|
-
width: calc((
|
|
114
|
+
padding-left: max(32px, calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));
|
|
115
|
+
width: calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
@media (min-width: 960px) {
|
|
120
120
|
.curtain {
|
|
121
121
|
position: sticky;
|
|
122
|
-
top: -
|
|
122
|
+
top: calc(var(--vp-nav-height) * -1);
|
|
123
123
|
left: 0;
|
|
124
124
|
z-index: 1;
|
|
125
125
|
margin-top: calc(var(--vp-nav-height) * -1);
|
|
@@ -8,39 +8,18 @@ const route = useRoute()
|
|
|
8
8
|
const backToTop = ref()
|
|
9
9
|
|
|
10
10
|
watch(() => route.path, () => backToTop.value.focus())
|
|
11
|
-
|
|
12
|
-
function focusOnTargetAnchor({ target }: Event) {
|
|
13
|
-
const el = document.getElementById(
|
|
14
|
-
decodeURIComponent((target as HTMLAnchorElement).hash).slice(1)
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
if (el) {
|
|
18
|
-
const removeTabIndex = () => {
|
|
19
|
-
el.removeAttribute('tabindex')
|
|
20
|
-
el.removeEventListener('blur', removeTabIndex)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
el.setAttribute('tabindex', '-1')
|
|
24
|
-
el.addEventListener('blur', removeTabIndex)
|
|
25
|
-
el.focus()
|
|
26
|
-
window.scrollTo(0, 0)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
11
|
</script>
|
|
30
12
|
|
|
31
13
|
<template>
|
|
32
14
|
<span ref="backToTop" tabindex="-1" />
|
|
33
|
-
<a
|
|
34
|
-
href="#VPContent"
|
|
35
|
-
class="VPSkipLink visually-hidden"
|
|
36
|
-
@click="focusOnTargetAnchor"
|
|
37
|
-
>
|
|
15
|
+
<a href="#VPContent" class="VPSkipLink visually-hidden">
|
|
38
16
|
{{ theme.skipToContentLabel || 'Skip to content' }}
|
|
39
17
|
</a>
|
|
40
18
|
</template>
|
|
41
19
|
|
|
42
20
|
<style scoped>
|
|
43
21
|
.VPSkipLink {
|
|
22
|
+
position: fixed;
|
|
44
23
|
top: 8px;
|
|
45
24
|
left: 8px;
|
|
46
25
|
padding: 8px 16px;
|
|
@@ -12,7 +12,9 @@ export function useLangs({ correspondingLink = false } = {}) {
|
|
|
12
12
|
? []
|
|
13
13
|
: {
|
|
14
14
|
text: value.label,
|
|
15
|
-
link: normalizeLink(value.link || (key === 'root' ? '/' : `/${key}/`), theme.value.i18nRouting !== false && correspondingLink, page.value.relativePath.slice(currentLang.value.link.length - 1), !site.value.cleanUrls) + hash.value
|
|
15
|
+
link: normalizeLink(value.link || (key === 'root' ? '/' : `/${key}/`), theme.value.i18nRouting !== false && correspondingLink, page.value.relativePath.slice(currentLang.value.link.length - 1), !site.value.cleanUrls) + hash.value,
|
|
16
|
+
lang: value.lang,
|
|
17
|
+
dir: value.dir
|
|
16
18
|
}));
|
|
17
19
|
return { localeLinks, currentLang };
|
|
18
20
|
}
|
|
@@ -14,7 +14,7 @@ export function resolveTitle(theme) {
|
|
|
14
14
|
}
|
|
15
15
|
export function getHeaders(range) {
|
|
16
16
|
const headers = [
|
|
17
|
-
...document.querySelectorAll('.VPDoc
|
|
17
|
+
...document.querySelectorAll('.VPDoc h1, .VPDoc h2, .VPDoc h3, .VPDoc h4, .VPDoc h5, .VPDoc h6')
|
|
18
18
|
]
|
|
19
19
|
.filter((el) => el.id && el.hasChildNodes())
|
|
20
20
|
.map((el) => {
|