From c6bdcfbf4f14916f20a7192b44941d33d4bee51e Mon Sep 17 00:00:00 2001 From: Matias Capeletto Date: Thu, 26 Nov 2020 11:49:41 +0100 Subject: [PATCH] feat!: add more global and computed properties (#152) BREAKING CHANGE: `$theme` global computed is renamed to `$themeConfig` to align better with VuePress. Co-authored-by: Kia King Ishii --- docs/.vitepress/config.js | 1 + docs/guide/frontmatter.md | 4 +- docs/guide/global-computed.md | 73 +++++++++++++++++++ src/client/app/index.ts | 21 +++++- .../theme-default/components/NavBarTitle.vue | 13 +--- src/node/markdownToVue.ts | 26 ++++++- types/shared.d.ts | 5 +- 7 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 docs/guide/global-computed.md diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 10e44a51..ca10e3c7 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -44,6 +44,7 @@ function getGuideSidebar() { text: 'Advanced', children: [ { text: 'Frontmatter', link: '/guide/frontmatter' }, + { text: 'Global Computed', link: '/guide/global-computed' }, { text: 'Customization', link: '/guide/customization' } ] } diff --git a/docs/guide/frontmatter.md b/docs/guide/frontmatter.md index 3c6fb5d3..71f28bee 100644 --- a/docs/guide/frontmatter.md +++ b/docs/guide/frontmatter.md @@ -9,7 +9,7 @@ editLink: true --- ``` -Between the triple-dashed lines, you can set [predefined variables](#predefined-variables), or even create custom ones of your own. These variables can be used via the \$page.frontmatter variable. +Between the triple-dashed lines, you can set [predefined variables](#predefined-variables), or even create custom ones of your own. These variables can be used via the $frontmatter variable. Here’s an example of how you could use it in your Markdown file: @@ -19,7 +19,7 @@ title: Docs with VitePress editLink: true --- -# {{ $page.frontmatter.title }} +# {{ $frontmatter.title }} Guide content ``` diff --git a/docs/guide/global-computed.md b/docs/guide/global-computed.md new file mode 100644 index 00000000..7221534a --- /dev/null +++ b/docs/guide/global-computed.md @@ -0,0 +1,73 @@ +# Global Computed + +In VitePress, some core [computed properties](https://v3.vuejs.org/guide/computed.html#computed-properties) can be used by the default theme or custom themes. Or directly in Markdown pages using vue, for example using `$frontmatter.title` to access the title defined in the frontmatter section of the page. + +## $site + +This is the `$site` value of the site you're currently reading: + +```js +{ + base: '/', + lang: 'en-US', + title: 'VitePress', + description: 'Vite & Vue powered static site generator.', + head: [], + locales: {}, + themeConfig: $themeConfig +} +``` + +## $themeConfig + +Refers to `$site.themeConfig`. + +```js +{ + locales: {}, + repo: 'vuejs/vitepress', + docsDir: 'docs', + editLinks: true, + editLinkText: 'Edit this page on GitHub', + lastUpdated: 'Last Updated', + nav: [...], + sidebar: { ... } +} +``` + +## $page + +This is the `$page` value of the page you're currently reading: + +```js +{ + relativePath: 'guide/global-computed.md', + title: 'Global Computed', + headers: [ + { level: 2, title: '$site', slug: 'site' }, + { level: 2, title: '$page', slug: '$page' }, + ... + ], + frontmatter: $frontmatter, + lastUpdated: 1606297645000 +} +``` + +## $frontmatter + +Reference of `$page.frontmatter`. + +```js +{ + title: 'Docs with VitePress', + editLink: true +} +``` + +## $title + +Value of the `` label used for the current page. + +## $description + +The content value of the `<meta name= "description" content= "...">` for the current page. diff --git a/src/client/app/index.ts b/src/client/app/index.ts index f3eaa170..5ae7de79 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -82,14 +82,31 @@ export function createApp() { return siteDataByRouteRef.value } }, + $themeConfig: { + get() { + return siteDataByRouteRef.value.themeConfig + } + }, $page: { get() { return router.route.data } }, - $theme: { + $frontmatter: { get() { - return siteDataByRouteRef.value.themeConfig + return router.route.data.frontmatter + } + }, + $title: { + get() { + return router.route.data.title || siteDataByRouteRef.value.title + } + }, + $description: { + get() { + return ( + router.route.data.description || siteDataByRouteRef.value.description + ) } } }) diff --git a/src/client/theme-default/components/NavBarTitle.vue b/src/client/theme-default/components/NavBarTitle.vue index bafdc6c7..124560b6 100644 --- a/src/client/theme-default/components/NavBarTitle.vue +++ b/src/client/theme-default/components/NavBarTitle.vue @@ -5,24 +5,17 @@ :aria-label="`${$site.title}, back to home`" > <img - v-if="$theme.logo" + v-if="$themeConfig.logo" class="logo" - :src="withBase($theme.logo)" + :src="withBase($themeConfig.logo)" alt="Logo" /> {{ $site.title }} </a> </template> -<script lang="ts"> -import { defineComponent } from 'vue' +<script setup lang="ts"> import { withBase } from '../utils' - -export default defineComponent({ - setup() { - return { withBase } - } -}) </script> <style scoped> diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts index 86be2ec3..55a48f61 100644 --- a/src/node/markdownToVue.ts +++ b/src/node/markdownToVue.ts @@ -3,7 +3,7 @@ import matter from 'gray-matter' import LRUCache from 'lru-cache' import { createMarkdownRenderer, MarkdownOptions } from './markdown/markdown' import { deeplyParseHeader } from './utils/parseHeader' -import { PageData } from '../../types/shared' +import { PageData, HeadConfig } from '../../types/shared' const debug = require('debug')('vitepress:md') const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 }) @@ -41,6 +41,7 @@ export function createMarkdownToVueRenderFn( // inject page data const pageData: PageData = { title: inferTitle(frontmatter, content), + description: inferDescription(frontmatter), frontmatter, headers: data.headers, relativePath: file.replace(/\\/g, '/'), @@ -106,3 +107,26 @@ const inferTitle = (frontmatter: any, content: string) => { } return '' } + +const inferDescription = (frontmatter: Record<string, any>) => { + if (!frontmatter.head) { + return '' + } + + return getHeadMetaContent(frontmatter.head, 'description') || '' +} + +const getHeadMetaContent = ( + head: HeadConfig[], + name: string +): string | undefined => { + if (!head || !head.length) { + return undefined + } + + const meta = head.find(([tag, attrs = {}]) => { + return tag === 'meta' && attrs.name === name && attrs.content + }) + + return meta && meta[1].content +} diff --git a/types/shared.d.ts b/types/shared.d.ts index 859176f2..8ecfea93 100644 --- a/types/shared.d.ts +++ b/types/shared.d.ts @@ -24,10 +24,11 @@ export type HeadConfig = | [string, Record<string, string>, string] export interface PageData { + relativePath: string title: string - frontmatter: Record<string, any> + description: string headers: Header[] - relativePath: string + frontmatter: Record<string, any> lastUpdated: number }