vitepress 2.0.0-alpha.17 → 2.0.0-alpha.18

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 (50) hide show
  1. package/dist/client/app/index.js +1 -1
  2. package/dist/client/app/router.js +8 -21
  3. package/dist/client/app/utils.js +0 -34
  4. package/dist/client/index.d.ts +160 -41
  5. package/dist/client/index.js +1 -1
  6. package/dist/client/shared.js +1 -1
  7. package/dist/client/theme-default/components/VPAlgoliaSearchBox.vue +8 -9
  8. package/dist/client/theme-default/components/VPButton.vue +1 -1
  9. package/dist/client/theme-default/components/VPCarbonAds.vue +7 -2
  10. package/dist/client/theme-default/components/VPContent.vue +10 -8
  11. package/dist/client/theme-default/components/VPDocAside.vue +1 -1
  12. package/dist/client/theme-default/components/VPDocAsideCarbonAds.vue +1 -1
  13. package/dist/client/theme-default/components/VPDocAsideOutline.vue +1 -1
  14. package/dist/client/theme-default/components/VPDocAsideSponsors.vue +1 -1
  15. package/dist/client/theme-default/components/VPDocFooter.vue +1 -1
  16. package/dist/client/theme-default/components/VPHome.vue +3 -3
  17. package/dist/client/theme-default/components/VPLink.vue +4 -6
  18. package/dist/client/theme-default/components/VPLocalSearchBox.vue +101 -22
  19. package/dist/client/theme-default/components/VPMenuLink.vue +1 -1
  20. package/dist/client/theme-default/components/VPNavBarExtra.vue +4 -3
  21. package/dist/client/theme-default/components/VPNavBarMenu.vue +1 -1
  22. package/dist/client/theme-default/components/VPNavBarMenuGroup.vue +1 -1
  23. package/dist/client/theme-default/components/VPNavBarMenuLink.vue +1 -1
  24. package/dist/client/theme-default/components/VPNavBarTranslations.vue +3 -2
  25. package/dist/client/theme-default/components/VPNavScreenMenu.vue +1 -1
  26. package/dist/client/theme-default/components/VPNavScreenMenuGroupLink.vue +1 -1
  27. package/dist/client/theme-default/components/VPNavScreenMenuLink.vue +1 -1
  28. package/dist/client/theme-default/components/VPNavScreenTranslations.vue +3 -0
  29. package/dist/client/theme-default/components/VPSkipLink.vue +1 -1
  30. package/dist/client/theme-default/components/VPSocialLink.vue +2 -1
  31. package/dist/client/theme-default/components/VPSocialLinks.vue +2 -1
  32. package/dist/client/theme-default/components/VPSponsors.vue +1 -1
  33. package/dist/client/theme-default/components/VPSponsorsGrid.vue +1 -1
  34. package/dist/client/theme-default/components/VPTeamMembersItem.vue +2 -4
  35. package/dist/client/theme-default/composables/langs.js +11 -2
  36. package/dist/client/theme-default/composables/outline.js +4 -4
  37. package/dist/client/theme-default/styles/base.css +16 -0
  38. package/dist/client/theme-default/styles/components/vp-code.css +8 -0
  39. package/dist/client/theme-default/styles/components/vp-doc.css +13 -6
  40. package/dist/client/theme-default/styles/docsearch.css +4 -0
  41. package/dist/client/theme-default/support/docsearch.js +23 -8
  42. package/dist/client/theme-default/support/sidebar.js +2 -2
  43. package/dist/client/theme-default/support/utils.js +6 -0
  44. package/dist/node/{chunk-CpMTk0EA.js → chunk-Cne7GbZY.js} +6504 -9084
  45. package/dist/node/cli.js +3 -6
  46. package/dist/node/index.d.ts +854 -22
  47. package/dist/node/index.js +6 -9
  48. package/package.json +55 -60
  49. package/types/default-theme.d.ts +13 -3
  50. package/types/shared.d.ts +37 -9
@@ -136,7 +136,7 @@ if (inBrowser) {
136
136
  app.mount('#app');
137
137
  // scroll to hash on new tab during dev
138
138
  if (import.meta.env.DEV && location.hash) {
139
- scrollTo(location.hash);
139
+ setTimeout(() => scrollTo(location.hash), 100);
140
140
  }
141
141
  });
