diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 99175da7..e2aa7800 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -6,19 +6,11 @@ export default defineConfig({
description: 'Vite & Vue powered static site generator.',
themeConfig: {
- nav: [
- { text: 'Guide', link: '/guide/what-is-vitepress' },
- { text: 'Configs', link: '/config/app-configs' },
- {
- text: 'Release Notes',
- link: 'https://github.com/vuejs/vitepress/releases'
- }
- ],
+ nav: nav(),
sidebar: {
- '/guide/': getGuideSidebar(),
- '/config/': getConfigSidebar(),
- // '/': getGuideSidebar()
+ '/guide/': sidebarGuide(),
+ '/config/': sidebarConfig()
},
editLink: {
@@ -32,6 +24,11 @@ export default defineConfig({
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
+ footer: {
+ message: 'Released under the MIT License.',
+ copyright: 'Copyright © 2019-present Evan You'
+ },
+
algolia: {
appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd',
@@ -40,16 +37,40 @@ export default defineConfig({
}
})
-function getGuideSidebar() {
+function nav() {
+ return [
+ { text: 'Guide', link: '/guide/what-is-vitepress' },
+ { text: 'Configs', link: '/config/introduction' },
+ {
+ text: 'Release Notes',
+ link: 'https://github.com/vuejs/vitepress/releases'
+ }
+ ]
+}
+
+function sidebarGuide() {
return [
{
text: 'Introduction',
items: [{ text: 'What is VitePress?', link: '/guide/what-is-vitepress' }]
+ },
+ {
+ text: 'Migrations',
+ items: [
+ {
+ text: 'Migration from VuePress',
+ link: '/guide/migration-from-vuepress'
+ },
+ {
+ text: 'Migration from VitePress 0.x',
+ link: '/guide/migration-from-vitepress-0'
+ }
+ ]
}
]
}
-function getConfigSidebar() {
+function sidebarConfig() {
return [
{
text: 'Config',
diff --git a/docs/config/app-configs.md b/docs/config/app-configs.md
index d3092f20..2b85ce90 100644
--- a/docs/config/app-configs.md
+++ b/docs/config/app-configs.md
@@ -71,7 +71,7 @@ export default {
- Type: `boolean`
- Default: `true`
-Whether to enable "Dark Mode" or not. If the option is set to `true`, it adds `.dark` class to the `` tag.
+Whether to enable "Dark Mode" or not. If the option is set to `true`, it adds `.dark` class to the `` tag depending on the users preference.
It also injects inline script that tries to read users settings from local storage by `vitepress-theme-appearance` key and restores users preferred color mode.
diff --git a/docs/config/frontmatter-configs.md b/docs/config/frontmatter-configs.md
index 1419f9e0..a8834a67 100644
--- a/docs/config/frontmatter-configs.md
+++ b/docs/config/frontmatter-configs.md
@@ -72,18 +72,80 @@ hero:
name: VuePress
text: Vite & Vue powered static site generator.
tagline: Lorem ipsum...
+ actions:
+ - theme: brand
+ text: Get Started
+ link: /guide/what-is-vitepress
+ - theme: alt
+ text: View on GitHub
+ link: https://github.com/vuejs/vitepress
---
```
```ts
interface Hero {
- // The string shown top of `text`. Best used for product name.
- name: string
+ // The string shown top of `text`. Comes with brand color
+ // and expected to be short, such as product name.
+ name?: string
- // The main text for the hero section. This will be defined as `h1`.
+ // The main text for the hero section. This will be defined
+ // as `h1` tag.
text: string
// Tagline displayed below `text`.
- tagline: string
+ tagline?: string
+
+ // Action buttons to display in home hero section.
+ actions?: HeroAction[]
+}
+
+interface HeroAction {
+ // Color theme of the button. Defaults to `brand`.
+ theme?: 'brand' | 'alt'
+
+ // Label of the button.
+ text: string
+
+ // Destination link of the button.
+ link: string
+}
+```
+
+## features
+
+- Type: `Feature[]`
+
+This option only take effect when `layout` is set to `home`.
+
+It defines items to display in features section.
+
+```yaml
+---
+layout: home
+
+features:
+ - icon: ⚡️
+ title: Vite, The DX that can't be beat
+ details: Lorem ipsum...
+ - icon: 🖖
+ title: Power of Vue meets Markdown
+ details: Lorem ipsum...
+ - icon: 🛠️
+ title: Simple and minimal, always
+ details: Lorem ipsum...
+---
+```
+
+```ts
+interface Feature {
+ // Show icon on each feature box. Currently, only emojis
+ // are supported.
+ icon?: string
+
+ // Title of the feature.
+ title: string
+
+ // Details of the feature.
+ details: string
}
```
diff --git a/docs/config/theme-configs.md b/docs/config/theme-configs.md
index 3bd5693f..e30843f8 100644
--- a/docs/config/theme-configs.md
+++ b/docs/config/theme-configs.md
@@ -1,3 +1,58 @@
# Theme Configs
-Coming soon...
+Theme configs let you customize your theme. You can define theme configs by adding `themeConfig` key to the config file.
+
+```ts
+export default {
+ lang: 'en-US',
+ title: 'VitePress',
+ description: 'Vite & Vue powered static site generator.',
+
+ // Theme related configurations.
+ themeConfig: {
+ logo: '/logo.svg',
+ nav: [...],
+ sidebar: { ... }
+ }
+}
+```
+
+Here it describes the settings for the VitePress default theme. If you're using a custom theme created by others, these settings may not have any effect, or might behave differently.
+
+## logo
+
+- Type: `string`
+
+Logo file to display in nav bar, right before the site title.
+
+```ts
+export default {
+ themeConfig: {
+ logo: '/logo.svg'
+ }
+}
+```
+
+## footer
+
+- Type: `Footer`
+
+Footer configuration. You can add a message and copyright. The footer will displayed only when the page doesn't contain sidebar due to design reason.
+
+```ts
+export default {
+ themeConfig: {
+ footer: {
+ message: 'Released under the MIT License.',
+ copyright: 'Copyright © 2019-present Evan You'
+ }
+ }
+}
+```
+
+```ts
+export interface Footer {
+ message?: string
+ copyright?: string
+}
+```
diff --git a/docs/guide/migration-from-vitepress-0.md b/docs/guide/migration-from-vitepress-0.md
new file mode 100644
index 00000000..038a31e7
--- /dev/null
+++ b/docs/guide/migration-from-vitepress-0.md
@@ -0,0 +1,3 @@
+# Migration from VitePress 0.x
+
+Coming soon...
diff --git a/docs/guide/migration-from-vuepress.md b/docs/guide/migration-from-vuepress.md
new file mode 100644
index 00000000..75faf43a
--- /dev/null
+++ b/docs/guide/migration-from-vuepress.md
@@ -0,0 +1,3 @@
+# Migration from VuePress
+
+Coming soon...
diff --git a/docs/index.md b/docs/index.md
index e8122241..3a95aca1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -2,7 +2,24 @@
layout: home
hero:
- name: VuePress
+ name: VitePress
text: Vite & Vue powered static site generator.
- tagline: Simple, minimal, yet powerful as lightning. Meet the modern SSG framework you've always wanted.
+ tagline: Simple, minimal, yet strikingly powerful. Meet the modern SSG framework you've always wanted.
+ actions:
+ - theme: brand
+ text: Get Started
+ link: /guide/what-is-vitepress
+ - theme: alt
+ text: View on GitHub
+ link: https://github.com/vuejs/vitepress
+
+features:
+ - title: Vite, The DX that can't be beat
+ details: Feel the speed of Vite. Instant server start and lightning fast HMR that stays fast regardless of the app size.
+ - title: Power of Vue meets Markdown
+ details: Enjoy the outstanding feature set of Vue Component in markdown, and develop custom themes with Vue.
+ - title: Simple and minimal, always
+ details: The project structure that helps you focus on writing, yet fully customizable for any website development.
+ - title: Fully static, but dynammic
+ details: Go wild with the true SSG + SPA architecture. Static on the page load, engage users with 100% interactive from there.
---
diff --git a/src/client/theme-default/Layout.vue b/src/client/theme-default/Layout.vue
index a890b801..321b3b88 100644
--- a/src/client/theme-default/Layout.vue
+++ b/src/client/theme-default/Layout.vue
@@ -7,6 +7,7 @@ import VPNav from './components/VPNav.vue'
import VPLocalNav from './components/VPLocalNav.vue'
import VPSidebar from './components/VPSidebar.vue'
import VPContent from './components/VPContent.vue'
+import VPFooter from './components/VPFooter.vue'
const {
isOpen: isSidebarOpen,
@@ -26,6 +27,22 @@ provide('close-sidebar', closeSidebar)
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPBackdrop.vue b/src/client/theme-default/components/VPBackdrop.vue
index b19239d5..1aa5d0b1 100644
--- a/src/client/theme-default/components/VPBackdrop.vue
+++ b/src/client/theme-default/components/VPBackdrop.vue
@@ -17,7 +17,7 @@ defineProps<{
right: 0;
bottom: 0;
left: 0;
- z-index: var(--vp-z-backdrop);
+ z-index: var(--vp-z-index-backdrop);
background: rgba(0, 0, 0, .6);
transition: opacity 0.5s;
}
diff --git a/src/client/theme-default/components/VPBox.vue b/src/client/theme-default/components/VPBox.vue
new file mode 100644
index 00000000..d1a4b4ae
--- /dev/null
+++ b/src/client/theme-default/components/VPBox.vue
@@ -0,0 +1,59 @@
+
+
+
+
+ {{ icon }}
+ {{ title }}
+ {{ details }}
+
+
+
+
diff --git a/src/client/theme-default/components/VPButton.vue b/src/client/theme-default/components/VPButton.vue
new file mode 100644
index 00000000..17d3aecd
--- /dev/null
+++ b/src/client/theme-default/components/VPButton.vue
@@ -0,0 +1,123 @@
+
+
+
+
+ {{ text }}
+
+
+
+
diff --git a/src/client/theme-default/components/VPContent.vue b/src/client/theme-default/components/VPContent.vue
index f09be8bf..9a93b63c 100644
--- a/src/client/theme-default/components/VPContent.vue
+++ b/src/client/theme-default/components/VPContent.vue
@@ -15,21 +15,38 @@ const { hasSidebar } = useSidebar()
+
-
+
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPHero.vue b/src/client/theme-default/components/VPHero.vue
new file mode 100644
index 00000000..89258050
--- /dev/null
+++ b/src/client/theme-default/components/VPHero.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
{{ name }}
+
{{ text }}
+
{{ tagline }}
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPHome.vue b/src/client/theme-default/components/VPHome.vue
index da120e7c..12e85c39 100644
--- a/src/client/theme-default/components/VPHome.vue
+++ b/src/client/theme-default/components/VPHome.vue
@@ -1,9 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPHomeFeatures.vue b/src/client/theme-default/components/VPHomeFeatures.vue
new file mode 100644
index 00000000..b0248cf4
--- /dev/null
+++ b/src/client/theme-default/components/VPHomeFeatures.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPHomeHero.vue b/src/client/theme-default/components/VPHomeHero.vue
index 0899ade0..1e98618b 100644
--- a/src/client/theme-default/components/VPHomeHero.vue
+++ b/src/client/theme-default/components/VPHomeHero.vue
@@ -1,106 +1,17 @@
-
-
{{ fm.hero.name }}
-
{{ fm.hero.text }}
-
{{ fm.hero.tagline }}
-
+
-
-
diff --git a/src/client/theme-default/components/VPHomeSponsors.vue b/src/client/theme-default/components/VPHomeSponsors.vue
new file mode 100644
index 00000000..86173ee4
--- /dev/null
+++ b/src/client/theme-default/components/VPHomeSponsors.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPNavBarSearch.vue b/src/client/theme-default/components/VPNavBarSearch.vue
index 3359fc49..227dfba4 100644
--- a/src/client/theme-default/components/VPNavBarSearch.vue
+++ b/src/client/theme-default/components/VPNavBarSearch.vue
@@ -3,9 +3,9 @@ import '@docsearch/css'
import { useData } from 'vitepress'
import { defineAsyncComponent, ref, onMounted, onUnmounted } from 'vue'
-const VPAlgoliaSearchBox = defineAsyncComponent(
- () => import('./VPAlgoliaSearchBox.vue')
-)
+const VPAlgoliaSearchBox = defineAsyncComponent(() => {
+ return import('./VPAlgoliaSearchBox.vue')
+})
const { theme } = useData()
diff --git a/src/client/theme-default/components/VPSponsors.vue b/src/client/theme-default/components/VPSponsors.vue
new file mode 100644
index 00000000..fe90add9
--- /dev/null
+++ b/src/client/theme-default/components/VPSponsors.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/components/VPSponsorsGrid.vue b/src/client/theme-default/components/VPSponsorsGrid.vue
new file mode 100644
index 00000000..68790653
--- /dev/null
+++ b/src/client/theme-default/components/VPSponsorsGrid.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
diff --git a/src/client/theme-default/components/icons/VPIconHeart.vue b/src/client/theme-default/components/icons/VPIconHeart.vue
new file mode 100644
index 00000000..d408828f
--- /dev/null
+++ b/src/client/theme-default/components/icons/VPIconHeart.vue
@@ -0,0 +1,5 @@
+
+
+
diff --git a/src/client/theme-default/composables/outline.ts b/src/client/theme-default/composables/outline.ts
index f1ce455a..460e5ca8 100644
--- a/src/client/theme-default/composables/outline.ts
+++ b/src/client/theme-default/composables/outline.ts
@@ -1,6 +1,7 @@
import { Ref, onMounted, onUpdated, onUnmounted } from 'vue'
import { Header } from 'vitepress'
import { useMediaQuery } from '@vueuse/core'
+import { throttleAndDebounce } from '../support/utils'
interface HeaderWithChildren extends Header {
children?: Header[]
@@ -162,24 +163,3 @@ function isAnchorActive(
return [false, null]
}
-
-function throttleAndDebounce(fn: () => void, delay: number): () => void {
- let timeout: number
- let called = false
-
- return () => {
- if (timeout) {
- clearTimeout(timeout)
- }
-
- if (!called) {
- fn()
- called = true
- setTimeout(() => {
- called = false
- }, delay)
- } else {
- timeout = setTimeout(fn, delay)
- }
- }
-}
diff --git a/src/client/theme-default/composables/sponsor-grid.ts b/src/client/theme-default/composables/sponsor-grid.ts
new file mode 100644
index 00000000..cd356c74
--- /dev/null
+++ b/src/client/theme-default/composables/sponsor-grid.ts
@@ -0,0 +1,130 @@
+import { Ref, onMounted, onUnmounted } from 'vue'
+import { throttleAndDebounce } from '../support/utils'
+
+export interface GridSetting {
+ [size: string]: [number, number][]
+}
+
+export type GridSize = 'small' | 'medium' | 'big'
+
+export interface UseSponsorsGridOprions {
+ el: Ref
+ size: GridSize
+}
+
+/**
+ * Defines grid configuration for each sponsor size in touple.
+ *
+ * [Screen widh, Column size]
+ *
+ * It sets grid size on matching screen size. For example, `[768, 5]` will set
+ * 5 columns when screen size is bigger or equal to 768px.
+ *
+ * Column will set only when item size is bigger than the column size. For
+ * example, even we want 5 columns, if we only have 1 sponsor yet, we would
+ * like to show it in 1 column.
+ */
+const GridSettings: GridSetting = {
+ small: [
+ [920, 6],
+ [768, 5],
+ [640, 4],
+ [480, 3],
+ [0, 2]
+ ],
+ medium: [
+ [960, 5],
+ [832, 4],
+ [640, 3],
+ [480, 2]
+ ],
+ big: [
+ [832, 3],
+ [640, 2]
+ ]
+}
+
+export function useSponsorsGrid(options: UseSponsorsGridOprions) {
+ const onResize = throttleAndDebounce(manage, 100)
+
+ onMounted(() => {
+ manage()
+ window.addEventListener('resize', onResize)
+ })
+
+ onUnmounted(() => {
+ window.removeEventListener('resize', onResize)
+ })
+
+ function manage() {
+ adjustSlots(options.el.value!, options.size)
+ }
+}
+
+function adjustSlots(el: HTMLElement, size: GridSize) {
+ const tsize = el.children.length
+ const asize = el.querySelectorAll('.vp-sponsor-grid-item:not(.empty)').length
+
+ const grid = setGrid(el, size, asize)
+
+ manageSlots(el, grid, tsize, asize)
+}
+
+function setGrid(el: HTMLElement, size: GridSize, items: number) {
+ const settings = GridSettings[size]
+ const screen = window.innerWidth
+
+ let grid = 1
+
+ settings.some(([breakpoint, value]) => {
+ if (screen >= breakpoint) {
+ grid = items < value ? items : value
+ return true
+ }
+ })
+
+ setGridData(el, grid)
+
+ return grid
+}
+
+function setGridData(el: HTMLElement, value: number) {
+ el.dataset.vpGrid = String(value)
+}
+
+function manageSlots(
+ el: HTMLElement,
+ grid: number,
+ tsize: number,
+ asize: number
+) {
+ const diff = tsize - asize
+ const rem = asize % grid
+ const drem = rem === 0 ? rem : grid - rem
+
+ neutralizeSlots(el, drem - diff)
+}
+
+function neutralizeSlots(el: HTMLElement, count: number) {
+ if (count === 0) {
+ return
+ }
+
+ count > 0 ? addSlots(el, count) : removeSlots(el, count * -1)
+}
+
+function addSlots(el: HTMLElement, count: number) {
+ for (let i = 0; i < count; i++) {
+ const slot = document.createElement('div')
+
+ slot.classList.add('vp-sponsor-grid-item', 'empty')
+
+ el.append(slot)
+ }
+}
+
+function removeSlots(el: HTMLElement, count: number) {
+ for (let i = 0; i < count; i++) {
+ el.removeChild(el.lastElementChild!)
+ }
+}
diff --git a/src/client/theme-default/index.ts b/src/client/theme-default/index.ts
index c3d43d7a..ca744086 100644
--- a/src/client/theme-default/index.ts
+++ b/src/client/theme-default/index.ts
@@ -3,6 +3,7 @@ import './styles/vars.css'
import './styles/base.css'
import './styles/utils.css'
import './styles/vp-doc.css'
+import './styles/vp-sponsor.css'
import { Theme } from 'vitepress'
import Layout from './Layout.vue'
@@ -10,6 +11,10 @@ import NotFound from './NotFound.vue'
export { DefaultTheme } from './config'
+export { default as VPHomeHero } from './components/VPHomeHero.vue'
+export { default as VPHomeFeatures } from './components/VPHomeFeatures.vue'
+export { default as VPHomeSponsors } from './components/VPHomeSponsors.vue'
+
const theme: Theme = {
Layout,
NotFound
diff --git a/src/client/theme-default/styles/vars.css b/src/client/theme-default/styles/vars.css
index fe6e2a5d..0ec0581d 100644
--- a/src/client/theme-default/styles/vars.css
+++ b/src/client/theme-default/styles/vars.css
@@ -52,6 +52,9 @@
--vp-c-indigo: #213547;
--vp-c-indigo-soft: #476582;
--vp-c-indigo-light: #aac8e4;
+ --vp-c-indigo-lighter: #c9def1;
+ --vp-c-indigo-dark: #1d2f3f;
+ --vp-c-indigo-darker: #14212e;
--vp-c-blue: #3b8eed;
--vp-c-blue-light: #549ced;
@@ -109,7 +112,11 @@
--vp-c-brand: var(--vp-c-green);
--vp-c-brand-light: var(--vp-c-green-light);
+ --vp-c-brand-lighter: var(--vp-c-green-lighter);
--vp-c-brand-dark: var(--vp-c-green-dark);
+ --vp-c-brand-darker: var(--vp-c-green-darker);
+
+ --vp-c-sponsor: #fd1d7c;
}
.dark {
@@ -168,8 +175,9 @@
:root {
--vp-z-index-local-nav: 10;
--vp-z-index-nav: 20;
- --vp-z-backdrop: 30;
+ --vp-z-index-backdrop: 30;
--vp-z-index-sidebar: 40;
+ --vp-z-index-footer: 50;
}
/**
@@ -221,13 +229,71 @@
}
/**
- * Component: Home
+ * Component: Button
* -------------------------------------------------------------------------- */
:root {
-
+ --vp-button-brand-border: var(--vp-c-brand-light);
+ --vp-button-brand-text: var(--vp-c-text-dark-1);
+ --vp-button-brand-bg: var(--vp-c-brand);
+ --vp-button-brand-hover-border: var(--vp-c-brand-light);
+ --vp-button-brand-hover-text: var(--vp-c-text-dark-1);
+ --vp-button-brand-hover-bg: var(--vp-c-brand-light);
+ --vp-button-brand-active-border: var(--vp-c-brand-light);
+ --vp-button-brand-active-text: var(--vp-c-text-dark-1);
+ --vp-button-brand-active-bg: var(--vp-button-brand-bg);
+
+ --vp-button-alt-border: var(--vp-c-gray-light-3);
+ --vp-button-alt-text: var(--vp-c-text-light-1);
+ --vp-button-alt-bg: var(--vp-c-gray-light-5);
+ --vp-button-alt-hover-border: var(--vp-c-gray-light-3);
+ --vp-button-alt-hover-text: var(--vp-c-text-light-1);
+ --vp-button-alt-hover-bg: var(--vp-c-gray-light-4);
+ --vp-button-alt-active-border: var(--vp-c-gray-light-3);
+ --vp-button-alt-active-text: var(--vp-c-text-light-1);
+ --vp-button-alt-active-bg: var(--vp-c-gray-light-3);
+
+ --vp-button-sponsor-border: var(--vp-c-gray-light-3);
+ --vp-button-sponsor-text: var(--vp-c-text-light-2);
+ --vp-button-sponsor-bg: transparent;
+ --vp-button-sponsor-hover-border: var(--vp-c-sponsor);
+ --vp-button-sponsor-hover-text: var(--vp-c-sponsor);
+ --vp-button-sponsor-hover-bg: transparent;
+ --vp-button-sponsor-active-border: var(--vp-c-sponsor);
+ --vp-button-sponsor-active-text: var(--vp-c-sponsor);
+ --vp-button-sponsor-active-bg: transparent;
}
.dark {
+ --vp-button-brand-border: var(--vp-c-brand-lighter);
+ --vp-button-brand-text: var(--vp-c-text-light-1);
+ --vp-button-brand-bg: var(--vp-c-brand-light);
+ --vp-button-brand-hover-border: var(--vp-c-brand-lighter);
+ --vp-button-brand-hover-text: var(--vp-c-text-light-1);
+ --vp-button-brand-hover-bg: var(--vp-c-brand-lighter);
+ --vp-button-brand-active-border: var(--vp-c-brand-lighter);
+ --vp-button-brand-active-text: var(--vp-c-text-light-1);
+ --vp-button-brand-active-bg: var(--vp-button-brand-bg);
+
+ --vp-button-alt-border: var(--vp-c-gray-dark-2);
+ --vp-button-alt-text: var(--vp-c-text-dark-1);
+ --vp-button-alt-bg: var(--vp-c-bg-mute);
+ --vp-button-alt-hover-border: var(--vp-c-gray-dark-2);
+ --vp-button-alt-hover-text: var(--vp-c-text-dark-1);
+ --vp-button-alt-hover-bg: var(--vp-c-gray-dark-3);
+ --vp-button-alt-active-border: var(--vp-c-gray-dark-2);
+ --vp-button-alt-active-text: var(--vp-c-text-dark-1);
+ --vp-button-alt-active-bg: var(--vp-button-alt-bg);
+
+ --vp-button-sponsor-border: var(--vp-c-gray-dark-1);
+ --vp-button-sponsor-text: var(--vp-c-text-dark-2);
+}
+/**
+ * Component: Home
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-home-hero-name-color: var(--vp-c-brand);
+ --vp-home-hero-name-background: transparent;
}
diff --git a/src/client/theme-default/styles/vp-doc.css b/src/client/theme-default/styles/vp-doc.css
index 44f79bf5..e664afbc 100644
--- a/src/client/theme-default/styles/vp-doc.css
+++ b/src/client/theme-default/styles/vp-doc.css
@@ -221,7 +221,7 @@
@media (min-width: 640px) {
.vp-doc div[class*='language-'] {
border-radius: 8px;
- margin: 20px 0;
+ margin: 24px 0;
}
}
diff --git a/src/client/theme-default/styles/vp-sponsor.css b/src/client/theme-default/styles/vp-sponsor.css
new file mode 100644
index 00000000..877e0216
--- /dev/null
+++ b/src/client/theme-default/styles/vp-sponsor.css
@@ -0,0 +1,86 @@
+.vp-sponsor-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+}
+
+.vp-sponsor-grid.small .vp-sponsor-grid-link { height: 96px; }
+.vp-sponsor-grid.small .vp-sponsor-grid-image { max-width: 96px; max-height: 24px }
+
+.vp-sponsor-grid.medium .vp-sponsor-grid-link { height: 112px; }
+.vp-sponsor-grid.medium .vp-sponsor-grid-image { max-width: 120px; max-height: 36px }
+
+.vp-sponsor-grid.big .vp-sponsor-grid-link { height: 184px; }
+.vp-sponsor-grid.big .vp-sponsor-grid-image { max-width: 192px; max-height: 56px }
+
+.vp-sponsor-grid[data-vp-grid="2"] .vp-sponsor-grid-item {
+ width: calc((100% - 4px) / 2);
+}
+
+.vp-sponsor-grid[data-vp-grid="3"] .vp-sponsor-grid-item {
+ width: calc((100% - 4px * 2) / 3);
+}
+
+.vp-sponsor-grid[data-vp-grid="4"] .vp-sponsor-grid-item {
+ width: calc((100% - 4px * 3) / 4);
+}
+
+.vp-sponsor-grid[data-vp-grid="5"] .vp-sponsor-grid-item {
+ width: calc((100% - 4px * 4) / 5);
+}
+
+.vp-sponsor-grid[data-vp-grid="6"] .vp-sponsor-grid-item {
+ width: calc((100% - 4px * 5) / 6);
+}
+
+.vp-sponsor-grid-item {
+ flex-shrink: 0;
+ width: 100%;
+ background-color: var(--vp-c-white-soft);
+ transition: background-color 0.25s;
+}
+
+.vp-sponsor-grid-item:hover {
+ background-color: var(--vp-c-white-mute);
+}
+
+.vp-sponsor-grid-item:hover .vp-sponsor-grid-image {
+ filter: grayscale(0) invert(0);
+}
+
+.vp-sponsor-grid-item.empty:hover {
+ background-color: var(--vp-c-white-soft);
+}
+
+.dark .vp-sponsor-grid-item {
+ background-color: var(--vp-c-black-mute);
+}
+
+.dark .vp-sponsor-grid-item:hover {
+ background-color: var(--vp-c-white-soft);
+}
+
+.dark .vp-sponsor-grid-item.empty:hover {
+ background-color: var(--vp-c-black-mute);
+}
+
+.vp-sponsor-grid-link {
+ display: flex;
+}
+
+.vp-sponsor-grid-box {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+}
+
+.vp-sponsor-grid-image {
+ max-width: 100%;
+ filter: grayscale(1);
+ transition: filter 0.25s;
+}
+
+.dark .vp-sponsor-grid-image {
+ filter: grayscale(1) invert(1);
+}
diff --git a/src/client/theme-default/support/utils.ts b/src/client/theme-default/support/utils.ts
index bc99d224..be2a39c8 100644
--- a/src/client/theme-default/support/utils.ts
+++ b/src/client/theme-default/support/utils.ts
@@ -12,6 +12,27 @@ export function isExternal(path: string): boolean {
return OUTBOUND_RE.test(path)
}
+export function throttleAndDebounce(fn: () => void, delay: number): () => void {
+ let timeout: number
+ let called = false
+
+ return () => {
+ if (timeout) {
+ clearTimeout(timeout)
+ }
+
+ if (!called) {
+ fn()
+ called = true
+ setTimeout(() => {
+ called = false
+ }, delay)
+ } else {
+ timeout = setTimeout(fn, delay)
+ }
+ }
+}
+
export function isActive(
currentPath: string,
matchPath?: string,
diff --git a/types/default-theme.d.ts b/types/default-theme.d.ts
index 2cfd0ea7..ef6d7a9e 100644
--- a/types/default-theme.d.ts
+++ b/types/default-theme.d.ts
@@ -29,6 +29,11 @@ export namespace DefaultTheme {
*/
socialLinks?: SocialLink[]
+ /**
+ * The footer configuration.
+ */
+ footer?: Footer
+
/**
* Adds locale menu to the nav. This option should be used when you have
* your translated sites outside of the project.
@@ -133,6 +138,13 @@ export namespace DefaultTheme {
| 'twitter'
| 'youtube'
+ // footer --------------------------------------------------------------------
+
+ export interface Footer {
+ message?: string
+ copyright?: string
+ }
+
// locales -------------------------------------------------------------------
export interface LocaleLinks {