vitepress 2.0.0-alpha.11 → 2.0.0-alpha.13
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/dist/client/app/composables/copyCode.js +5 -3
- package/dist/client/app/data.js +1 -9
- package/dist/client/app/router.js +39 -17
- package/dist/client/shared.js +4 -0
- package/dist/client/theme-default/components/VPAlgoliaSearchBox.vue +1 -1
- package/dist/client/theme-default/components/VPBadge.vue +1 -0
- 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 +5 -10
- package/dist/client/theme-default/components/VPLocalNavOutlineDropdown.vue +0 -10
- package/dist/client/theme-default/components/VPMenuLink.vue +14 -3
- package/dist/client/theme-default/components/VPNavBar.vue +8 -2
- 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/client/theme-default/styles/icons.css +2 -2
- package/dist/node/{chunk-CwUP9ZhX.js → chunk-ChGxanGi.js} +7519 -4597
- package/dist/node/cli.js +55 -47
- package/dist/node/index.d.ts +66 -33
- package/dist/node/index.js +41 -24
- package/package.json +52 -52
- package/types/default-theme.d.ts +1 -1
|
@@ -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(() => {
|
package/dist/client/app/data.js
CHANGED
|
@@ -4,15 +4,7 @@ import { computed, inject, readonly, ref, shallowRef, watch } from 'vue';
|
|
|
4
4
|
import { APPEARANCE_KEY, createTitle, inBrowser, resolveSiteDataByRoute } from '../shared';
|
|
5
5
|
export const dataSymbol = Symbol();
|
|
6
6
|
// site data is a singleton
|
|
7
|
-
export const siteDataRef = shallowRef(
|
|
8
|
-
// hmr
|
|
9
|
-
if (import.meta.hot) {
|
|
10
|
-
import.meta.hot.accept('@siteData', (m) => {
|
|
11
|
-
if (m) {
|
|
12
|
-
siteDataRef.value = m.default;
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
}
|
|
7
|
+
export const siteDataRef = shallowRef(readonly(siteData));
|
|
16
8
|
// per-app data
|
|
17
9
|
export function initData(route) {
|
|
18
10
|
const site = computed(() => resolveSiteDataByRoute(siteDataRef.value, route.data.relativePath));
|
|
@@ -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
|
+
}
|
|
@@ -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">
|
|
@@ -32,7 +32,7 @@ const classes = computed(() => {
|
|
|
32
32
|
VPLocalNav: true,
|
|
33
33
|
'has-sidebar': hasSidebar.value,
|
|
34
34
|
empty: !hasLocalNav.value,
|
|
35
|
-
fixed: !hasLocalNav.value && !hasSidebar.value
|
|
35
|
+
fixed: !hasLocalNav.value && !hasSidebar.value
|
|
36
36
|
}
|
|
37
37
|
})
|
|
38
38
|
</script>
|
|
@@ -113,7 +113,6 @@ const classes = computed(() => {
|
|
|
113
113
|
.menu {
|
|
114
114
|
display: flex;
|
|
115
115
|
align-items: center;
|
|
116
|
-
padding: 12px 24px 11px;
|
|
117
116
|
line-height: 24px;
|
|
118
117
|
font-size: 12px;
|
|
119
118
|
font-weight: 500;
|
|
@@ -126,12 +125,6 @@ const classes = computed(() => {
|
|
|
126
125
|
transition: color 0.25s;
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
@media (min-width: 768px) {
|
|
130
|
-
.menu {
|
|
131
|
-
padding: 0 32px;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
128
|
@media (min-width: 960px) {
|
|
136
129
|
.menu {
|
|
137
130
|
display: none;
|
|
@@ -143,12 +136,14 @@ const classes = computed(() => {
|
|
|
143
136
|
font-size: 14px;
|
|
144
137
|
}
|
|
145
138
|
|
|
146
|
-
.
|
|
139
|
+
.menu,
|
|
140
|
+
:deep(.VPLocalNavOutlineDropdown > button) {
|
|
147
141
|
padding: 12px 24px 11px;
|
|
148
142
|
}
|
|
149
143
|
|
|
150
144
|
@media (min-width: 768px) {
|
|
151
|
-
.
|
|
145
|
+
.menu,
|
|
146
|
+
:deep(.VPLocalNavOutlineDropdown > button) {
|
|
152
147
|
padding: 12px 32px 11px;
|
|
153
148
|
}
|
|
154
149
|
}
|
|
@@ -92,16 +92,6 @@ function scrollToTop() {
|
|
|
92
92
|
</template>
|
|
93
93
|
|
|
94
94
|
<style scoped>
|
|
95
|
-
.VPLocalNavOutlineDropdown {
|
|
96
|
-
padding: 12px 20px 11px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@media (min-width: 960px) {
|
|
100
|
-
.VPLocalNavOutlineDropdown {
|
|
101
|
-
padding: 12px 36px 11px;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
95
|
.VPLocalNavOutlineDropdown button {
|
|
106
96
|
display: block;
|
|
107
97
|
font-size: 12px;
|
|
@@ -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,
|
|
@@ -170,16 +170,22 @@ watchPostEffect(() => {
|
|
|
170
170
|
.VPNavBar.has-sidebar .content {
|
|
171
171
|
position: relative;
|
|
172
172
|
z-index: 1;
|
|
173
|
-
padding-right: 32px;
|
|
174
173
|
padding-left: var(--vp-sidebar-width);
|
|
175
174
|
}
|
|
175
|
+
|
|
176
|
+
.VPNavBar.has-sidebar .content-body {
|
|
177
|
+
padding-right: 32px;
|
|
178
|
+
}
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
@media (min-width: 1440px) {
|
|
179
182
|
.VPNavBar.has-sidebar .content {
|
|
180
|
-
padding-right: calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);
|
|
181
183
|
padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
|
|
182
184
|
}
|
|
185
|
+
|
|
186
|
+
.VPNavBar.has-sidebar .content-body {
|
|
187
|
+
padding-right: calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);
|
|
188
|
+
}
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
.content-body {
|
|
@@ -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((100vw - (var(--vp-layout-max-width) - 64px)) / 2));
|
|
115
|
+
width: calc((100vw - (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) => {
|
|
@@ -88,6 +88,6 @@
|
|
|
88
88
|
:root {
|
|
89
89
|
/* clipboard */
|
|
90
90
|
--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/g%3E%3C/svg%3E");
|
|
91
|
-
/* clipboard-
|
|
92
|
-
--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='
|
|
91
|
+
/* clipboard-check */
|
|
92
|
+
--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14l2 2l4-4'/%3E%3C/g%3E%3C/svg%3E");
|
|
93
93
|
}
|