142
142
  });
@@ -1,7 +1,7 @@
1
1
  import { inject, markRaw, nextTick, reactive, readonly } from 'vue';
2
2
  import { notFoundPageData, treatAsHtml } from '../shared';
3
3
  import { siteDataRef } from './data';
4
- import { getScrollOffset, inBrowser, withBase } from './utils';
4
+ import { 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
7
  // matter and is only passed to support same-host hrefs
@@ -70,7 +70,7 @@ export function createRouter(loadPageModule, fallbackComponent) {
70
70
  history.replaceState({}, '', href);
71
71
  }
72
72
  if (!initialLoad)
73
- scrollTo(targetLoc.hash, false, scrollPosition);
73
+ scrollTo(targetLoc.hash, scrollPosition);
74
74
  });
75
75
  }
76
76
  }
@@ -143,10 +143,7 @@ export function createRouter(loadPageModule, fallbackComponent) {
143
143
  // only intercept inbound html links
144
144
  if (origin === currentLoc.origin && treatAsHtml(pathname)) {
145
145
  e.preventDefault();
146
- router.go(href, {
147
- // use smooth scroll when clicking on header anchor links
148
- smoothScroll: link.classList.contains('header-anchor')
149
- });
146
+ router.go(href);
150
147
  }
151
148
  }, { capture: true });
