vitepress 1.0.0-draft.1 → 1.0.0-draft.4

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 (46) hide show
  1. package/dist/client/app/composables/head.js +2 -2
  2. package/dist/client/app/data.js +2 -4
  3. package/dist/client/index.d.ts +8 -0
  4. package/dist/client/shared.js +22 -0
  5. package/dist/client/theme-default/Layout.vue +18 -1
  6. package/dist/client/theme-default/components/VPBackdrop.vue +1 -1
  7. package/dist/client/theme-default/components/VPBox.vue +59 -0
  8. package/dist/client/theme-default/components/VPButton.vue +123 -0
  9. package/dist/client/theme-default/components/VPContent.vue +34 -10
  10. package/dist/client/theme-default/components/{VPContentDoc.vue → VPDoc.vue} +66 -42
  11. package/dist/client/theme-default/components/{VPContentDocFooter.vue → VPDocFooter.vue} +3 -2
  12. package/dist/client/theme-default/components/{VPContentDocOutline.vue → VPDocOutline.vue} +14 -3
  13. package/dist/client/theme-default/components/VPFooter.vue +53 -0
  14. package/dist/client/theme-default/components/VPHero.vue +144 -0
  15. package/dist/client/theme-default/components/VPHome.vue +33 -0
  16. package/dist/client/theme-default/components/VPHomeFeatures.vue +96 -0
  17. package/dist/client/theme-default/components/VPHomeHero.vue +17 -0
  18. package/dist/client/theme-default/components/VPHomeSponsors.vue +93 -0
  19. package/dist/client/theme-default/components/VPNavBar.vue +2 -1
  20. package/dist/client/theme-default/components/VPNavBarAppearance.vue +4 -1
  21. package/dist/client/theme-default/components/VPNavBarExtra.vue +2 -2
  22. package/dist/client/theme-default/components/VPNavBarSearch.vue +3 -3
  23. package/dist/client/theme-default/components/VPNavBarTitle.vue +26 -13
  24. package/dist/client/theme-default/components/VPNavScreenAppearance.vue +4 -1
  25. package/dist/client/theme-default/components/VPPage.vue +5 -0
  26. package/dist/client/theme-default/components/VPSidebar.vue +2 -2
  27. package/dist/client/theme-default/components/VPSponsors.vue +77 -0
  28. package/dist/client/theme-default/components/VPSponsorsGrid.vue +32 -0
  29. package/dist/client/theme-default/components/VPSwitchAppearance.vue +3 -3
  30. package/dist/client/theme-default/components/icons/VPIconHeart.vue +5 -0
  31. package/dist/client/theme-default/composables/outline.js +12 -20
  32. package/dist/client/theme-default/composables/sponsor-grid.js +92 -0
  33. package/dist/client/theme-default/index.js +6 -1
  34. package/dist/client/theme-default/styles/base.css +3 -0
  35. package/dist/client/theme-default/styles/components/custom-block.css +90 -0
  36. package/dist/client/theme-default/styles/{vp-doc.css → components/vp-doc.css} +63 -11
  37. package/dist/client/theme-default/styles/components/vp-sponsor.css +86 -0
  38. package/dist/client/theme-default/styles/vars.css +150 -29
  39. package/dist/client/theme-default/support/utils.js +19 -0
  40. package/dist/node/cli.js +1 -1
  41. package/dist/node/index.d.ts +22 -1
  42. package/dist/node/index.js +1 -1
  43. package/dist/node/{serve-428d4610.js → serve-b3182d88.js} +50 -8
  44. package/package.json +2 -1
  45. package/types/default-theme.d.ts +12 -0
  46. package/types/shared.d.ts +14 -6
@@ -1,4 +1,5 @@
1
1
  import { watchEffect } from 'vue';
