Merge branch 'main' into next-theme/navigation

pull/741/head
Sacha STAFYNIAK 3 years ago
commit 517dbae215

@ -1,3 +1,7 @@
# [1.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v0.22.4...v1.0.0-alpha.1) (2022-06-01)
Complete rewrite on default theme, with bunch of features added. Please refer to the docs for the new feature and changes.
## [0.22.4](https://github.com/vuejs/vitepress/compare/v0.22.3...v0.22.4) (2022-05-06) ## [0.22.4](https://github.com/vuejs/vitepress/compare/v0.22.3...v0.22.4) (2022-05-06)
### Bug Fixes ### Bug Fixes

@ -16,9 +16,7 @@ export default defineConfig({
}, },
editLink: { editLink: {
repo: 'vuejs/vitepress', pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
branch: 'next',
dir: 'docs',
text: 'Edit this page on GitHub' text: 'Edit this page on GitHub'
}, },

@ -76,6 +76,19 @@ type Head =
| [string, Record<string, string>, string] | [string, Record<string, string>, string]
``` ```
## lastUpdated
- Type: `boolean`
- Default: `true`
Whether to display [Last Updated](../guide/theme-last-updated) text in the current page.
```yaml
---
lastUpdated: false
---
```
## layout ## layout
- Type: `doc | home | page` - Type: `doc | home | page`

@ -188,6 +188,30 @@ export interface Footer {
} }
``` ```
## editLink
- Type: `EditLink`
Edit Link lets you display a link to edit the page on Git management services such as GitHub, or GitLab. See [Theme: Edit Link](../guide/theme-edit-link) for more details.
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edit this page on GitHub'
}
}
}
```
```ts
export interface EditLink {
pattern: string
text?: string
}
```
## lastUpdatedText ## lastUpdatedText
- Type: `string` - Type: `string`

@ -16,7 +16,7 @@ All **static** path references, including absolute paths, should be based on you
## Public Files ## Public Files
Sometimes you may need to provide static assets that are not directly referenced in any of your Markdown or theme components (for example, favicons and PWA icons). The `public` directory under project root can be used as an escape hatch to provide static assets that either are never referenced in source code (e.g. `robots.txt`), or must retain the exact same file name (without hashing). Sometimes you may need to provide static assets that are not directly referenced in any of your Markdown or theme components (for example, favicons and PWA icons). The `public` directory under project root (`docs` folder if you're running `vitepress build docs`) can be used as an escape hatch to provide static assets that either are never referenced in source code (e.g. `robots.txt`), or must retain the exact same file name (without hashing).
Assets placed in `public` will be copied to the root of the dist directory as-is. Assets placed in `public` will be copied to the root of the dist directory as-is.

@ -15,13 +15,13 @@ The essential file for configuring a VitePress site is `.vitepress/config.js`, w
```js ```js
export default { export default {
title: 'Hello VitePress', title: 'VitePress',
description: 'Just playing around.' description: 'Just playing around.'
} }
``` ```
In the above example, the site will have the title of `VitePress`, and `Just playing around` as description meta tag. In the above example, the site will have the title of `VitePress`, and `Just playing around.` as the description meta tag.
Learn everything about VitePress features at [Theme: Introduction](./theme-introduction) to find how to configure specific features with in this config file. Learn everything about VitePress features at [Theme: Introduction](./theme-introduction) to find how to configure specific features within this config file.
You may also find all configuration references at [Configs](../config/introduction). You may also find all configuration references at [Configs](../config/introduction).

@ -34,7 +34,7 @@ $ yarn docs:serve
The `serve` command will boot up local static web server that serves the files from `.vitepress/dist` at `http://localhost:5000`. It's an easy way to check if the production build looks OK in your local environment. The `serve` command will boot up local static web server that serves the files from `.vitepress/dist` at `http://localhost:5000`. It's an easy way to check if the production build looks OK in your local environment.
You may configure the port of the server py passing `--port` flag as an argument. You may configure the port of the server by passing `--port` flag as an argument.
```json ```json
{ {
@ -135,7 +135,7 @@ deploy:
3. Create a file called `.gitlab-ci.yml` in the root of your project with the content below. This will build and deploy your site whenever you make changes to your content: 3. Create a file called `.gitlab-ci.yml` in the root of your project with the content below. This will build and deploy your site whenever you make changes to your content:
```yaml ```yaml
image: node:10.22.0 image: node:16
pages: pages:
cache: cache:
paths: paths:

@ -364,12 +364,12 @@ It also supports [line highlighting](#line-highlighting-in-code-blocks):
The value of `@` corresponds to the source root. By default it's the VitePress project root, unless `srcDir` is configured. The value of `@` corresponds to the source root. By default it's the VitePress project root, unless `srcDir` is configured.
::: :::
You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) to only include the corresponding part of the code file. You can provide a custom region name after a `#` following the filepath (`snippet` by default): You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) to only include the corresponding part of the code file. You can provide a custom region name after a `#` following the filepath:
**Input** **Input**
```md ```md
<<< @/snippets/snippet-with-region.js{1} <<< @/snippets/snippet-with-region.js#snippet{1}
``` ```
**Code file** **Code file**

@ -1,3 +1,28 @@
# Edit Link # Edit Link
Documentation coming soon... Edit Link lets you display a link to edit the page on Git management services such as GitHub, or GitLab. To enable it, add `themeConfig.editLink` options to your config.
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'
}
}
}
```
The `pattern` option defines the URL structure for the link, and `:path` is going to be replaced with the page path.
By default, this will add the link text "Edit this page" at the bottom of the doc page. You may customize this text by defining the `text` option.
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edit this page on GitHub'
}
}
}
```