152
149
  window.addEventListener('popstate', async (e) => {
@@ -174,7 +171,7 @@ export function useRouter() {
174
171
  export function useRoute() {
175
172
  return useRouter().route;
176
173
  }
177
- export function scrollTo(hash, smooth = false, scrollPosition = 0) {
174
+ export function scrollTo(hash, scrollPosition = 0) {
178
175
  if (!hash || scrollPosition) {
179
176
  window.scrollTo(0, scrollPosition);
180
177
  return;
@@ -188,18 +185,8 @@ export function scrollTo(hash, smooth = false, scrollPosition = 0) {
188
185
  }
189
186
  if (!target)
190
187
  return;
191
- const targetTop = window.scrollY +
192
- target.getBoundingClientRect().top -
193
- getScrollOffset() +
194
- Number.parseInt(window.getComputedStyle(target).paddingTop, 10) || 0;
195
- const behavior = window.matchMedia('(prefers-reduced-motion)').matches
196
- ? 'instant'
197
- : // only smooth scroll if distance is smaller than screen height
198
- smooth && Math.abs(targetTop - window.scrollY) <= window.innerHeight
199
- ? 'smooth'
200
- : 'auto';
201
188
  const scrollToTarget = () => {
202
- window.scrollTo({ left: 0, top: targetTop, behavior });
189
+ target.scrollIntoView({ block: 'start' });
203
190
  // focus the target element for better accessibility
204
191
  target.focus({ preventScroll: true });
205
192
  // return if focus worked
@@ -253,14 +240,14 @@ function normalizeHref(href) {
253
240
  }
254
241
  return url.pathname + url.search + url.hash.split(':~:')[0];
255
242
  }
256
- async function changeRoute(href, { smoothScroll = false, initialLoad = false, replace = false, hasTextFragment = false } = {}) {
243
+ async function changeRoute(href, { initialLoad = false, replace = false, hasTextFragment = false } = {}) {
257
244
  const loc = normalizeHref(location.href);
258
245
  const nextUrl = new URL(href, location.origin);
259
246
  const currentUrl = new URL(loc, location.origin);
260
247
  if (href === loc) {
261
248
  if (!initialLoad) {
262
249
  if (!hasTextFragment)
263
- scrollTo(nextUrl.hash, smoothScroll);
250
+ scrollTo(nextUrl.hash);
264
251
  return false;
265
252
  }
266
253
  }
@@ -281,7 +268,7 @@ async function changeRoute(href, { smoothScroll = false, initialLoad = false, re
281
268
  newURL: nextUrl.href
282
269
  }));
283
270
  if (!hasTextFragment)
284
- scrollTo(nextUrl.hash, smoothScroll);
271
+ scrollTo(nextUrl.hash);
285
272
  }
286
273
  return false;
287
274
  }
@@ -84,37 +84,3 @@ export function defineClientComponent(loader, args, cb) {
84
84
  }
85
85
  };
86
86
  }
87
- export function getScrollOffset() {
88
- let scrollOffset = siteDataRef.value.scrollOffset;
89
- let offset = 0;
90
- let padding = 24;
91
- if (typeof scrollOffset === 'object' && 'padding' in scrollOffset) {
92
- padding = scrollOffset.padding;
93
- scrollOffset = scrollOffset.selector;
94
- }
95
- if (typeof scrollOffset === 'number') {
96
- offset = scrollOffset;
97
- }
98
- else if (typeof scrollOffset === 'string') {
99
- offset = tryOffsetSelector(scrollOffset, padding);
100
- }
101
- else if (Array.isArray(scrollOffset)) {
102
- for (const selector of scrollOffset) {
103
- const res = tryOffsetSelector(selector, padding);
104
- if (res) {
105
- offset = res;
106
- break;
107
- }
108
- }
109
- }
110
- return offset;
111
- }
112
- function tryOffsetSelector(selector, padding) {
113
- const el = document.querySelector(selector);
114
- if (!el)
115
- return 0;
116
- const bot = el.getBoundingClientRect().bottom;
117
- if (bot < 0)
118
- return 0;
119
- return bot + padding;
120
- }
@@ -1,7 +1,159 @@
1
1
  import * as vue from 'vue';
2
- import { Component, Ref, InjectionKey, App, AsyncComponentLoader } from 'vue';
3
- import { PageData, Awaitable, SiteData } from '../../types/shared.js';
4
- export { HeadConfig, Header, PageData, SiteData } from '../../types/shared.js';
2
+ import { Ref, Component, App, InjectionKey, AsyncComponentLoader } from 'vue';
3
+ import { UseDarkOptions } from '@vueuse/core';
4
+
5
+ // types shared between server and client
6
+
7
+
8
+ type Awaitable<T> = T | PromiseLike<T>
9
+
10
+ type DeepPartial<T> =
11
+ T extends Record<string, any>
12
+ ? T extends
13
+ | Date
14
+ | RegExp
15
+ | Function
16
+ | ReadonlyMap<any, any>
17
+ | ReadonlySet<any>
18
+ | ReadonlyArray<any>
19
+ ? T
20
+ : { [P in keyof T]?: DeepPartial<T[P]> }
21
+ : T
22
+
23
+ interface PageData {
24
+ relativePath: string
25
+ /**
26
+ * differs from relativePath in case of path rewrites
27
+ * empty string if the page is virtual (e.g. 404 page)
28
+ */
29
+ filePath: string
30
+ title: string
31
+ titleTemplate?: string | boolean
32
+ description: string
33
+ headers: Header[]
34
+ frontmatter: Record<string, any>
35
+ params?: Record<string, any>
36
+ isNotFound?: boolean
37
+ lastUpdated?: number
38
+ }
39
+
40
+ interface Header {
41
+ /**
42
+ * The level of the header
43
+ *
44
+ * `1` to `6` for `<h1>` to `<h6>`
45
+ */
46
+ level: number
47
+ /**
48
+ * The title of the header
49
+ */
50
+ title: string
51
+ /**
52
+ * The slug of the header
53
+ *
54
+ * Typically the `id` attr of the header anchor
55
+ */
56
+ slug: string
57
+ /**
58
+ * Link of the header
59
+ *
60
+ * Typically using `#${slug}` as the anchor hash
61
+ */
62
+ link: string
63
+ /**
64
+ * The children of the header
65
+ */
66
+ children: Header[]
67
+ }
68
+
69
+ interface SiteData<ThemeConfig = any> {
70
+ base: string
71
+ cleanUrls?: boolean
72
+ lang: string
73
+ dir: string
74
+ title: string
75
+ titleTemplate?: string | boolean
76
+ description: string
77
+ head: HeadConfig[]
78
+ appearance:
79
+ | boolean
80
+ | 'dark'
81
+ | 'force-dark'
82
+ | 'force-auto'
83
+ | (Omit<UseDarkOptions, 'initialValue'> & { initialValue?: 'dark' })
84
+ themeConfig: ThemeConfig
85
+ locales: LocaleConfig<ThemeConfig>
86
+ localeIndex?: string
87
+ contentProps?: Record<string, any>
88
+ router: {
89
+ prefetchLinks: boolean
90
+ }
91
+ additionalConfig?:
92
+ AdditionalConfigDict<ThemeConfig> | AdditionalConfigLoader<ThemeConfig>
93
+ }
94
+
95
+ interface VitePressData<T = any> {
96
+ /**
97
+ * Site-level metadata
98
+ */
99
+ site: Ref<SiteData<T>>
100
+ /**
101
+ * themeConfig from .vitepress/config.js
102
+ */
103
+ theme: Ref<T>
104
+ /**
105
+ * Page-level metadata
106
+ */
107
+ page: Ref<PageData>
108
+ /**
109
+ * page frontmatter data
110
+ */
111
+ frontmatter: Ref<PageData['frontmatter']>
112
+ /**
113
+ * dynamic route params
114
+ */
115
+ params: Ref<PageData['params']>
116
+ title: Ref<string>
117
+ description: Ref<string>
118
+ lang: Ref<string>
119
+ dir: Ref<string>
120
+ localeIndex: Ref<string>
121
+ isDark: Ref<boolean>
122
+ /**
123
+ * Current location hash
124
+ */
125
+ hash: Ref<string>
126
+ }
127
+
128
+ type HeadConfig =
129
+ [string, Record<string, string>] | [string, Record<string, string>, string]
130
+
131
+ interface LocaleSpecificConfig<ThemeConfig = any> {
132
+ lang?: string
133
+ dir?: string
134
+ title?: string
135
+ titleTemplate?: string | boolean
136
+ description?: string
137
+ head?: HeadConfig[]
138
+ themeConfig?: DeepPartial<ThemeConfig>
139
+ }
140
+
141
+ type LocaleConfig<ThemeConfig = any> = Record<
142
+ string,
143
+ LocaleSpecificConfig<ThemeConfig> & { label: string; link?: string }
144
+ >
145
+
146
+ type AdditionalConfig<ThemeConfig = any> =
147
+ LocaleSpecificConfig<ThemeConfig>
148
+
149
+ type AdditionalConfigDict<ThemeConfig = any> = Record<
150
+ string,
151
+ AdditionalConfig<ThemeConfig>
152
+ >
153
+
154
+ type AdditionalConfigLoader<ThemeConfig = any> = (
155
+ relativePath: string
156
+ ) => AdditionalConfig<ThemeConfig>[] | void
5
157
 
6
158
  declare const inBrowser: boolean;
7
159
  /**
@@ -26,7 +178,6 @@ interface Router {
26
178
  */
27
179
  go: (to: string, options?: {
28
180
  initialLoad?: boolean;
29
- smoothScroll?: boolean;
30
181
  replace?: boolean;
31
182
  }) => Promise<void>;
32
183
  /**
@@ -50,41 +201,6 @@ interface Router {
50
201
  declare function useRouter(): Router;
51
202
  declare function useRoute(): Route;
52
203
 
53
- declare const dataSymbol: InjectionKey<VitePressData>;
54
- interface VitePressData<T = any> {
55
- /**
56
- * Site-level metadata
57
- */
58
- site: Ref<SiteData<T>>;
59
- /**
60
- * themeConfig from .vitepress/config.js
61
- */
62
- theme: Ref<T>;
63
- /**
64
- * Page-level metadata
65
- */
66
- page: Ref<PageData>;
67
- /**
68
- * page frontmatter data
69
- */
70
- frontmatter: Ref<PageData['frontmatter']>;
71
- /**
72
- * dynamic route params
73
- */
74
- params: Ref<PageData['params']>;
75
- title: Ref<string>;
76
- description: Ref<string>;
77
- lang: Ref<string>;
78
- dir: Ref<string>;
79
- localeIndex: Ref<string>;
80
- isDark: Ref<boolean>;
81
- /**
82
- * Current location hash
83
- */
84
- hash: Ref<string>;
85
- }
86
- declare function useData<T = any>(): VitePressData<T>;
87
-
88
204
  interface EnhanceAppContext {
89
205
  app: App;
90
206
  router: Router;
@@ -104,6 +220,10 @@ interface Theme {
104
220
  NotFound?: Component;
105
221
  }
106
222
 
223
+ declare const dataSymbol: InjectionKey<VitePressData>;
224
+
225
+ declare function useData<T = any>(): VitePressData<T>;
226
+
107
227
  /**
108
228
  * Append base to internal (non-relative) urls
109
229
  */
@@ -118,7 +238,6 @@ declare function defineClientComponent(loader: AsyncComponentLoader, args?: any[
118
238
  [key: string]: any;
119
239
  }> | null;
120
240
  };
121
- declare function getScrollOffset(): number;
122
241
 
123
242
  declare const Content: vue.DefineComponent<vue.ExtractPropTypes<{
124
243
  as: {
@@ -136,4 +255,4 @@ declare const Content: vue.DefineComponent<vue.ExtractPropTypes<{
136
255
  as: string | Record<string, any>;
137
256
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
138
257
 
139
- export { Content, type EnhanceAppContext, type Route, type Router, type Theme, type VitePressData, escapeHtml as _escapeHtml, dataSymbol, defineClientComponent, getScrollOffset, inBrowser, onContentUpdated, useData, useRoute, useRouter, withBase };
258
+ export { Content, type EnhanceAppContext, type HeadConfig, type Header, type PageData, type Route, type Router, type SiteData, type Theme, type VitePressData, escapeHtml as _escapeHtml, dataSymbol, defineClientComponent, inBrowser, onContentUpdated, useData, useRoute, useRouter, withBase };
@@ -4,6 +4,6 @@
4
4
  export { dataSymbol, useData } from './app/data';
5
5
  export { useRoute, useRouter } from './app/router';
6
6
  // utilities
7
- export { _escapeHtml, defineClientComponent, getScrollOffset, inBrowser, onContentUpdated, withBase } from './app/utils';
7
+ export { _escapeHtml, defineClientComponent, inBrowser, onContentUpdated, withBase } from './app/utils';
8
8
  // components
9
9
  export { Content } from './app/components/Content';
@@ -4,7 +4,7 @@ export const VP_SOURCE_KEY = '[VP_SOURCE]';
4
4
  const UnpackStackView = Symbol('stack-view:unpack');
5
5
  const HASH_WITHOUT_FRAGMENT_RE = /#.*?(?=:~:|$)/;
6
6
  const HASH_OR_QUERY_RE = /[?#].*$/;
7
- const INDEX_OR_EXT_RE = /(?:(^|\/)index)?\.(?:md|html)$/;
7
+ const INDEX_OR_EXT_RE = /(?:(^|\/)index)?(?:\.(?:md|html))?$/;
8
8
  export const inBrowser = typeof document !== 'undefined';
9
9
  export const notFoundPageData = {
10
10
  relativePath: '404.md',
@@ -1,12 +1,16 @@
1
1
  <script setup lang="ts">
2
2
  import type { DocSearchInstance, DocSearchProps } from '@docsearch/js'
3
- import type { SidepanelInstance, SidepanelProps } from '@docsearch/sidepanel-js'
3
+ import type { SidepanelInstance } from '@docsearch/sidepanel-js'
4
4
  import { inBrowser, useRouter } from 'vitepress'
5
5
  import type { DefaultTheme } from 'vitepress/theme'
6
6
  import { nextTick, onUnmounted, watch } from 'vue'
7
7
  import type { DocSearchAskAi } from '../../../../types/docsearch'
8
8
  import { useData } from '../composables/data'
9
- import { resolveMode, validateCredentials } from '../support/docsearch'
9
+ import {
10
+ buildSidePanelProps,
11
+ resolveMode,
12
+ validateCredentials
13
+ } from '../support/docsearch'
10
14
 
11
15
  import '../styles/docsearch.css'
12
16
 
@@ -105,12 +109,7 @@ async function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
105
109
  if (currentInitialize !== initializeCount) return
106
110
 
107
111
  sidepanelInstance = sidepanel({
108
- ...(askAi.sidePanel === true ? {} : askAi.sidePanel),
109
- container: '#vp-docsearch-sidepanel',
110
- indexName: askAi.indexName ?? userOptions.indexName,
111
- appId: askAi.appId ?? userOptions.appId,
112
- apiKey: askAi.apiKey ?? userOptions.apiKey,
113
- assistantId: askAi.assistantId,
112
+ ...buildSidePanelProps(askAi, userOptions),
114
113
  onOpen: focusInput,
115
114
  onClose: onClose.bind(null, 'sidepanel'),
116
115
  onReady: () => {
@@ -122,7 +121,7 @@ async function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
122
121
  keyboardShortcuts: {
123
122
  'Ctrl/Cmd+I': false
124
123
  }
125
- } as SidepanelProps)
124
+ })
126
125
  }
127
126
 
128
127
  const options = {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
- import { normalizeLink } from '../support/utils'
4
3
  import { EXTERNAL_URL_RE } from '../../shared'
4
+ import { normalizeLink } from '../support/utils'
5
5
 
6
6
  interface Props {
7
7
  tag?: string
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { DefaultTheme } from 'vitepress/theme'
3
- import { ref, watch, onMounted } from 'vue'
3
+ import { onMounted, ref, watch } from 'vue'
4
4
  import { useAside } from '../composables/aside'
5
5
  import { useData } from '../composables/data'
6
6
 
@@ -19,9 +19,14 @@ let isInitialized = false
19
19
  function init() {
20
20
  if (!isInitialized) {
21
21
  isInitialized = true
22
+ const params = new URLSearchParams({
23
+ serve: carbonOptions.code,
24
+ placement: carbonOptions.placement,
25
+ format: carbonOptions?.format || 'classic',
26
+ })
22
27
  const s = document.createElement('script')
23
28
  s.id = '_carbonads_js'
24
- s.src = `//cdn.carbonads.com/carbon.js?serve=${carbonOptions.code}&placement=${carbonOptions.placement}`
29
+ s.src = `//cdn.carbonads.com/carbon.js?${params.toString()}`
25
30
  s.async = true
26
31
  container.value.appendChild(s)
27
32
  }
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { resolveDynamicComponent } from 'vue'
2
3
  import NotFound from '../NotFound.vue'
3
4
  import { useData } from '../composables/data'
4
5
  import { useLayout } from '../composables/layout'
@@ -8,6 +9,10 @@ import VPPage from './VPPage.vue'
8
9
 
9
10
  const { page, frontmatter } = useData()
10
11
  const { isHome, hasSidebar } = useLayout()
12
+
13
+ function isRegistered(component: string): boolean {
14
+ return typeof resolveDynamicComponent(component) !== 'string'
15
+ }
11
16
  </script>
12
17
 
13
18
  <template>
@@ -18,12 +23,12 @@ const { isHome, hasSidebar } = useLayout()
18
23
  >
19
24
  <slot name="not-found" v-if="page.isNotFound"><NotFound /></slot>
20
25
 
21
- <VPPage v-else-if="frontmatter.layout === 'page'">
26
+ <VPPage v-else-if="frontmatter.layout === 'page' && !isRegistered('page')">
22
27
  <template #page-top><slot name="page-top" /></template>
23
28
  <template #page-bottom><slot name="page-bottom" /></template>
24
29
  </VPPage>
25
30
 
26
- <VPHome v-else-if="frontmatter.layout === 'home'">
31
+ <VPHome v-else-if="frontmatter.layout === 'home' && !isRegistered('home')">
27
32
  <template #home-hero-before><slot name="home-hero-before" /></template>
28
33
  <template #home-hero-info-before><slot name="home-hero-info-before" /></template>
29
34
  <template #home-hero-info><slot name="home-hero-info" /></template>
@@ -36,12 +41,7 @@ const { isHome, hasSidebar } = useLayout()
36
41
  <template #home-features-after><slot name="home-features-after" /></template>
37
42
  </VPHome>
38
43
 
39
- <component
40
- v-else-if="frontmatter.layout && frontmatter.layout !== 'doc'"
41
- :is="frontmatter.layout"
42
- />
43
-
44
- <VPDoc v-else>
44
+ <VPDoc v-else-if="(!frontmatter.layout || frontmatter.layout === 'doc') && !isRegistered('doc')">
45
45
  <template #doc-top><slot name="doc-top" /></template>
46
46
  <template #doc-bottom><slot name="doc-bottom" /></template>
47
47
 
@@ -56,6 +56,8 @@ const { isHome, hasSidebar } = useLayout()
56
56
  <template #aside-ads-after><slot name="aside-ads-after" /></template>
57
57
  <template #aside-bottom><slot name="aside-bottom" /></template>
58
58
  </VPDoc>
59
+
60
+ <component v-else :is="frontmatter.layout || 'doc'" />
59
61
  </div>
60
62
  </template>
61
63
 
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { useData } from '../composables/data'
3
- import VPDocAsideOutline from './VPDocAsideOutline.vue'
4
3
  import VPDocAsideCarbonAds from './VPDocAsideCarbonAds.vue'
4
+ import VPDocAsideOutline from './VPDocAsideOutline.vue'
5
5
 
6
6
  const { theme } = useData()
7
7
  </script>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { defineAsyncComponent } from 'vue'
3
2
  import type { DefaultTheme } from 'vitepress/theme'
3
+ import { defineAsyncComponent } from 'vue'
4
4
 
5
5
  defineProps<{
6
6
  carbonAds: DefaultTheme.CarbonAdsOptions
@@ -1,9 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue'
3
3
  import { useData } from '../composables/data'
4
+ import { useLayout } from '../composables/layout'
4
5
  import { resolveTitle, useActiveAnchor } from '../composables/outline'
5
6
  import VPDocOutlineItem from './VPDocOutlineItem.vue'
6
- import { useLayout } from '../composables/layout'
7
7
 
8
8
  const { theme } = useData()
9
9
 
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { Sponsors } from './VPSponsors.vue'
3
- import type { Sponsor } from './VPSponsorsGrid.vue'
4
3
  import VPSponsors from './VPSponsors.vue'
4
+ import type { Sponsor } from './VPSponsorsGrid.vue'
5
5
 
6
6
  defineProps<{
7
7
  tier?: string
@@ -3,8 +3,8 @@ import { computed } from 'vue'
3
3
  import { useData } from '../composables/data'
4
4
  import { useEditLink } from '../composables/edit-link'
5
5
  import { usePrevNext } from '../composables/prev-next'
6
- import VPLink from './VPLink.vue'
7
6
  import VPDocFooterLastUpdated from './VPDocFooterLastUpdated.vue'
7
+ import VPLink from './VPLink.vue'
8
8
 
9
9
  const { theme, page, frontmatter } = useData()
10
10
 
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
- import VPHomeHero from './VPHomeHero.vue'
3
- import VPHomeFeatures from './VPHomeFeatures.vue'
4
- import VPHomeContent from './VPHomeContent.vue'
5
2
  import { useData } from '../composables/data'
3
+ import VPHomeContent from './VPHomeContent.vue'
4
+ import VPHomeFeatures from './VPHomeFeatures.vue'
5
+ import VPHomeHero from './VPHomeHero.vue'
6
6
 
7
7
  const { frontmatter, theme } = useData()
8
8
  </script>
@@ -1,21 +1,19 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed } from 'vue'
3
- import { normalizeLink } from '../support/utils'
4
- import { EXTERNAL_URL_RE } from '../../shared'
3
+ import { isLinkExternal, normalizeLink } from '../support/utils'
5
4
 
6
5
  const props = defineProps<{
7
6
  tag?: string
8
7
  href?: string
9
8
  noIcon?: boolean
9
+ external?: boolean
10
10
  target?: string
11
11
  rel?: string
12
12
  }>()
13
13
 
14
14
  const tag = computed(() => props.tag ?? (props.href ? 'a' : 'span'))
15
- const isExternal = computed(
16
- () =>
17
- (props.href && EXTERNAL_URL_RE.test(props.href)) ||
18
- props.target === '_blank'
15
+ const isExternal = computed(() =>
16
+ isLinkExternal(props.href, props.target, props.external)
19
17
  )
20
18
  </script>
21
19