2
+ import { createTitle } from '../../shared';
2
3
  export function useUpdateHead(route, siteDataByRouteRef) {
3
4
  let managedHeadTags = [];
4
5
  let isFirstUpdate = true;
@@ -50,11 +51,10 @@ export function useUpdateHead(route, siteDataByRouteRef) {
50
51
  watchEffect(() => {
51
52
  const pageData = route.data;
52
53
  const siteData = siteDataByRouteRef.value;
53
- const pageTitle = pageData && pageData.title;
54
54
  const pageDescription = pageData && pageData.description;
55
55
  const frontmatterHead = pageData && pageData.frontmatter.head;
56
56
  // update title and description
57
- document.title = (pageTitle ? pageTitle + ` | ` : ``) + siteData.title;
57
+ document.title = createTitle(siteData, pageData);
58
58
  document
59
59
  .querySelector(`meta[name=description]`)
60
60
  .setAttribute('content', pageDescription || siteData.description);
@@ -1,6 +1,6 @@
1
1
  import { shallowRef, readonly, computed, inject } from 'vue';
2
2
  import serializedSiteData from '@siteData';
3
- import { resolveSiteDataByRoute } from '../shared';
3
+ import { resolveSiteDataByRoute, createTitle } from '../shared';
4
4
  import { withBase } from './utils';
5
5
  export const dataSymbol = Symbol();
6
6
  export const siteDataRef = shallowRef(parse(serializedSiteData));
@@ -29,9 +29,7 @@ export function initData(route) {
29
29
  return withBase(path || '/');
30
30
  }),
31
31
  title: computed(() => {
32
- return route.data.title
33
- ? route.data.title + ' | ' + site.value.title
34
- : site.value.title;
32
+ return createTitle(site.value, route.data);
35
33
  }),
36
34
  description: computed(() => {
37
35
  return route.data.description || site.value.description;
@@ -40,6 +40,7 @@ export declare const inBrowser: boolean;
40
40
  export declare interface LocaleConfig {
41
41
  lang: string
42
42
  title?: string
43
+ titleTemplate?: string | boolean
43
44
  description?: string
44
45
  head?: HeadConfig[]
45
46
  label?: string
@@ -49,6 +50,7 @@ export declare interface LocaleConfig {
49
50
  export declare interface PageData {
50
51
  relativePath: string
51
52
  title: string
53
+ titleTemplate?: string | boolean
52
54
  description: string
53
55
  headers: Header[]
54
56
  frontmatter: Record<string, any>
@@ -68,17 +70,23 @@ export declare interface Router {
68
70
 
69
71
  export declare interface SiteData<ThemeConfig = any> {
70
72
  base: string
73
+
71
74
  /**
72
75
  * Language of the site as it should be set on the `html` element.
76
+ *
73
77
  * @example `en-US`, `zh-CN`
74
78
  */
75
79
  lang: string
80
+
76
81
  title: string
82
+ titleTemplate?: string | boolean
77
83
  description: string
78
84
  head: HeadConfig[]
85
+ appearance: boolean
79
86
  themeConfig: ThemeConfig
80
87
  scrollOffset: number | string
81
88
  locales: Record<string, LocaleConfig>
89
+
82
90
  /**
83
91
  * Available locales for the site when it has defined `locales` in its
84
92
  * `themeConfig`. This object is otherwise empty. Keys are paths like `/` or
@@ -1,4 +1,5 @@
1
1
  export const EXTERNAL_URL_RE = /^https?:/i;
2
+ export const APPEARANCE_KEY = 'vitepress-theme-appearance';
2
3
  // @ts-ignore
3
4
  export const inBrowser = typeof window !== 'undefined';
4
5
  function findMatchRoot(route, roots) {
@@ -52,6 +53,27 @@ export function resolveSiteDataByRoute(siteData, route) {
52
53
  langs: createLangDictionary(siteData)
53
54
  });
54
55
  }
56
+ /**
57
+ * Create the page title string based on configs.
58
+ */
59
+ export function createTitle(siteData, pageData) {
60
+ const title = pageData.title || siteData.title;
61
+ const template = pageData.titleTemplate ?? siteData.titleTemplate;
62
+ const templateString = createTitleTemplate(siteData.title, template);
63
+ return `${title}${templateString}`;
64
+ }
65
+ function createTitleTemplate(siteTitle, template) {
66
+ if (template === false) {
67
+ return '';
68
+ }
69
+ if (template === true || template === undefined) {
70
+ return ` | ${siteTitle}`;
71
+ }
72
+ if (siteTitle === template) {
73
+ return '';
74
+ }
75
+ return ` | ${template}`;
76
+ }
55
77
  /**
56
78
  * Clean up the route by removing the `base` path if it's set in config.
57
79
  */
@@ -7,6 +7,7 @@ import VPNav from './components/VPNav.vue'
7
7
  import VPLocalNav from './components/VPLocalNav.vue'
8
8
  import VPSidebar from './components/VPSidebar.vue'
9
9
  import VPContent from './components/VPContent.vue'
10
+ import VPFooter from './components/VPFooter.vue'
10
11
 
11
12
  const {
12
13
  isOpen: isSidebarOpen,
@@ -26,6 +27,22 @@ provide('close-sidebar', closeSidebar)
26
27
  <VPNav />
27
28
  <VPLocalNav :open="isSidebarOpen" @open-menu="openSidebar" />
28
29
  <VPSidebar :open="isSidebarOpen" />
29
- <VPContent />
30
+
31
+ <VPContent>
32
+ <template #home-hero-before><slot name="home-hero-before" /></template>
33
+ <template #home-hero-after><slot name="home-hero-after" /></template>
34
+ <template #home-features-before><slot name="home-features-before" /></template>
35
+ <template #home-features-after><slot name="home-features-after" /></template>
36
+ </VPContent>
37
+
38
+ <VPFooter />
30
39
  </div>
31
40
  </template>
41
+
42
+ <style scoped>
43
+ .Layout {
44
+ display: flex;
45
+ flex-direction: column;
46
+ min-height: 100vh;
47
+ }
48
+ </style>
@@ -17,7 +17,7 @@ defineProps<{
17
17
  right: 0;
18
18
  bottom: 0;
19
19
  left: 0;
20
- z-index: var(--vp-z-backdrop);
20
+ z-index: var(--vp-z-index-backdrop);
21
21
  background: rgba(0, 0, 0, .6);
22
22
  transition: opacity 0.5s;
23
23
  }
@@ -0,0 +1,59 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ icon?: string
4
+ title: string
5
+ details: string
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <article class="VPBox">
11
+ <div v-if="icon" class="icon">{{ icon }}</div>
12
+ <h1 class="title">{{ title }}</h1>
13
+ <p class="details">{{ details }}</p>
14
+ </article>
15
+ </template>
16
+
17
+ <style scoped>
18
+ .VPBox {
19
+ border: 1px solid var(--vp-c-divider-light);
20
+ border-radius: 8px;
21
+ padding: 24px;
22
+ height: 100%;
23
+ background-color: var(--vp-c-bg-soft);
24
+ }
25
+
26
+ .dark .VPBox {
27
+ background-color: var(--vp-c-bg-mute);
28
+ }
29
+
30
+ .icon {
31
+ display: flex;
32
+ justify-content: center;
33
+ align-items: center;
34
+ margin-bottom: 20px;
35
+ border-radius: 6px;
36
+ background-color: var(--vp-c-gray-light-4);
37
+ width: 48px;
38
+ height: 48px;
39
+ font-size: 24px;
40
+ }
41
+
42
+ .dark .icon {
43
+ background-color: var(--vp-c-bg-soft);
44
+ }
45
+
46
+ .title {
47
+ line-height: 24px;
48
+ font-size: 16px;
49
+ font-weight: 600;
50
+ }
51
+
52
+ .details {
53
+ padding-top: 8px;
54
+ line-height: 24px;
55
+ font-size: 14px;
56
+ font-weight: 500;
57
+ color: var(--vp-c-text-2);
58
+ }
59
+ </style>
@@ -0,0 +1,123 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ tag?: string
6
+ size?: 'medium' | 'big'
7
+ theme?: 'brand' | 'alt' | 'sponsor'
8
+ text: string
9
+ href?: string
10
+ }>()
11
+
12
+ const classes = computed(() => [
13
+ props.size ?? 'medium',
14
+ props.theme ?? 'brand'
15
+ ])
16
+
17
+ const isExternal = computed(() => props.href && /^[a-z]+:/i.test(props.href))
18
+
19
+ const component = computed(() => {
20
+ if (props.tag) {
21
+ return props.tag
22
+ }
23
+
24
+ return props.href ? 'a' : 'button'
25
+ })
26
+ </script>
27
+
28
+ <template>
29
+ <component
30
+ :is="component"
31
+ class="VPButton"
32
+ :class="classes"
33
+ :href="href"
34
+ :target="isExternal ? '_blank' : undefined"
35
+ :rel="isExternal ? 'noopener noreferrer' : undefined"
36
+ >
37
+ {{ text }}
38
+ </component>
39
+ </template>
40
+
41
+ <style scoped>
42
+ .VPButton {
43
+ display: inline-block;
44
+ border: 1px solid transparent;
45
+
46
+ text-align: center;
47
+ font-weight: 500;
48
+ white-space: nowrap;
49
+ transition: color 0.25s, border-color 0.25s, background-color 0.25s;
50
+ }
51
+
52
+ .VPButton:active {
53
+ transition: color 0.1s, border-color 0.1s, background-color 0.1s;
54
+ }
55
+
56
+ .VPButton.medium {
57
+ border-radius: 20px;
58
+ padding: 0 20px;
59
+ line-height: 38px;
60
+ font-size: 14px;
61
+ }
62
+
63
+ .VPButton.big {
64
+ border-radius: 24px;
65
+ padding: 0 24px;
66
+ line-height: 46px;
67
+ font-size: 16px;
68
+ }
69
+
70
+ .VPButton.brand {
71
+ border-color: var(--vp-button-brand-border);
72
+ color: var(--vp-button-brand-text);
73
+ background-color: var(--vp-button-brand-bg);
74
+ }
75
+
76
+ .VPButton.brand:hover {
77
+ border-color: var(--vp-button-brand-hover-border);
78
+ color: var(--vp-button-brand-hover-text);
79
+ background-color: var(--vp-button-brand-hover-bg);
80
+ }
81
+
82
+ .VPButton.brand:active {
83
+ border-color: var(--vp-button-brand-active-border);
84
+ color: var(--vp-button-brand-active-text);
85
+ background-color: var(--vp-button-brand-active-bg);
86
+ }
87
+
88
+ .VPButton.alt {
89
+ border-color: var(--vp-button-alt-border);
90
+ color: var(--vp-button-alt-text);
91
+ background-color: var(--vp-button-alt-bg);
92
+ }
93
+
94
+ .VPButton.alt:hover {
95
+ border-color: var(--vp-button-alt-hover-border);
96
+ color: var(--vp-button-alt-hover-text);
97
+ background-color: var(--vp-button-alt-hover-bg);
98
+ }
99
+
100
+ .VPButton.alt:active {
101
+ border-color: var(--vp-button-alt-active-border);
102
+ color: var(--vp-button-alt-active-text);
103
+ background-color: var(--vp-button-alt-active-bg);
104
+ }
105
+
106
+ .VPButton.sponsor {
107
+ border-color: var(--vp-button-sponsor-border);
108
+ color: var(--vp-button-sponsor-text);
109
+ background-color: var(--vp-button-sponsor-bg);
110
+ }
111
+
112
+ .VPButton.sponsor:hover {
113
+ border-color: var(--vp-button-sponsor-hover-border);
114
+ color: var(--vp-button-sponsor-hover-text);
115
+ background-color: var(--vp-button-sponsor-hover-bg);
116
+ }
117
+
118
+ .VPButton.sponsor:active {
119
+ border-color: var(--vp-button-sponsor-active-border);
120
+ color: var(--vp-button-sponsor-active-text);
121
+ background-color: var(--vp-button-sponsor-active-bg);
122
+ }
123
+ </style>
@@ -1,10 +1,13 @@
1
1
  <script setup lang="ts">
2
- import { useRoute } from 'vitepress'
2
+ import { useRoute, useData } from 'vitepress'
3
3
  import { useSidebar } from '../composables/sidebar'
4
4
  import NotFound from '../NotFound.vue'
5
- import VPContentDoc from './VPContentDoc.vue'
5
+ import VPPage from './VPPage.vue'
6
+ import VPHome from './VPHome.vue'
7
+ import VPDoc from './VPDoc.vue'
6
8
 
7
9
  const route = useRoute()
10
+ const { frontmatter } = useData()
8
11
  const { hasSidebar } = useSidebar()
9
12
  </script>
10
13
 
@@ -12,33 +15,54 @@ const { hasSidebar } = useSidebar()
12
15
  <div
13
16
  class="VPContent"
14
17
  id="VPContent"
15
- :class="{ 'has-sidebar': hasSidebar }"
18
+ :class="{
19
+ 'has-sidebar': hasSidebar,
20
+ 'is-home': frontmatter.layout === 'home'
21
+ }"
16
22
  >
17
23
  <NotFound v-if="route.component === NotFound" />
18
- <VPContentDoc v-else :class="{ 'has-sidebar': hasSidebar }" />
24
+
25
+ <VPPage v-else-if="frontmatter.layout === 'page'" />
26
+
27
+ <VPHome v-else-if="frontmatter.layout === 'home'">
28
+ <template #home-hero-before><slot name="home-hero-before" /></template>
29
+ <template #home-hero-after><slot name="home-hero-after" /></template>
30
+ <template #home-features-before><slot name="home-features-before" /></template>
31
+ <template #home-features-after><slot name="home-features-after" /></template>
32
+ </VPHome>
33
+
34
+ <VPDoc v-else />
19
35
  </div>
20
36
  </template>
21
37
 
22
38
  <style scoped>
23
- @media (max-width: 768px) {
24
- .VPContent {
25
- overflow-x: hidden;
26
- }
39
+ .VPContent {
40
+ flex-grow: 1;
41
+ flex-shrink: 0;
42
+ margin: 0 auto;
43
+ width: 100%;
44
+ }
45
+
46
+ .VPContent.is-home {
47
+ width: 100%;
48
+ max-width: 100%;
27
49
  }
28
50
 
29
51
  @media (min-width: 960px) {
30
52
  .VPContent {
31
- padding-top: var(--vp-nav-height-desktop);
53
+ padding-top: var(--vp-nav-height);
32
54
  }
33
55
 
34
56
  .VPContent.has-sidebar {
57
+ margin: 0;
35
58
  padding-left: var(--vp-sidebar-width);
36
59
  }
37
60
  }
38
61
 
39
62
  @media (min-width: 1440px) {
40
63
  .VPContent.has-sidebar {
41
- padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width) - 32px);
64
+ padding-right: calc((100vw - var(--vp-layout-max-width)) / 2);
65
+ padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
42
66
  }
43
67
  }
44
68
  </style>
@@ -1,10 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
3
  import { useData } from 'vitepress'
4
- import VPContentDocOutline from './VPContentDocOutline.vue'
5
- import VPContentDocFooter from './VPContentDocFooter.vue'
4
+ import { useSidebar } from '../composables/sidebar'
5
+ import VPDocOutline from './VPDocOutline.vue'
6
+ import VPDocFooter from './VPDocFooter.vue'
6
7
 
7
8
  const { page } = useData()
9
+ const { hasSidebar } = useSidebar()
8
10
 
9
11
  const pageName = computed(() => {
10
12
  return page.value.relativePath.slice(0, page.value.relativePath.indexOf('/'))
@@ -12,95 +14,101 @@ const pageName = computed(() => {
12
14
  </script>
13
15
 
14
16
  <template>
15
- <div class="VPContentDoc has-aside">
17
+ <div class="VPDoc" :class="{ 'has-sidebar': hasSidebar }">
16
18
  <div class="container">
17
19
  <div class="aside">
18
20
  <div class="aside-container">
19
21
  <div class="aside-curtain" />
20
22
  <div class="aside-content">
21
- <VPContentDocOutline v-if="page.headers" />
23
+ <VPDocOutline v-if="page.headers" />
22
24
  </div>
23
25
  </div>
24
26
  </div>
25
27
 
26
28
  <div class="content">
27
- <main class="main">
28
- <Content class="vp-doc" :class="pageName" />
29
- </main>
29
+ <div class="content-container">
30
+ <main class="main">
31
+ <Content class="vp-doc" :class="pageName" />
32
+ </main>
30
33
 
31
- <VPContentDocFooter />
34
+ <VPDocFooter />
35
+ </div>
32
36
  </div>
33
37
  </div>
34
38
  </div>
35
39
  </template>
36
40
 
37
41
  <style scoped>
38
- .VPContentDoc {
42
+ .VPDoc {
39
43
  padding: 32px 24px 96px;
44
+ width: 100%;
40
45
  }
41
46
 
42
47
  @media (min-width: 768px) {
43
- .VPContentDoc {
48
+ .VPDoc {
44
49
  padding: 48px 32px 128px;
45
50
  }
46
51
  }
47
52
 
48
53
  @media (min-width: 960px) {
49
- .VPContentDoc {
50
- padding: 32px 64px 96px;
54
+ .VPDoc {
55
+ padding: 32px 32px 128px;
51
56
  }
52
- }
53
57
 
54
- @media (min-width: 1280px) {
55
- .VPContentDoc {
56
- padding: 32px 0 128px 64px;
58
+ .VPDoc:not(.has-sidebar) .container {
59
+ display: flex;
60
+ justify-content: center;
61
+ max-width: 992px;
57
62
  }
58
63
 
59
- .VPContentDoc:not(.has-sidebar.has-aside) {
60
- padding-left: calc((100vw - 688px) / 2);
64
+ .VPDoc:not(.has-sidebar) .aside {
65
+ display: block;
61
66
  }
62
67
 
63
- .VPContentDoc.has-aside:not(.has-sidebar) {
64
- padding-left: calc((100vw - 688px - 320px) / 2);
68
+ .VPDoc:not(.has-sidebar) .content {
69
+ max-width: 752px;
65
70
  }
71
+ }
66
72
 
67
- .VPContentDoc:not(.has-aside) .content {
68
- min-width: 688px;
73
+ @media (min-width: 1280px) {
74
+ .VPDoc .container {
75
+ display: flex;
76
+ justify-content: center;
77
+ }
78
+
79
+ .VPDoc .aside {
80
+ display: block;
69
81
  }
70
82
  }
71
83
 
72
84
  @media (min-width: 1440px) {
73
- .VPContentDoc {
74
- padding: 32px 0 128px 96px;
85
+ .VPDoc:not(.has-sidebar) .content {
86
+ max-width: 784px;
75
87
  }
76
- }
77
88
 
78
- @media (min-width: 1280px) {
79
- .container {
80
- display: flex;
89
+ .VPDoc:not(.has-sidebar) .container {
90
+ max-width: 1104px;
81
91
  }
82
92
  }
83
93
 
94
+ .container {
95
+ margin: 0 auto;
96
+ width: 100%;
97
+ }
98
+
84
99
  .aside {
85
100
  position: relative;
86
101
  display: none;
87
102
  order: 2;
88
- flex-shrink: 0;
89
103
  flex-grow: 1;
90
- padding-left: 64px;
91
- padding-right: 32px;
92
- min-width: 320px;
93
- }
94
-
95
- @media (min-width: 1280px) {
96
- .aside {
97
- display: block;
98
- }
104
+ flex-shrink: 0;
105
+ padding-left: 32px;
106
+ min-width: 240px;
99
107
  }
100
108
 
101
109
  @media (min-width: 1440px) {
102
110
  .aside {
103
- padding-left: 96px;
111
+ padding-left: 64px;
104
112
  }
105
113
  }
106
114
 
@@ -109,7 +117,7 @@ const pageName = computed(() => {
109
117
  top: var(--vp-nav-height-desktop);
110
118
  bottom: 0;
111
119
  padding-top: 32px;
112
- width: 224px;
120
+ width: 208px;
113
121
  overflow-x: hidden;
114
122
  overflow-y: auto;
115
123
  }
@@ -140,17 +148,33 @@ const pageName = computed(() => {
140
148
  .content {
141
149
  position: relative;
142
150
  margin: 0 auto;
143
- max-width: 688px;
151
+ }
152
+
153
+ @media (min-width: 960px) {
154
+ .content {
155
+ padding: 0 32px;
156
+ }
144
157
  }
145
158
 
146
159
  @media (min-width: 1280px) {
147
160
  .content {
148
161
  order: 1;
149
162
  margin: 0;
150
- min-width: 632px;
163
+ min-width: 640px;
164
+ }
165
+ }
166
+
167
+ @media (min-width: 1440px) {
168
+ .content {
169
+ padding-left: 64px;
151
170
  }
152
171
  }
153
172
 
173
+ .content-container {
174
+ margin: 0 auto;
175
+ max-width: 688px;
176
+ }
177
+
154
178
  .edit-link {
155
179
  margin: 0 0 32px;
156
180
  }
@@ -13,7 +13,7 @@ const control = usePrevNext()
13
13
  </script>
14
14
 
15
15
  <template>
16
- <footer v-if="control.prev || control.next" class="VPContentDocFooter">
16
+ <footer v-if="control.prev || control.next" class="VPDocFooter">
17
17
  <div v-if="theme.editLink && frontmatter.editLink !== false" class="edit-link">
18
18
  <VPLink class="edit-link-button" :href="editLink.url" :no-icon="true">
19
19
  <VPIconEdit class="edit-link-icon" />
@@ -39,7 +39,7 @@ const control = usePrevNext()
39
39
  </template>
40
40
 
41
41
  <style scoped>
42
- .VPContentDocFooter {
42
+ .VPDocFooter {
43
43
  margin-top: 64px;
44
44
  }
45
45
 
@@ -94,6 +94,7 @@ const control = usePrevNext()
94
94
  }
95
95
 
96
96
  .pager.has-prev {
97
+ padding-top: 0;
97
98
  padding-left: 16px;
98
99
  }
99
100
  }
@@ -1,10 +1,16 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed } from 'vue'
3
3
  import { useData } from 'vitepress'
4
- import { resolveHeaders, useActiveAnchor } from '../composables/outline'
4
+ import {
5
+ resolveHeaders,
6
+ useOutline,
7
+ useActiveAnchor
8
+ } from '../composables/outline'
5
9
 
6
10
  const { page, frontmatter } = useData()
7
11
 
12
+ const { hasOutline } = useOutline()
13
+
8
14
  const container = ref()
9
15
  const marker = ref()
10
16
 
@@ -22,7 +28,7 @@ function handleClick({ target: el }: Event) {
22
28
  </script>
23
29
 
24
30
  <template>
25
- <div class="VPContentDocOutline" ref="container">
31
+ <div class="VPDocOutline" :class="{ 'has-outline': hasOutline }" ref="container">
26
32
  <div class="outline-marker" ref="marker" />
27
33
 
28
34
  <div class="outline-title">On this page</div>
@@ -54,14 +60,19 @@ function handleClick({ target: el }: Event) {
54
60
  </template>
55
61
 
56
62
  <style scoped>
57
- .VPContentDocOutline {
63
+ .VPDocOutline {
58
64
  position: relative;
65
+ display: none;
59
66
  border-left: 1px solid var(--vp-c-divider-light);
60
67
  padding-left: 16px;
61
68
  font-size: 13px;
62
69
  font-weight: 500;
63
70
  }
64
71
 
72
+ .VPDocOutline.has-outline {
73
+ display: block;
74
+ }
75
+
65
76
  .outline-marker {
66
77
  position: absolute;
67
78
  top: 32px;