vitepress 2.0.0-alpha.16 → 2.0.0-alpha.17

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.
Files changed (38) hide show
  1. package/README.md +11 -0
  2. package/dist/client/app/composables/copyCode.js +1 -1
  3. package/dist/client/app/router.js +21 -10
  4. package/dist/client/shared.js +2 -2
  5. package/dist/client/theme-default/Layout.vue +1 -0
  6. package/dist/client/theme-default/components/VPContent.vue +1 -0
  7. package/dist/client/theme-default/components/VPFeature.vue +9 -2
  8. package/dist/client/theme-default/components/VPHero.vue +6 -0
  9. package/dist/client/theme-default/components/VPHome.vue +1 -0
  10. package/dist/client/theme-default/components/VPHomeHero.vue +1 -0
  11. package/dist/client/theme-default/components/VPMenuLink.vue +11 -8
  12. package/dist/client/theme-default/components/VPNavBarExtra.vue +7 -1
  13. package/dist/client/theme-default/components/VPNavBarMenuGroup.vue +16 -11
  14. package/dist/client/theme-default/components/VPNavBarMenuLink.vue +9 -8
  15. package/dist/client/theme-default/components/VPNavBarTranslations.vue +7 -1
  16. package/dist/client/theme-default/composables/layout.js +1 -0
  17. package/dist/client/theme-default/fonts/inter-italic-cyrillic-ext.woff2 +0 -0
  18. package/dist/client/theme-default/fonts/inter-italic-cyrillic.woff2 +0 -0
  19. package/dist/client/theme-default/fonts/inter-italic-greek-ext.woff2 +0 -0
  20. package/dist/client/theme-default/fonts/inter-italic-greek.woff2 +0 -0
  21. package/dist/client/theme-default/fonts/inter-italic-latin-ext.woff2 +0 -0
  22. package/dist/client/theme-default/fonts/inter-italic-latin.woff2 +0 -0
  23. package/dist/client/theme-default/fonts/inter-italic-vietnamese.woff2 +0 -0
  24. package/dist/client/theme-default/fonts/inter-roman-cyrillic-ext.woff2 +0 -0
  25. package/dist/client/theme-default/fonts/inter-roman-cyrillic.woff2 +0 -0
  26. package/dist/client/theme-default/fonts/inter-roman-greek-ext.woff2 +0 -0
  27. package/dist/client/theme-default/fonts/inter-roman-greek.woff2 +0 -0
  28. package/dist/client/theme-default/fonts/inter-roman-latin-ext.woff2 +0 -0
  29. package/dist/client/theme-default/fonts/inter-roman-latin.woff2 +0 -0
  30. package/dist/client/theme-default/fonts/inter-roman-vietnamese.woff2 +0 -0
  31. package/dist/client/theme-default/styles/base.css +3 -0
  32. package/dist/client/theme-default/styles/components/vp-doc.css +1 -0
  33. package/dist/client/theme-default/styles/fonts.css +163 -39
  34. package/dist/client/theme-default/styles/vars.css +23 -3
  35. package/dist/node/{chunk-CCYAX98b.js → chunk-CpMTk0EA.js} +4399 -11429
  36. package/dist/node/cli.js +7 -12
  37. package/dist/node/index.js +8 -13
  38. package/package.json +15 -15