@ -68,7 +68,7 @@ export default {
## Multiple Sidebars ## Multiple Sidebars
You may show different sidebar depending on the page path. For example, as shown on this site, you might want to create a separate sections of content in your documentation like "Guide" page and `Config` page. You may show different sidebar depending on the page path. For example, as shown on this site, you might want to create a separate sections of content in your documentation like "Guide" page and "Config" page.
To do so, first organize your pages into directories for each desired section: To do so, first organize your pages into directories for each desired section:
@ -92,27 +92,31 @@ export default {
sidebar: { sidebar: {
// This sidebar gets displayed when user is // This sidebar gets displayed when user is
// under `guide` directory. // under `guide` directory.
'/guide/': { '/guide/': [
text: 'Guide', {
items: [ text: 'Guide',
// This shows `/guide/index.md` page. items: [
{ text: 'Index', link: '/guide/' }, // /guide/index.md // This shows `/guide/index.md` page.
{ text: 'One', link: '/guide/one' }, // /guide/one.md { text: 'Index', link: '/guide/' }, // /guide/index.md
{ text: 'Two', link: '/guide/two' } // /guide/two.md { text: 'One', link: '/guide/one' }, // /guide/one.md
] { text: 'Two', link: '/guide/two' } // /guide/two.md
}, ]
}
],
// This sidebar gets displayed when user is // This sidebar gets displayed when user is
// under `config` directory. // under `config` directory.
'/config/': { '/config/': [
text: 'Config', {
items: [ text: 'Config',
// This shows `/guide/index.md` page. items: [
{ text: 'Index', link: '/config/' }, // /config/index.mdasdfasdfasdfasdfaf // This shows `/guide/index.md` page.
{ text: 'Three', link: '/config/three' }, // /config/three.md { text: 'Index', link: '/config/' }, // /config/index.md
{ text: 'Four', link: '/config/four' } // /config/four.md { text: 'Three', link: '/config/three' }, // /config/three.md
] { text: 'Four', link: '/config/four' } // /config/four.md
} ]
}
]
} }
} }
} }

