vitepress 1.0.0-alpha.9 → 1.0.0-beta.2
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/README.md +4 -3
- package/dist/client/app/components/ClientOnly.js +10 -10
- package/dist/client/app/components/Content.js +21 -11
- package/dist/client/app/composables/codeGroups.js +19 -0
- package/dist/client/{theme-default/composables/copy-code.js → app/composables/copyCode.js} +72 -71
- package/dist/client/app/composables/head.js +51 -51
- package/dist/client/app/composables/preFetch.js +99 -94
- package/dist/client/app/data.js +42 -44
- package/dist/client/app/devtools.js +28 -28
- package/dist/client/app/index.js +130 -92
- package/dist/client/app/router.js +248 -200
- package/dist/client/app/ssr.js +10 -9
- package/dist/client/app/theme.js +1 -1
- package/dist/client/app/utils.js +80 -47
- package/dist/client/index.d.ts +87 -116
- package/dist/client/index.js +9 -9
- package/dist/client/shared.js +111 -109
- package/dist/client/theme-default/Layout.vue +26 -4
- package/dist/client/theme-default/NotFound.vue +20 -4
- package/dist/client/theme-default/components/VPAlgoliaSearchBox.vue +32 -25
- package/dist/client/theme-default/components/VPBackdrop.vue +3 -1
- package/dist/client/theme-default/components/VPBadge.vue +64 -0
- package/dist/client/theme-default/components/VPButton.vue +3 -3
- package/dist/client/theme-default/components/VPCarbonAds.vue +31 -20
- package/dist/client/theme-default/components/VPContent.vue +20 -14
- package/dist/client/theme-default/components/VPDoc.vue +31 -10
- package/dist/client/theme-default/components/VPDocAside.vue +4 -4
- package/dist/client/theme-default/components/VPDocAsideCarbonAds.vue +6 -1
- package/dist/client/theme-default/components/VPDocAsideOutline.vue +21 -68
- package/dist/client/theme-default/components/VPDocFooter.vue +17 -19
- package/dist/client/theme-default/components/VPDocFooterLastUpdated.vue +7 -8
- package/dist/client/theme-default/components/VPDocOutlineDropdown.vue +84 -0
- package/dist/client/theme-default/components/VPDocOutlineItem.vue +59 -0
- package/dist/client/theme-default/components/VPFeature.vue +72 -13
- package/dist/client/theme-default/components/VPFeatures.vue +13 -3
- package/dist/client/theme-default/components/VPFlyout.vue +4 -22
- package/dist/client/theme-default/components/VPFooter.vue +3 -6
- package/dist/client/theme-default/components/VPHero.vue +28 -13
- package/dist/client/theme-default/components/VPHome.vue +4 -1
- package/dist/client/theme-default/components/VPHomeFeatures.vue +1 -1
- package/dist/client/theme-default/components/VPHomeHero.vue +5 -2
- package/dist/client/theme-default/components/VPHomeSponsors.vue +1 -1
- package/dist/client/theme-default/components/VPImage.vue +14 -2
- package/dist/client/theme-default/components/VPLink.vue +10 -5
- package/dist/client/theme-default/components/VPLocalNav.vue +50 -25
- package/dist/client/theme-default/components/VPLocalNavOutlineDropdown.vue +147 -0
- package/dist/client/theme-default/components/VPLocalSearchBox.vue +904 -0
- package/dist/client/theme-default/components/VPMenu.vue +5 -15
- package/dist/client/theme-default/components/VPMenuGroup.vue +3 -2
- package/dist/client/theme-default/components/VPMenuLink.vue +10 -11
- package/dist/client/theme-default/components/VPNav.vue +5 -25
- package/dist/client/theme-default/components/VPNavBar.vue +136 -48
- package/dist/client/theme-default/components/VPNavBarAppearance.vue +1 -1
- package/dist/client/theme-default/components/VPNavBarExtra.vue +18 -6
- package/dist/client/theme-default/components/VPNavBarMenu.vue +1 -1
- package/dist/client/theme-default/components/VPNavBarMenuGroup.vue +2 -2
- package/dist/client/theme-default/components/VPNavBarMenuLink.vue +6 -10
- package/dist/client/theme-default/components/VPNavBarSearch.vue +139 -210
- package/dist/client/theme-default/components/VPNavBarSearchButton.vue +207 -0
- package/dist/client/theme-default/components/VPNavBarSocialLinks.vue +1 -1
- package/dist/client/theme-default/components/VPNavBarTitle.vue +12 -22
- package/dist/client/theme-default/components/VPNavBarTranslations.vue +7 -4
- package/dist/client/theme-default/components/VPNavScreen.vue +5 -3
- package/dist/client/theme-default/components/VPNavScreenAppearance.vue +5 -5
- package/dist/client/theme-default/components/VPNavScreenMenu.vue +2 -3
- package/dist/client/theme-default/components/VPNavScreenMenuGroup.vue +3 -5
- package/dist/client/theme-default/components/VPNavScreenMenuGroupLink.vue +12 -6
- package/dist/client/theme-default/components/VPNavScreenMenuGroupSection.vue +1 -2
- package/dist/client/theme-default/components/VPNavScreenMenuLink.vue +12 -6
- package/dist/client/theme-default/components/VPNavScreenSocialLinks.vue +1 -1
- package/dist/client/theme-default/components/VPNavScreenTranslations.vue +11 -7
- package/dist/client/theme-default/components/VPPage.vue +2 -0
- package/dist/client/theme-default/components/VPSidebar.vue +45 -23
- package/dist/client/theme-default/components/VPSidebarItem.vue +230 -0
- package/dist/client/theme-default/components/VPSkipLink.vue +1 -5
- package/dist/client/theme-default/components/VPSocialLink.vue +3 -1
- package/dist/client/theme-default/components/VPSocialLinks.vue +2 -2
- package/dist/client/theme-default/components/VPSponsors.vue +1 -1
- package/dist/client/theme-default/components/VPSponsorsGrid.vue +2 -2
- package/dist/client/theme-default/components/VPSwitch.vue +7 -10
- package/dist/client/theme-default/components/VPSwitchAppearance.vue +43 -7
- package/dist/client/theme-default/components/VPTeamMembersItem.vue +11 -6
- package/dist/client/theme-default/components/VPTeamPageSection.vue +1 -1
- package/dist/client/theme-default/composables/aside.js +17 -17
- package/dist/client/theme-default/composables/data.js +2 -0
- package/dist/client/theme-default/composables/edit-link.js +16 -11
- package/dist/client/theme-default/composables/flyout.js +41 -40
- package/dist/client/theme-default/composables/langs.js +26 -0
- package/dist/client/theme-default/composables/nav.js +30 -53
- package/dist/client/theme-default/composables/outline.js +155 -121
- package/dist/client/theme-default/composables/prev-next.js +44 -22
- package/dist/client/theme-default/composables/sidebar.js +130 -63
- package/dist/client/theme-default/composables/sponsor-grid.js +94 -94
- package/dist/client/theme-default/index.js +3 -23
- package/dist/client/theme-default/styles/base.css +18 -4
- package/dist/client/theme-default/styles/components/custom-block.css +10 -5
- package/dist/client/theme-default/styles/components/vp-code-group.css +87 -0
- package/dist/client/theme-default/styles/components/vp-doc.css +107 -28
- package/dist/client/theme-default/styles/components/vp-sponsor.css +3 -3
- package/dist/client/theme-default/styles/fonts.css +13 -65
- package/dist/client/theme-default/styles/vars.css +261 -173
- package/dist/client/theme-default/support/sidebar.js +73 -37
- package/dist/client/theme-default/support/socialIcons.js +12 -11
- package/dist/client/theme-default/support/translation.js +48 -0
- package/dist/client/theme-default/support/utils.js +36 -63
- package/dist/client/theme-default/without-fonts.js +28 -0
- package/dist/node/cli.js +394 -267
- package/dist/node/index.d.ts +2004 -372
- package/dist/node/index.js +91 -12
- package/dist/node/{serve-dfb48091.js → serve-9050e258.js} +51782 -52505
- package/dist/node-cjs/cli.cjs +395 -268
- package/dist/node-cjs/index.cjs +105 -24
- package/dist/node-cjs/{serve-865d0baf.cjs → serve-1a76c42b.cjs} +51615 -52347
- package/package.json +89 -69
- package/template/.vitepress/config.js +28 -0
- package/template/.vitepress/theme/Layout.vue +21 -0
- package/template/.vitepress/theme/index.js +25 -0
- package/template/.vitepress/theme/style.css +95 -0
- package/template/api-examples.md +49 -0
- package/template/index.md +28 -0
- package/template/markdown-examples.md +85 -0
- package/theme-without-fonts.d.ts +1 -0
- package/theme.d.ts +14 -11
- package/types/default-theme.d.ts +120 -46
- package/types/docsearch.d.ts +143 -0
- package/types/index.d.ts +2 -34
- package/types/local-search.d.ts +27 -0
- package/types/shared.d.ts +52 -46
- package/dist/client/theme-default/components/VPSidebarGroup.vue +0 -124
- package/dist/client/theme-default/components/VPSidebarLink.vue +0 -69
- package/dist/client/theme-default/fonts/inter-cyrillic-ext.woff2 +0 -0
- package/dist/client/theme-default/fonts/inter-cyrillic.woff2 +0 -0
- package/dist/client/theme-default/fonts/inter-greek-ext.woff2 +0 -0
- package/dist/client/theme-default/fonts/inter-greek.woff2 +0 -0
- package/dist/client/theme-default/fonts/inter-latin-ext.woff2 +0 -0
- package/dist/client/theme-default/fonts/inter-latin.woff2 +0 -0
- package/dist/client/theme-default/fonts/inter-vietnamese.woff2 +0 -0
package/README.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
# VitePress (
|
|
1
|
+
# VitePress (beta) 📝💨
|
|
2
2
|
|
|
3
3
|
[](https://github.com/vuejs/vitepress/actions)
|
|
4
4
|
[](https://www.npmjs.com/package/vitepress)
|
|
5
|
+
[](https://chat.vuejs.org)
|
|
5
6
|
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
VitePress is [VuePress](https://vuepress.vuejs.org)' spiritual successor, built on top of [vite](https://github.com/vitejs/vite).
|
|
9
10
|
|
|
10
|
-
Currently, it
|
|
11
|
+
Currently, it is in the `beta` stage. It is already suitable for out-of-the-box documentation use. There still might be issues, however, we do not plan to introduce any breaking changes from here on until the stable release.
|
|
11
12
|
|
|
12
13
|
## Documentation
|
|
13
14
|
|
|
14
|
-
To check out docs, visit [vitepress.
|
|
15
|
+
To check out docs, visit [vitepress.dev](https://vitepress.dev).
|
|
15
16
|
|
|
16
17
|
## Changelog
|
|
17
18
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineComponent, ref, onMounted } from 'vue';
|
|
2
|
-
export const ClientOnly = defineComponent({
|
|
3
|
-
setup(_, { slots }) {
|
|
4
|
-
const show = ref(false);
|
|
5
|
-
onMounted(() => {
|
|
6
|
-
show.value = true;
|
|
7
|
-
});
|
|
8
|
-
return () => (show.value && slots.default ? slots.default() : null);
|
|
9
|
-
}
|
|
10
|
-
});
|
|
1
|
+
import { defineComponent, ref, onMounted } from 'vue';
|
|
2
|
+
export const ClientOnly = defineComponent({
|
|
3
|
+
setup(_, { slots }) {
|
|
4
|
+
const show = ref(false);
|
|
5
|
+
onMounted(() => {
|
|
6
|
+
show.value = true;
|
|
7
|
+
});
|
|
8
|
+
return () => (show.value && slots.default ? slots.default() : null);
|
|
9
|
+
}
|
|
10
|
+
});
|
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
import { defineComponent, h } from 'vue';
|
|
2
|
-
import { useRoute } from '../router
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { defineComponent, h } from 'vue';
|
|
2
|
+
import { useRoute } from '../router';
|
|
3
|
+
import { contentUpdatedCallbacks } from '../utils';
|
|
4
|
+
const runCbs = () => contentUpdatedCallbacks.forEach((fn) => fn());
|
|
5
|
+
export const Content = defineComponent({
|
|
6
|
+
name: 'VitePressContent',
|
|
7
|
+
props: {
|
|
8
|
+
as: { type: [Object, String], default: 'div' }
|
|
9
|
+
},
|
|
10
|
+
setup(props) {
|
|
11
|
+
const route = useRoute();
|
|
12
|
+
return () => h(props.as, { style: { position: 'relative' } }, [
|
|
13
|
+
route.component
|
|
14
|
+
? h(route.component, {
|
|
15
|
+
onVnodeMounted: runCbs,
|
|
16
|
+
onVnodeUpdated: runCbs
|
|
17
|
+
})
|
|
18
|
+
: '404 Page Not Found'
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { inBrowser } from 'vitepress';
|
|
2
|
+
export function useCodeGroups() {
|
|
3
|
+
if (inBrowser) {
|
|
4
|
+
window.addEventListener('click', (e) => {
|
|
5
|
+
const el = e.target;
|
|
6
|
+
if (el.matches('.vp-code-group input')) {
|
|
7
|
+
// input <- .tabs <- .vp-code-group
|
|
8
|
+
const group = el.parentElement?.parentElement;
|
|
9
|
+
const i = Array.from(group?.querySelectorAll('input') || []).indexOf(el);
|
|
10
|
+
const current = group?.querySelector('div[class*="language-"].active');
|
|
11
|
+
const next = group?.querySelectorAll('div[class*="language-"]:not(.language-id)')?.[i];
|
|
12
|
+
if (current && next && current !== next) {
|
|
13
|
+
current.classList.remove('active');
|
|
14
|
+
next.classList.add('active');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,71 +1,72 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
1
|
+
import { inBrowser } from 'vitepress';
|
|
2
|
+
export function useCopyCode() {
|
|
3
|
+
if (inBrowser) {
|
|
4
|
+
const timeoutIdMap = new Map();
|
|
5
|
+
window.addEventListener('click', (e) => {
|
|
6
|
+
const el = e.target;
|
|
7
|
+
if (el.matches('div[class*="language-"] > button.copy')) {
|
|
8
|
+
const parent = el.parentElement;
|
|
9
|
+
const sibling = el.nextElementSibling
|
|
10
|
+
?.nextElementSibling;
|
|
11
|
+
if (!parent || !sibling) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const isShell = /language-(shellscript|shell|bash|sh|zsh)/.test(parent.className);
|
|
15
|
+
let text = '';
|
|
16
|
+
sibling
|
|
17
|
+
.querySelectorAll('span.line:not(.diff.remove)')
|
|
18
|
+
.forEach((node) => (text += (node.textContent || '') + '\n'));
|
|
19
|
+
text = text.slice(0, -1);
|
|
20
|
+
if (isShell) {
|
|
21
|
+
text = text.replace(/^ *(\$|>) /gm, '').trim();
|
|
22
|
+
}
|
|
23
|
+
copyToClipboard(text).then(() => {
|
|
24
|
+
el.classList.add('copied');
|
|
25
|
+
clearTimeout(timeoutIdMap.get(el));
|
|
26
|
+
const timeoutId = setTimeout(() => {
|
|
27
|
+
el.classList.remove('copied');
|
|
28
|
+
el.blur();
|
|
29
|
+
timeoutIdMap.delete(el);
|
|
30
|
+
}, 2000);
|
|
31
|
+
timeoutIdMap.set(el, timeoutId);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function copyToClipboard(text) {
|
|
38
|
+
try {
|
|
39
|
+
return navigator.clipboard.writeText(text);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
const element = document.createElement('textarea');
|
|
43
|
+
const previouslyFocusedElement = document.activeElement;
|
|
44
|
+
element.value = text;
|
|
45
|
+
// Prevent keyboard from showing on mobile
|
|
46
|
+
element.setAttribute('readonly', '');
|
|
47
|
+
element.style.contain = 'strict';
|
|
48
|
+
element.style.position = 'absolute';
|
|
49
|
+
element.style.left = '-9999px';
|
|
50
|
+
element.style.fontSize = '12pt'; // Prevent zooming on iOS
|
|
51
|
+
const selection = document.getSelection();
|
|
52
|
+
const originalRange = selection
|
|
53
|
+
? selection.rangeCount > 0 && selection.getRangeAt(0)
|
|
54
|
+
: null;
|
|
55
|
+
document.body.appendChild(element);
|
|
56
|
+
element.select();
|
|
57
|
+
// Explicit selection workaround for iOS
|
|
58
|
+
element.selectionStart = 0;
|
|
59
|
+
element.selectionEnd = text.length;
|
|
60
|
+
document.execCommand('copy');
|
|
61
|
+
document.body.removeChild(element);
|
|
62
|
+
if (originalRange) {
|
|
63
|
+
selection.removeAllRanges(); // originalRange can't be truthy when selection is falsy
|
|
64
|
+
selection.addRange(originalRange);
|
|
65
|
+
}
|
|
66
|
+
// Get the focus back on the previously focused element, if any
|
|
67
|
+
if (previouslyFocusedElement) {
|
|
68
|
+
;
|
|
69
|
+
previouslyFocusedElement.focus();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
import { watchEffect } from 'vue';
|
|
2
|
-
import { createTitle, mergeHead } from '../../shared
|
|
3
|
-
export function useUpdateHead(route, siteDataByRouteRef) {
|
|
4
|
-
let managedHeadTags = [];
|
|
5
|
-
let isFirstUpdate = true;
|
|
6
|
-
const updateHeadTags = (newTags) => {
|
|
7
|
-
if (import.meta.env.PROD && isFirstUpdate) {
|
|
8
|
-
// in production, the initial meta tags are already pre-rendered so we
|
|
9
|
-
// skip the first update.
|
|
10
|
-
isFirstUpdate = false;
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
managedHeadTags.forEach((el) => document.head.removeChild(el));
|
|
14
|
-
managedHeadTags = [];
|
|
15
|
-
newTags.forEach((headConfig) => {
|
|
16
|
-
const el = createHeadElement(headConfig);
|
|
17
|
-
document.head.appendChild(el);
|
|
18
|
-
managedHeadTags.push(el);
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
watchEffect(() => {
|
|
22
|
-
const pageData = route.data;
|
|
23
|
-
const siteData = siteDataByRouteRef.value;
|
|
24
|
-
const pageDescription = pageData && pageData.description;
|
|
25
|
-
const frontmatterHead = (pageData && pageData.frontmatter.head) || [];
|
|
26
|
-
// update title and description
|
|
27
|
-
document.title = createTitle(siteData, pageData);
|
|
28
|
-
document
|
|
29
|
-
.querySelector(`meta[name=description]`)
|
|
30
|
-
.setAttribute('content', pageDescription || siteData.description);
|
|
31
|
-
updateHeadTags(mergeHead(siteData.head, filterOutHeadDescription(frontmatterHead)));
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
function createHeadElement([tag, attrs, innerHTML]) {
|
|
35
|
-
const el = document.createElement(tag);
|
|
36
|
-
for (const key in attrs) {
|
|
37
|
-
el.setAttribute(key, attrs[key]);
|
|
38
|
-
}
|
|
39
|
-
if (innerHTML) {
|
|
40
|
-
el.innerHTML = innerHTML;
|
|
41
|
-
}
|
|
42
|
-
return el;
|
|
43
|
-
}
|
|
44
|
-
function isMetaDescription(headConfig) {
|
|
45
|
-
return (headConfig[0] === 'meta' &&
|
|
46
|
-
headConfig[1] &&
|
|
47
|
-
headConfig[1].name === 'description');
|
|
48
|
-
}
|
|
49
|
-
function filterOutHeadDescription(head) {
|
|
50
|
-
return head.filter((h) => !isMetaDescription(h));
|
|
51
|
-
}
|
|
1
|
+
import { watchEffect } from 'vue';
|
|
2
|
+
import { createTitle, mergeHead } from '../../shared';
|
|
3
|
+
export function useUpdateHead(route, siteDataByRouteRef) {
|
|
4
|
+
let managedHeadTags = [];
|
|
5
|
+
let isFirstUpdate = true;
|
|
6
|
+
const updateHeadTags = (newTags) => {
|
|
7
|
+
if (import.meta.env.PROD && isFirstUpdate) {
|
|
8
|
+
// in production, the initial meta tags are already pre-rendered so we
|
|
9
|
+
// skip the first update.
|
|
10
|
+
isFirstUpdate = false;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
managedHeadTags.forEach((el) => document.head.removeChild(el));
|
|
14
|
+
managedHeadTags = [];
|
|
15
|
+
newTags.forEach((headConfig) => {
|
|
16
|
+
const el = createHeadElement(headConfig);
|
|
17
|
+
document.head.appendChild(el);
|
|
18
|
+
managedHeadTags.push(el);
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
watchEffect(() => {
|
|
22
|
+
const pageData = route.data;
|
|
23
|
+
const siteData = siteDataByRouteRef.value;
|
|
24
|
+
const pageDescription = pageData && pageData.description;
|
|
25
|
+
const frontmatterHead = (pageData && pageData.frontmatter.head) || [];
|
|
26
|
+
// update title and description
|
|
27
|
+
document.title = createTitle(siteData, pageData);
|
|
28
|
+
document
|
|
29
|
+
.querySelector(`meta[name=description]`)
|
|
30
|
+
.setAttribute('content', pageDescription || siteData.description);
|
|
31
|
+
updateHeadTags(mergeHead(siteData.head, filterOutHeadDescription(frontmatterHead)));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function createHeadElement([tag, attrs, innerHTML]) {
|
|
35
|
+
const el = document.createElement(tag);
|
|
36
|
+
for (const key in attrs) {
|
|
37
|
+
el.setAttribute(key, attrs[key]);
|
|
38
|
+
}
|
|
39
|
+
if (innerHTML) {
|
|
40
|
+
el.innerHTML = innerHTML;
|
|
41
|
+
}
|
|
42
|
+
return el;
|
|
43
|
+
}
|
|
44
|
+
function isMetaDescription(headConfig) {
|
|
45
|
+
return (headConfig[0] === 'meta' &&
|
|
46
|
+
headConfig[1] &&
|
|
47
|
+
headConfig[1].name === 'description');
|
|
48
|
+
}
|
|
49
|
+
function filterOutHeadDescription(head) {
|
|
50
|
+
return head.filter((h) => !isMetaDescription(h));
|
|
51
|
+
}
|
|
@@ -1,94 +1,99 @@
|
|
|
1
|
-
// Customized pre-fetch for page chunks based on
|
|
2
|
-
// https://github.com/GoogleChromeLabs/quicklink
|
|
3
|
-
import { useRoute } from '../router
|
|
4
|
-
import { onMounted, onUnmounted, watch } from 'vue';
|
|
5
|
-
import { inBrowser, pathToFile } from '../utils
|
|
6
|
-
const hasFetched = new Set();
|
|
7
|
-
const createLink = () => document.createElement('link');
|
|
8
|
-
const viaDOM = (url) => {
|
|
9
|
-
const link = createLink();
|
|
10
|
-
link.rel = `prefetch`;
|
|
11
|
-
link.href = url;
|
|
12
|
-
document.head.appendChild(link);
|
|
13
|
-
};
|
|
14
|
-
const viaXHR = (url) => {
|
|
15
|
-
const req = new XMLHttpRequest();
|
|
16
|
-
req.open('GET', url, (req.withCredentials = true));
|
|
17
|
-
req.send();
|
|
18
|
-
};
|
|
19
|
-
let link;
|
|
20
|
-
const doFetch = inBrowser &&
|
|
21
|
-
(link = createLink()) &&
|
|
22
|
-
link.relList &&
|
|
23
|
-
link.relList.supports &&
|
|
24
|
-
link.relList.supports('prefetch')
|
|
25
|
-
? viaDOM
|
|
26
|
-
: viaXHR;
|
|
27
|
-
export function usePrefetch() {
|
|
28
|
-
if (!inBrowser) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (!window.IntersectionObserver) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
let conn;
|
|
35
|
-
if ((conn = navigator.connection) &&
|
|
36
|
-
(conn.saveData || /2g/.test(conn.effectiveType))) {
|
|
37
|
-
// Don't prefetch if using 2G or if Save-Data is enabled.
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const rIC = window.requestIdleCallback || setTimeout;
|
|
41
|
-
let observer = null;
|
|
42
|
-
const observeLinks = () => {
|
|
43
|
-
if (observer) {
|
|
44
|
-
observer.disconnect();
|
|
45
|
-
}
|
|
46
|
-
observer = new IntersectionObserver((entries) => {
|
|
47
|
-
entries.forEach((entry) => {
|
|
48
|
-
if (entry.isIntersecting) {
|
|
49
|
-
const link = entry.target;
|
|
50
|
-
observer.unobserve(link);
|
|
51
|
-
const { pathname } = link;
|
|
52
|
-
if (!hasFetched.has(pathname)) {
|
|
53
|
-
hasFetched.add(pathname);
|
|
54
|
-
const pageChunkPath = pathToFile(pathname);
|
|
55
|
-
doFetch(pageChunkPath);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
rIC(() => {
|
|
61
|
-
document
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
// Customized pre-fetch for page chunks based on
|
|
2
|
+
// https://github.com/GoogleChromeLabs/quicklink
|
|
3
|
+
import { useRoute } from '../router';
|
|
4
|
+
import { onMounted, onUnmounted, watch } from 'vue';
|
|
5
|
+
import { inBrowser, pathToFile } from '../utils';
|
|
6
|
+
const hasFetched = new Set();
|
|
7
|
+
const createLink = () => document.createElement('link');
|
|
8
|
+
const viaDOM = (url) => {
|
|
9
|
+
const link = createLink();
|
|
10
|
+
link.rel = `prefetch`;
|
|
11
|
+
link.href = url;
|
|
12
|
+
document.head.appendChild(link);
|
|
13
|
+
};
|
|
14
|
+
const viaXHR = (url) => {
|
|
15
|
+
const req = new XMLHttpRequest();
|
|
16
|
+
req.open('GET', url, (req.withCredentials = true));
|
|
17
|
+
req.send();
|
|
18
|
+
};
|
|
19
|
+
let link;
|
|
20
|
+
const doFetch = inBrowser &&
|
|
21
|
+
(link = createLink()) &&
|
|
22
|
+
link.relList &&
|
|
23
|
+
link.relList.supports &&
|
|
24
|
+
link.relList.supports('prefetch')
|
|
25
|
+
? viaDOM
|
|
26
|
+
: viaXHR;
|
|
27
|
+
export function usePrefetch() {
|
|
28
|
+
if (!inBrowser) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!window.IntersectionObserver) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
let conn;
|
|
35
|
+
if ((conn = navigator.connection) &&
|
|
36
|
+
(conn.saveData || /2g/.test(conn.effectiveType))) {
|
|
37
|
+
// Don't prefetch if using 2G or if Save-Data is enabled.
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const rIC = window.requestIdleCallback || setTimeout;
|
|
41
|
+
let observer = null;
|
|
42
|
+
const observeLinks = () => {
|
|
43
|
+
if (observer) {
|
|
44
|
+
observer.disconnect();
|
|
45
|
+
}
|
|
46
|
+
observer = new IntersectionObserver((entries) => {
|
|
47
|
+
entries.forEach((entry) => {
|
|
48
|
+
if (entry.isIntersecting) {
|
|
49
|
+
const link = entry.target;
|
|
50
|
+
observer.unobserve(link);
|
|
51
|
+
const { pathname } = link;
|
|
52
|
+
if (!hasFetched.has(pathname)) {
|
|
53
|
+
hasFetched.add(pathname);
|
|
54
|
+
const pageChunkPath = pathToFile(pathname);
|
|
55
|
+
doFetch(pageChunkPath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
rIC(() => {
|
|
61
|
+
document
|
|
62
|
+
.querySelectorAll('#app a')
|
|
63
|
+
.forEach((link) => {
|
|
64
|
+
const { target } = link;
|
|
65
|
+
const { hostname, pathname } = new URL(link.href instanceof SVGAnimatedString
|
|
66
|
+
? link.href.animVal
|
|
67
|
+
: link.href, link.baseURI);
|
|
68
|
+
const extMatch = pathname.match(/\.\w+$/);
|
|
69
|
+
if (extMatch && extMatch[0] !== '.html') {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (
|
|
73
|
+
// only prefetch same tab navigation, since a new tab will load
|
|
74
|
+
// the lean js chunk instead.
|
|
75
|
+
target !== `_blank` &&
|
|
76
|
+
// only prefetch inbound links
|
|
77
|
+
hostname === location.hostname) {
|
|
78
|
+
if (pathname !== location.pathname) {
|
|
79
|
+
observer.observe(link);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// No need to prefetch chunk for the current page, but also mark
|
|
83
|
+
// it as already fetched. This is because the initial page uses its
|
|
84
|
+
// lean chunk, and if we don't mark it, navigation to another page
|
|
85
|
+
// with a link back to the first page will fetch its full chunk
|
|
86
|
+
// which isn't needed.
|
|
87
|
+
hasFetched.add(pathname);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
onMounted(observeLinks);
|
|
94
|
+
const route = useRoute();
|
|
95
|
+
watch(() => route.path, observeLinks);
|
|
96
|
+
onUnmounted(() => {
|
|
97
|
+
observer && observer.disconnect();
|
|
98
|
+
});
|
|
99
|
+
}
|
package/dist/client/app/data.js
CHANGED
|
@@ -1,44 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import siteData from '@siteData';
|
|
3
|
-
import { resolveSiteDataByRoute, createTitle } from '../shared
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
site,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
lang: computed(() => site.value.lang),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return
|
|
29
|
-
}),
|
|
30
|
-
|
|
31
|
-
return
|
|
32
|
-
}),
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return data;
|
|
44
|
-
}
|
|
1
|
+
import { computed, inject, readonly, ref, shallowRef } from 'vue';
|
|
2
|
+
import siteData from '@siteData';
|
|
3
|
+
import { resolveSiteDataByRoute, createTitle } from '../shared';
|
|
4
|
+
export const dataSymbol = Symbol();
|
|
5
|
+
// site data is a singleton
|
|
6
|
+
export const siteDataRef = shallowRef((import.meta.env.PROD ? siteData : readonly(siteData)));
|
|
7
|
+
// hmr
|
|
8
|
+
if (import.meta.hot) {
|
|
9
|
+
import.meta.hot.accept('/@siteData', (m) => {
|
|
10
|
+
if (m) {
|
|
11
|
+
siteDataRef.value = m.default;
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
// per-app data
|
|
16
|
+
export function initData(route) {
|
|
17
|
+
const site = computed(() => resolveSiteDataByRoute(siteDataRef.value, route.data.relativePath));
|
|
18
|
+
return {
|
|
19
|
+
site,
|
|
20
|
+
theme: computed(() => site.value.themeConfig),
|
|
21
|
+
page: computed(() => route.data),
|
|
22
|
+
frontmatter: computed(() => route.data.frontmatter),
|
|
23
|
+
params: computed(() => route.data.params),
|
|
24
|
+
lang: computed(() => site.value.lang),
|
|
25
|
+
dir: computed(() => site.value.dir),
|
|
26
|
+
localeIndex: computed(() => site.value.localeIndex || 'root'),
|
|
27
|
+
title: computed(() => {
|
|
28
|
+
return createTitle(site.value, route.data);
|
|
29
|
+
}),
|
|
30
|
+
description: computed(() => {
|
|
31
|
+
return route.data.description || site.value.description;
|
|
32
|
+
}),
|
|
33
|
+
isDark: ref(false)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function useData() {
|
|
37
|
+
const data = inject(dataSymbol);
|
|
38
|
+
if (!data) {
|
|
39
|
+
throw new Error('vitepress data not properly injected in app');
|
|
40
|
+
}
|
|
41
|
+
return data;
|
|
42
|
+
}
|