package/README.md CHANGED
@@ -26,3 +26,14 @@ Please make sure to read the [Contributing Guide](https://github.com/vuejs/vitep
26
26
  [MIT](https://github.com/vuejs/vitepress/blob/main/LICENSE)
27
27
 
28
28
  Copyright (c) 2019-present, Yuxi (Evan) You
29
+
30
+ ## Special Thanks
31
+
32
+ This project would not be possible without the support of these amazing companies and tools.
33
+
34
+ | | | |
35
+ | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
36
+ | <a href="https://voidzero.dev" target="_blank"><img alt="VoidZero's logo" src="https://github.com/voidzero-dev.png" width="80" /></a> | **[VoidZero](https://voidzero.dev)** | The company behind Vite, Vitest, Rolldown, and Oxc. VoidZero has been a long-time sponsor of VitePress. VitePress itself is built on top of this ecosystem of high-performance JavaScript tooling. |
37
+ | <a href="https://stackblitz.com" target="_blank"><img alt="StackBlitz's logo" src="https://github.com/stackblitz.png" width="80" /></a> | **[StackBlitz](https://stackblitz.com)** | Creators of WebContainers and a browser-based development platform. Their technology powers the VitePress playground and provides instant preview releases for our pull requests and commits. |
38
+ | <a href="https://algolia.com" target="_blank"><img alt="Algolia's logo" src="https://github.com/algolia.png" width="80" /></a> | **[Algolia](https://algolia.com)** | An AI-powered search platform that provides fast, scalable search. Algolia powers DocSearch for VitePress. Their team has been a long-time partner in building and maintaining our search integration. |
39
+ | <a href="https://browserstack.com" target="_blank"><img alt="BrowserStack's logo" src="https://github.com/browserstack.png" width="80" /></a> | **[BrowserStack](https://browserstack.com)** | A cloud-based testing platform for websites and mobile apps. BrowserStack provides the cross-browser and real-device infrastructure used to ensure VitePress works consistently across all browsers. |
@@ -41,7 +41,7 @@ export function useCopyCode() {
41
41
  }
42
42
  async function copyToClipboard(text) {
43
43
  try {
44
- return navigator.clipboard.writeText(text);
44
+ await navigator.clipboard.writeText(text);
45
45
  }
46
46
  catch {
47
47
  const element = document.createElement('textarea');
@@ -18,17 +18,25 @@ export function createRouter(loadPageModule, fallbackComponent) {
18
18
  const router = {
19
19
  route,
20
20
  async go(href, options) {
21
+ const { hash } = new URL(href, fakeHost);
22
+ const hasTextFragment = inBrowser && document.fragmentDirective && hash.includes(':~:');
21
23
  href = normalizeHref(href);
22
24
  if ((await router.onBeforeRouteChange?.(href)) === false)
23
25
  return;
24
- if (!inBrowser || (await changeRoute(href, options)))
25
- await loadPage(href);
26
+ if (!inBrowser ||
27
+ (await changeRoute(href, { ...options, hasTextFragment }))) {
28
+ await loadPage(href, { initialLoad: !!options?.initialLoad });
29
+ }
30
+ if (hasTextFragment) {
31
+ // this will create a new history entry, but that's almost unavoidable
32
+ location.hash = hash;
33
+ }
26
34
  syncRouteQueryAndHash();
27
35
  await router.onAfterRouteChange?.(href);
28
36
  }
29
37
  };
30
38
  let latestPendingPath = null;
31
- async function loadPage(href, scrollPosition = 0, isRetry = false) {
39
+ async function loadPage(href, { scrollPosition = 0, isRetry = false, initialLoad = false } = {}) {
32
40
  if ((await router.onBeforePageLoad?.(href)) === false)
33
41
  return;
34
42
  const targetLoc = new URL(href, fakeHost);
@@ -61,7 +69,8 @@ export function createRouter(loadPageModule, fallbackComponent) {
61
69
  href = actualPathname + targetLoc.search + targetLoc.hash;
62
70
  history.replaceState({}, '', href);
63
71
  }
64
- return scrollTo(targetLoc.hash, false, scrollPosition);
72
+ if (!initialLoad)
73
+ scrollTo(targetLoc.hash, false, scrollPosition);
65
74
  });
66
75
  }
67
76
  }
@@ -78,7 +87,7 @@ export function createRouter(loadPageModule, fallbackComponent) {
78
87
  try {
79
88
  const res = await fetch(siteDataRef.value.base + 'hashmap.json');
80
89
  window.__VP_HASH_MAP__ = await res.json();
81
- await loadPage(href, scrollPosition, true);
90
+ await loadPage(href, { scrollPosition, isRetry: true, initialLoad });
82
91
  return;
83
92
  }
84
93
  catch (e) { }
@@ -144,7 +153,7 @@ export function createRouter(loadPageModule, fallbackComponent) {
144
153
  if (e.state === null)
145
154
  return;
146
155
  const href = normalizeHref(location.href);
147
- await loadPage(href, (e.state && e.state.scrollPosition) || 0);
156
+ await loadPage(href, { scrollPosition: e.state.scrollPosition || 0 });
148
157
  syncRouteQueryAndHash();
149
158
  await router.onAfterRouteChange?.(href);
150
159
  });
@@ -242,15 +251,16 @@ function normalizeHref(href) {
242
251
  else if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) {
243
252
  url.pathname += '.html';
244
253
  }
245
- return url.pathname + url.search + url.hash;
254
+ return url.pathname + url.search + url.hash.split(':~:')[0];
246
255
  }
247
- async function changeRoute(href, { smoothScroll = false, initialLoad = false, replace = false } = {}) {
256
+ async function changeRoute(href, { smoothScroll = false, initialLoad = false, replace = false, hasTextFragment = false } = {}) {
248
257
  const loc = normalizeHref(location.href);
249
258
  const nextUrl = new URL(href, location.origin);
250
259
  const currentUrl = new URL(loc, location.origin);
251
260
  if (href === loc) {
252
261
  if (!initialLoad) {
253
- scrollTo(nextUrl.hash, smoothScroll);
262
+ if (!hasTextFragment)
263
+ scrollTo(nextUrl.hash, smoothScroll);
254
264
  return false;
255
265
  }
256
266
  }
@@ -270,7 +280,8 @@ async function changeRoute(href, { smoothScroll = false, initialLoad = false, re
270
280
  oldURL: currentUrl.href,
271
281
  newURL: nextUrl.href
272
282
  }));
273
- scrollTo(nextUrl.hash, smoothScroll);
283
+ if (!hasTextFragment)
284
+ scrollTo(nextUrl.hash, smoothScroll);
274
285
  }
275
286
  return false;
276
287
  }
@@ -2,7 +2,7 @@ export const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
2
2
  export const APPEARANCE_KEY = 'vitepress-theme-appearance';
3
3
  export const VP_SOURCE_KEY = '[VP_SOURCE]';
4
4
  const UnpackStackView = Symbol('stack-view:unpack');
5
- const HASH_RE = /#.*$/;
5
+ const HASH_WITHOUT_FRAGMENT_RE = /#.*?(?=:~:|$)/;
6
6
  const HASH_OR_QUERY_RE = /[?#].*$/;
7
7
  const INDEX_OR_EXT_RE = /(?:(^|\/)index)?\.(?:md|html)$/;
8
8
  export const inBrowser = typeof document !== 'undefined';
@@ -27,7 +27,7 @@ export function isActive(currentPath, matchPath, asRegex = false) {
27
27
  if (normalize(matchPath) !== currentPath) {
28
28
  return false;
29
29
  }
30
- const hashMatch = matchPath.match(HASH_RE);
30
+ const hashMatch = matchPath.match(HASH_WITHOUT_FRAGMENT_RE);
31
31
  if (hashMatch) {
32
32
  return (inBrowser ? location.hash : '') === hashMatch[0];
33
33
  }
@@ -61,6 +61,7 @@ provide(layoutInfoInjectionKey, { heroImageSlotExists })
61
61
  <template #home-hero-info><slot name="home-hero-info" /></template>
62
62
  <template #home-hero-info-after><slot name="home-hero-info-after" /></template>
63
63
  <template #home-hero-actions-after><slot name="home-hero-actions-after" /></template>
64
+ <template #home-hero-actions-before-actions><slot name="home-hero-actions-before-actions" /></template>
64
65
  <template #home-hero-image><slot name="home-hero-image" /></template>
65
66
  <template #home-hero-after><slot name="home-hero-after" /></template>
66
67
  <template #home-features-before><slot name="home-features-before" /></template>
@@ -29,6 +29,7 @@ const { isHome, hasSidebar } = useLayout()
29
29
  <template #home-hero-info><slot name="home-hero-info" /></template>
30
30
  <template #home-hero-info-after><slot name="home-hero-info-after" /></template>
31
31
  <template #home-hero-actions-after><slot name="home-hero-actions-after" /></template>
32
+ <template #home-hero-actions-before-actions><slot name="home-hero-actions-before-actions" /></template>
32
33
  <template #home-hero-image><slot name="home-hero-image" /></template>
33
34
  <template #home-hero-after><slot name="home-hero-after" /></template>
34
35
  <template #home-features-before><slot name="home-features-before" /></template>
@@ -41,8 +41,10 @@ defineProps<{
41
41
  />
42
42
  <div v-else-if="icon" class="icon" v-html="icon"></div>
43
43
  <h2 class="title" v-html="title"></h2>
44
- <p v-if="details" class="details" v-html="details"></p>
45
-
44
+ <ul v-if="Array.isArray(details)" class="details">
45
+ <li v-for="item in details" :key="item" v-html="item"></li>
46
+ </ul>
47
+ <p v-else-if="details" class="details" v-html="details"></p>
46
48
  <div v-if="linkText" class="link-text">
47
49
  <p class="link-text-value">
48
50
  {{ linkText }} <span class="vpi-arrow-right link-text-icon" />
@@ -105,6 +107,11 @@ defineProps<{
105
107
  color: var(--vp-c-text-2);
106
108
  }
107
109
 
110
+ ul.details {
111
+ list-style-type: disc;
112
+ padding-left: 14px;
113
+ }
114
+
108
115
  .link-text {
109
116
  padding-top: 8px;
110
117
  }
@@ -42,6 +42,7 @@ const { heroImageSlotExists } = inject(
42
42
  <slot name="home-hero-info-after" />
43
43
 
44
44
  <div v-if="actions" class="actions">
45
+ <slot name="home-hero-actions-before-actions" />
45
46
  <div v-for="action in actions" :key="action.link" class="action">
46
47
  <VPButton
47
48
  tag="a"
@@ -143,6 +144,11 @@ const { heroImageSlotExists } = inject(
143
144
  font-size: 32px;
144
145
  font-weight: 700;
145
146
  white-space: pre-wrap;
147
+
148
+ &:lang(ja) {
149
+ font-feature-settings: 'palt';
150
+ word-break: auto-phrase;
151
+ }
146
152
  }
147
153
 
148
154
  .VPHero.has-image .name,
@@ -19,6 +19,7 @@ const { frontmatter, theme } = useData()
19
19
  <template #home-hero-info><slot name="home-hero-info" /></template>
20
20
  <template #home-hero-info-after><slot name="home-hero-info-after" /></template>
21
21
  <template #home-hero-actions-after><slot name="home-hero-actions-after" /></template>
22
+ <template #home-hero-actions-before-actions><slot name="home-hero-actions-before-actions" /></template>
22
23
  <template #home-hero-image><slot name="home-hero-image" /></template>
23
24
  </VPHomeHero>
24
25
  <slot name="home-hero-after" />
@@ -19,6 +19,7 @@ const { frontmatter: fm } = useData()
19
19
  <template #home-hero-info><slot name="home-hero-info" /></template>
20
20
  <template #home-hero-info-after><slot name="home-hero-info-after" /></template>
21
21
  <template #home-hero-actions-after><slot name="home-hero-actions-after" /></template>
22
+ <template #home-hero-actions-before-actions><slot name="home-hero-actions-before-actions" /></template>
22
23
  <template #home-hero-image><slot name="home-hero-image" /></template>
23
24
  </VPHero>
24
25
  </template>
@@ -7,6 +7,7 @@ import VPLink from './VPLink.vue'
7
7
 
8
8
  const props = defineProps<{
9
9
  item: T
10
+ rel?: string
10
11
  }>()
11
12
 
12
13
  const { page } = useData()
@@ -17,6 +18,14 @@ const href = computed(() =>
17
18
  : props.item.link
18
19
  )
19
20
 
21
+ const isActiveLink = computed(() =>
22
+ isActive(
23
+ page.value.relativePath,
24
+ props.item.activeMatch || href.value,
25
+ !!props.item.activeMatch
26
+ )
27
+ )
28
+
20
29
  defineOptions({ inheritAttrs: false })
21
30
  </script>
22
31
 
@@ -24,16 +33,10 @@ defineOptions({ inheritAttrs: false })
24
33
  <div class="VPMenuLink">
25
34
  <VPLink
26
35
  v-bind="$attrs"
27
- :class="{
28
- active: isActive(
29
- page.relativePath,
30
- item.activeMatch || href,
31
- !!item.activeMatch
32
- )
33
- }"
36
+ :class="{ active: isActiveLink }"
34
37
  :href
35
38
  :target="item.target"
36
- :rel="item.rel"
39
+ :rel="props.rel ?? item.rel"
37
40
  :no-icon="item.noIcon"
38
41
  >
39
42
  <span v-html="item.text"></span>
@@ -31,7 +31,13 @@ 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" :lang="locale.lang" :dir="locale.dir" />
34
+ <VPMenuLink
35
+ :item="locale"
36
+ :lang="locale.lang"
37
+ :hreflang="locale.lang"
38
+ rel="alternate"
39
+ :dir="locale.dir"
40
+ />
35
41
  </template>
36
42
  </div>
37
43
 
@@ -11,31 +11,36 @@ const props = defineProps<{
11
11
 
12
12
  const { page } = useData()
13
13
 
14
- const isChildActive = (navItem: DefaultTheme.NavItem) => {
14
+ const isActiveGroup = computed(() => {
15
+ if (props.item.activeMatch) {
16
+ return isActive(page.value.relativePath, props.item.activeMatch, true)
17
+ }
18
+ return isChildActive(props.item)
19
+ })
20
+
21
+ function isChildActive(navItem: DefaultTheme.NavItem): boolean {
15
22
  if ('component' in navItem) return false
16
23
 
17
24
  if ('link' in navItem) {
25
+ const href =
26
+ typeof navItem.link === 'function'
27
+ ? navItem.link(page.value)
28
+ : navItem.link
29
+
18
30
  return isActive(
19
31
  page.value.relativePath,
20
- typeof navItem.link === "function" ? navItem.link(page.value) : navItem.link,
21
- !!props.item.activeMatch
32
+ navItem.activeMatch || href,
33
+ !!navItem.activeMatch
22
34
  )
23
35
  }
24
36
 
25
37
  return navItem.items.some(isChildActive)
26
38
  }
27
-
28
- const childrenActive = computed(() => isChildActive(props.item))
29
39
  </script>
30
40
 
31
41
  <template>
32
42
  <VPFlyout
33
- :class="{
34
- VPNavBarMenuGroup: true,
35
- active:
36
- isActive(page.relativePath, item.activeMatch, !!item.activeMatch) ||
37
- childrenActive
38
- }"
43
+ :class="{ VPNavBarMenuGroup: true, active: isActiveGroup }"
39
44
  :button="item.text"
40
45
  :items="item.items"
41
46
  />
@@ -16,18 +16,19 @@ const href = computed(() =>
16
16
  ? props.item.link(page.value)
17
17
  : props.item.link
18
18
  )
19
+
20
+ const isActiveLink = computed(() =>
21
+ isActive(
22
+ page.value.relativePath,
23
+ props.item.activeMatch || href.value,
24
+ !!props.item.activeMatch
25
+ )
26
+ )
19
27
  </script>
20
28
 
21
29
  <template>
22
30
  <VPLink
23
- :class="{
24
- VPNavBarMenuLink: true,
25
- active: isActive(
26
- page.relativePath,
27
- item.activeMatch || href,
28
- !!item.activeMatch
29
- )
30
- }"
31
+ :class="{ VPNavBarMenuLink: true, active: isActiveLink }"
31
32
  :href
32
33
  :target="item.target"
33
34
  :rel="item.rel"
@@ -19,7 +19,13 @@ 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" :lang="locale.lang" :dir="locale.dir" />
22
+ <VPMenuLink
23
+ :item="locale"
24
+ :lang="locale.lang"
25
+ :hreflang="locale.lang"
26
+ rel="alternate"
27
+ :dir="locale.dir"
28
+ />
23
29
  </template>
24
30
  </div>
25
31
  </VPFlyout>
@@ -71,6 +71,7 @@ export function registerWatchers({ closeSidebar }) {
71
71
  }
72
72
  const route = useRoute();
73
73
  watch(() => route.path, closeSidebar);
74
+ watch(is960, closeSidebar);
74
75
  useCloseSidebarOnEscape(closeSidebar);
75
76
  }
76
77
  export const layoutInfoInjectionKey = Symbol('layout-info');
@@ -44,6 +44,8 @@
44
44
  text-rendering: optimizeLegibility;
45
45
  -webkit-font-smoothing: antialiased;
46
46
  -moz-osx-font-smoothing: grayscale;
47
+ text-autospace: normal;
48
+ text-spacing-trim: normal;
47
49
  }
48
50
 
49
51
  main {
@@ -119,6 +121,7 @@
119
121
  kbd,
120
122
  samp {
121
123
  font-family: var(--vp-font-family-mono);
124
+ text-autospace: no-autospace;
122
125
  }
123
126
 
124
127
  img,
@@ -92,6 +92,7 @@
92
92
  * -------------------------------------------------------------------------- */
93
93
 
94
94
  .vp-doc p,
95
+ .vp-doc img,
95
96
  .vp-doc summary {
96
97
  margin: 16px 0;
97
98
  }