@ -1,6 +1,6 @@
{ {
"name": "vitepress", "name": "vitepress",
"version": "1.0.0-draft.8", "version": "1.0.0-alpha.1",
"description": "Vite & Vue powered static site generator", "description": "Vite & Vue powered static site generator",
"type": "module", "type": "module",
"packageManager": "pnpm@7.1.7", "packageManager": "pnpm@7.1.7",

@ -1,15 +1,20 @@
import { readFileSync, writeFileSync } from 'fs' import { readFileSync, writeFileSync } from 'fs'
import { resolve } from 'path' import { resolve } from 'path'
import { fileURLToPath } from 'url'
import c from 'picocolors' import c from 'picocolors'
import { inc as _inc, valid } from 'semver'
import prompts from 'prompts' import prompts from 'prompts'
import { execa } from 'execa' import { execa } from 'execa'
import { version as currentVersion } from '../package.json' import semver from 'semver'
import { fileURLToPath } from 'url' import pkg from '../package.json' assert { type: 'json' }
const { version: currentVersion } = pkg
const { inc: _inc, valid } = semver
const versionIncrements = ['patch', 'minor', 'major'] const versionIncrements = ['patch', 'minor', 'major']
const dir = dirname(fileURLToPath(import.meta.url)) const tags = ['latest', 'next']
const dir = fileURLToPath(new URL('.', import.meta.url))
const inc = (i) => _inc(currentVersion, i) const inc = (i) => _inc(currentVersion, i)
const run = (bin, args, opts = {}) => const run = (bin, args, opts = {}) =>
execa(bin, args, { stdio: 'inherit', ...opts }) execa(bin, args, { stdio: 'inherit', ...opts })
@ -18,34 +23,45 @@ const step = (msg) => console.log(c.cyan(msg))
async function main() { async function main() {
let targetVersion let targetVersion
const versions = versionIncrements
.map((i) => `${i} (${inc(i)})`)
.concat(['custom'])
const { release } = await prompts({ const { release } = await prompts({
type: 'select', type: 'select',
name: 'release', name: 'release',
message: 'Select release type', message: 'Select release type',
choices: versionIncrements.map((i) => `${i} (${inc(i)})`).concat(['custom']) choices: versions
}) })
console.log(release, release === 3)
if (release === 'custom') { if (release === 3) {
targetVersion = ( targetVersion = (
await prompts({ await prompts({
type: 'input', type: 'text',
name: 'version', name: 'version',
message: 'Input custom version', message: 'Input custom version',
initial: currentVersion initial: currentVersion
}) })
).version ).version
} else { } else {
targetVersion = release.match(/\((.*)\)/)[1] targetVersion = versions[release].match(/\((.*)\)/)[1]
} }
if (!valid(targetVersion)) { if (!valid(targetVersion)) {
throw new Error(`Invalid target version: ${targetVersion}`) throw new Error(`Invalid target version: ${targetVersion}`)
} }
const { tag } = await prompts({
type: 'select',
name: 'tag',
message: 'Select tag type',
choices: tags
})
const { yes: tagOk } = await prompts({ const { yes: tagOk } = await prompts({
type: 'confirm', type: 'confirm',
name: 'yes', name: 'yes',
message: `Releasing v${targetVersion}. Confirm?` message: `Releasing v${targetVersion} on ${tags[tag]}. Confirm?`
}) })
if (!tagOk) { if (!tagOk) {
@ -83,7 +99,13 @@ async function main() {
// Publish the package. // Publish the package.
step('\nPublishing the package...') step('\nPublishing the package...')
await run('pnpm', ['publish', '--ignore-scripts', '--no-git-checks']) await run('pnpm', [
'publish',
'--tag',
tags[tag],
'--ignore-scripts',
'--no-git-checks'
])
// Push to GitHub. // Push to GitHub.
step('\nPushing to GitHub...') step('\nPushing to GitHub...')

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { withBase } from 'vitepress'
const props = defineProps<{ const props = defineProps<{
tag?: string tag?: string
@ -30,7 +31,7 @@ const component = computed(() => {
:is="component" :is="component"
class="VPButton" class="VPButton"
:class="classes" :class="classes"
:href="href" :href="href ? withBase(href) : undefined"
:target="isExternal ? '_blank' : undefined" :target="isExternal ? '_blank' : undefined"
:rel="isExternal ? 'noopener noreferrer' : undefined" :rel="isExternal ? 'noopener noreferrer' : undefined"
> >

@ -1,16 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { useRoute } from 'vitepress'
import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar' import { useSidebar } from '../composables/sidebar'
import VPDocAside from './VPDocAside.vue' import VPDocAside from './VPDocAside.vue'
import VPDocFooter from './VPDocFooter.vue' import VPDocFooter from './VPDocFooter.vue'
const { page } = useData() const { path } = useRoute()
const { hasSidebar } = useSidebar() const { hasSidebar } = useSidebar()
const pageName = computed(() => { const pageName = path.replace(/[./]+/g, '_').replace(/_html$/, '')
return page.value.relativePath.slice(0, page.value.relativePath.indexOf('/'))
})
</script> </script>
<template> <template>

@ -7,7 +7,7 @@ import {
useActiveAnchor useActiveAnchor
} from '../composables/outline' } from '../composables/outline'
const { page, frontmatter } = useData() const { page, frontmatter, theme } = useData()
const { hasOutline } = useOutline() const { hasOutline } = useOutline()
@ -32,7 +32,9 @@ function handleClick({ target: el }: Event) {
<div class="content"> <div class="content">
<div class="outline-marker" ref="marker" /> <div class="outline-marker" ref="marker" />
<div class="outline-title">On this page</div> <div class="outline-title">
{{ theme.outlineTitle || 'On this page' }}
</div>
<nav aria-labelledby="doc-outline-aria-label"> <nav aria-labelledby="doc-outline-aria-label">
<span class="visually-hidden" id="doc-outline-aria-label"> <span class="visually-hidden" id="doc-outline-aria-label">

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { normalizeLink } from '../support/utils' import { normalizeLink } from '../support/utils'
import { useEditLink } from '../composables/edit-link' import { useEditLink } from '../composables/edit-link'
@ -11,6 +12,10 @@ const { theme, page, frontmatter } = useData()
const editLink = useEditLink() const editLink = useEditLink()
const control = usePrevNext() const control = usePrevNext()
const hasLastUpdated = computed(() => {
return page.value.lastUpdated && frontmatter.value.lastUpdated !== false
})
</script> </script>
<template> <template>
@ -23,7 +28,7 @@ const control = usePrevNext()
</VPLink> </VPLink>
</div> </div>
<div v-if="page.lastUpdated" class="last-updated"> <div v-if="hasLastUpdated" class="last-updated">
<VPDocFooterLastUpdated /> <VPDocFooterLastUpdated />
</div> </div>
</div> </div>
@ -58,21 +63,18 @@ const control = usePrevNext()
.edit-info { .edit-info {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: baseline; align-items: center;
padding-bottom: 14px; padding-bottom: 14px;
} }
} }
.edit-link {
line-height: 32px;
font-size: 14px;
font-weight: 500;
}
.edit-link-button { .edit-link-button {
display: flex; display: flex;
align-items: center; align-items: center;
border: 0; border: 0;
line-height: 32px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-brand); color: var(--vp-c-brand);
transition: color 0.25s; transition: color 0.25s;
} }

@ -98,7 +98,7 @@ function onBlur() {
display: flex; display: flex;
align-items: center; align-items: center;
line-height: var(--vp-nav-height-mobile); line-height: var(--vp-nav-height-mobile);
font-size: 13px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: var(--vp-c-text-1); color: var(--vp-c-text-1);
transition: color 0.25s; transition: color 0.25s;

@ -12,6 +12,8 @@ import VPHomeFeatures from './VPHomeFeatures.vue'
<slot name="home-features-before" /> <slot name="home-features-before" />
<VPHomeFeatures /> <VPHomeFeatures />
<slot name="home-features-after" /> <slot name="home-features-after" />
<Content />
</div> </div>
</template> </template>

@ -41,8 +41,13 @@ provide('close-screen', closeScreen)
} }
.VPNav.no-sidebar { .VPNav.no-sidebar {
backdrop-filter: saturate(50%) blur(8px);
-webkit-backdrop-filter: saturate(50%) blur(8px); -webkit-backdrop-filter: saturate(50%) blur(8px);
backdrop-filter: saturate(50%) blur(8px);
background: rgba(255, 255, 255, 0.7);
}
.dark .VPNav.no-sidebar {
background: rgba(36, 36, 36, 0.7);
} }
@supports not (backdrop-filter: saturate(50%) blur(8px)) { @supports not (backdrop-filter: saturate(50%) blur(8px)) {

@ -70,8 +70,15 @@ const { hasSidebar } = useSidebar()
} }
.VPNavBar.has-sidebar .content { .VPNavBar.has-sidebar .content {
backdrop-filter: saturate(50%) blur(8px); margin-right: -32px;
padding-right: 32px;
-webkit-backdrop-filter: saturate(50%) blur(8px); -webkit-backdrop-filter: saturate(50%) blur(8px);
backdrop-filter: saturate(50%) blur(8px);
background: rgba(255, 255, 255, 0.7);
}
.dark .VPNavBar.has-sidebar .content {
background: rgba(36, 36, 36, 0.7);
} }
@supports not (backdrop-filter: saturate(50%) blur(8px)) { @supports not (backdrop-filter: saturate(50%) blur(8px)) {

@ -8,7 +8,7 @@ const { hasSidebar } = useSidebar()
<template> <template>
<div class="VPNavBarTitle" :class="{ 'has-sidebar': hasSidebar }"> <div class="VPNavBarTitle" :class="{ 'has-sidebar': hasSidebar }">
<a class="title" href="/"> <a class="title" :href="site.base">
<slot name="nav-bar-title-before" /> <slot name="nav-bar-title-before" />
<img v-if="theme.logo" class="logo" :src="theme.logo"> <img v-if="theme.logo" class="logo" :src="theme.logo">
<template v-if="theme.siteTitle">{{ theme.siteTitle }}</template> <template v-if="theme.siteTitle">{{ theme.siteTitle }}</template>

@ -6,7 +6,7 @@ import VPIconMinusSquare from './icons/VPIconMinusSquare.vue'
import VPSidebarLink from './VPSidebarLink.vue' import VPSidebarLink from './VPSidebarLink.vue'
const props = defineProps<{ const props = defineProps<{
text: string text?: string
items: DefaultTheme.SidebarItem[] items: DefaultTheme.SidebarItem[]
collapsible?: boolean collapsible?: boolean
collapsed?: boolean collapsed?: boolean
@ -23,7 +23,12 @@ function toggle() {
<template> <template>
<section class="VPSidebarGroup" :class="{ collapsible, collapsed }"> <section class="VPSidebarGroup" :class="{ collapsible, collapsed }">
<div class="title" :role="collapsible ? 'button' : undefined" @click="toggle"> <div
v-if="text"
class="title"
:role="collapsible ? 'button' : undefined"
@click="toggle"
>
<h2 class="title-text">{{ text }}</h2> <h2 class="title-text">{{ text }}</h2>
<div class="action"> <div class="action">
<VPIconMinusSquare class="icon minus" /> <VPIconMinusSquare class="icon minus" />

@ -3,6 +3,7 @@ import { inject } from 'vue'
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { DefaultTheme } from '../config' import { DefaultTheme } from '../config'
import { isActive, normalizeLink } from '../support/utils' import { isActive, normalizeLink } from '../support/utils'
import VPLink from './VPLink.vue'
defineProps<{ defineProps<{
item: DefaultTheme.SidebarItem item: DefaultTheme.SidebarItem
@ -14,37 +15,40 @@ const closeSideBar = inject('close-sidebar') as () => void
</script> </script>
<template> <template>
<a <VPLink
class="link"
:class="{ active: isActive(page.relativePath, item.link) }" :class="{ active: isActive(page.relativePath, item.link) }"
:href="normalizeLink(item.link)" :href="normalizeLink(item.link)"
@click="closeSideBar" @click="closeSideBar"
> >
<p class="link-text">{{ item.text }}</p> <span class="link-text">{{ item.text }}</span>
</a> </VPLink>
</template> </template>
<style scoped> <style scoped>
.link { .link {
display: block; display: block;
padding: 6px 0; padding: 4px 0;
color: var(--vp-c-text-2);
transition: color 0.5s;
} }
.link:hover .link-text { .link:hover {
color: var(--vp-c-text-1); color: var(--vp-c-text-1);
transition: color 0.25s;
} }
.link.active .link-text { .link.active {
color: var(--vp-c-brand); color: var(--vp-c-brand);
transition: color 0.25s; }
.link :deep(.icon) {
width: 12px;
height: 12px;
fill: currentColor;
} }
.link-text { .link-text {
line-height: 20px; line-height: 20px;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: var(--vp-c-text-2);
transition: color 0.5s;
} }
</style> </style>

@ -5,22 +5,10 @@ export function useEditLink() {
const { theme, page } = useData() const { theme, page } = useData()
return computed(() => { return computed(() => {
const url = [ const { text = 'Edit this page', pattern } = theme.value.editLink || {}
'https://github.com', const { relativePath } = page.value
theme.value.editLink?.repo || '???', const url = pattern.replace(/:path/g, relativePath)
'edit',
theme.value.editLink?.branch || 'main',
theme.value.editLink?.dir || null,
page.value.relativePath
]
.filter((v) => v)
.join('/')
const text = theme.value.editLink?.text ?? 'Edit this page' return { url, text }
return {
url,
text
}
}) })
} }

@ -7,6 +7,7 @@
"module": "esnext", "module": "esnext",
"declaration": true, "declaration": true,
"declarationDir": "../../dist/client-types", "declarationDir": "../../dist/client-types",
"jsx": "preserve",
"lib": ["ESNext", "DOM"], "lib": ["ESNext", "DOM"],
"types": ["vite/client"], "types": ["vite/client"],
"paths": { "paths": {

@ -102,11 +102,10 @@ export async function renderPage(
const title: string = createTitle(siteData, pageData) const title: string = createTitle(siteData, pageData)
const description: string = pageData.description || siteData.description const description: string = pageData.description || siteData.description
const head = addSocialTags( const head = [
title,
...siteData.head, ...siteData.head,
...filterOutHeadDescription(pageData.frontmatter.head) ...filterOutHeadDescription(pageData.frontmatter.head)
) ]
let inlinedScript = '' let inlinedScript = ''
if (config.mpa && result) { if (config.mpa && result) {
@ -219,20 +218,3 @@ function isMetaDescription(headConfig: HeadConfig) {
function filterOutHeadDescription(head: HeadConfig[] | undefined) { function filterOutHeadDescription(head: HeadConfig[] | undefined) {
return head ? head.filter((h) => !isMetaDescription(h)) : [] return head ? head.filter((h) => !isMetaDescription(h)) : []
} }
function hasTag(head: HeadConfig[], tag: HeadConfig) {
const [tagType, tagAttrs] = tag
const [attr, value] = Object.entries(tagAttrs)[0] // First key
return head.some(([type, attrs]) => type === tagType && attrs[attr] === value)
}
function addSocialTags(title: string, ...head: HeadConfig[]) {
const tags: HeadConfig[] = [
['meta', { name: 'twitter:title', content: title }],
['meta', { property: 'og:title', content: title }]
]
tags.filter((tagAttrs) => {
if (!hasTag(head, tagAttrs)) head.push(tagAttrs)
})
return head
}

@ -56,7 +56,7 @@ export type { Header }
export const createMarkdownRenderer = async ( export const createMarkdownRenderer = async (
srcDir: string, srcDir: string,
options: MarkdownOptions = {}, options: MarkdownOptions = {},
base: string base = '/'
): Promise<MarkdownRenderer> => { ): Promise<MarkdownRenderer> => {
const md = MarkdownIt({ const md = MarkdownIt({
html: true, html: true,

@ -27,7 +27,7 @@ export async function createMarkdownToVueRenderFn(
pages: string[], pages: string[],
userDefines: Record<string, any> | undefined, userDefines: Record<string, any> | undefined,
isBuild = false, isBuild = false,
base: string, base = '/',
includeLastUpdatedData = false includeLastUpdatedData = false
) { ) {
const md = await createMarkdownRenderer(srcDir, options, base) const md = await createMarkdownRenderer(srcDir, options, base)
@ -162,8 +162,9 @@ export async function createMarkdownToVueRenderFn(
} }
const scriptRE = /<\/script>/ const scriptRE = /<\/script>/
const scriptLangTsRE = /<\s*script[^>]*\blang=['"]ts['"][^>]*/
const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/ const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/
const scriptClientRe = /<\s*script[^>]*\bclient\b[^>]*/ const scriptClientRE = /<\s*script[^>]*\bclient\b[^>]*/
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/ const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/ const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/
@ -176,10 +177,12 @@ function genPageDataCode(tags: string[], data: PageData) {
return ( return (
scriptRE.test(tag) && scriptRE.test(tag) &&
!scriptSetupRE.test(tag) && !scriptSetupRE.test(tag) &&
!scriptClientRe.test(tag) !scriptClientRE.test(tag)
) )
}) })
const isUsingTS = tags.findIndex((tag) => scriptLangTsRE.test(tag)) > -1
if (existingScriptIndex > -1) { if (existingScriptIndex > -1) {
const tagSrc = tags[existingScriptIndex] const tagSrc = tags[existingScriptIndex]
// user has <script> tag inside markdown // user has <script> tag inside markdown
@ -196,7 +199,9 @@ function genPageDataCode(tags: string[], data: PageData) {
) )
} else { } else {
tags.unshift( tags.unshift(
`<script>${code}\nexport default {name:'${data.relativePath}'}</script>` `<script ${isUsingTS ? 'lang="ts"' : ''}>${code}\nexport default {name:'${
data.relativePath
}'}</script>`
) )
} }

@ -8,6 +8,7 @@
"skipLibCheck": true, "skipLibCheck": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"jsx": "preserve",
"lib": ["ESNext", "DOM"] "lib": ["ESNext", "DOM"]
}, },
"exclude": ["**/node_modules/**", "**/dist/**"] "exclude": ["**/node_modules/**", "**/dist/**"]

@ -13,6 +13,13 @@ export namespace DefaultTheme {
*/ */
siteTitle?: string | false siteTitle?: string | false
/**
* Custom outline title in the aside component.
*
* @default 'On this page'
*/
outlineTitle?: string
/** /**
* The nav items. * The nav items.
*/ */
@ -81,7 +88,7 @@ export namespace DefaultTheme {
export interface NavItemWithChildren { export interface NavItemWithChildren {
text?: string text?: string
items: NavItemWithLink[] items: NavItem[]
} }
// sidebar ------------------------------------------------------------------- // sidebar -------------------------------------------------------------------
@ -93,7 +100,7 @@ export namespace DefaultTheme {
} }
export interface SidebarGroup { export interface SidebarGroup {
text: string text?: string
items: SidebarItem[] items: SidebarItem[]
/** /**
@ -120,25 +127,11 @@ export namespace DefaultTheme {
export interface EditLink { export interface EditLink {
/** /**
* Repo of the site. * Pattern for edit link.
*
* @example 'vuejs/docs'
*/
repo: string
/**
* Branch of the repo.
*
* @default 'main'
*/
branch?: string
/**
* If your docs are not at the root of the repo.
* *
* @example 'docs' * @example 'https://github.com/vuejs/vitepress/edit/main/docs/:path'
*/ */
dir?: string pattern: string
/** /**
* Custom text for edit link. * Custom text for edit link.

Loading…
Cancel
Save