mirror of https://github.com/vuejs/vitepress
parent
9c8f54c9f4
commit
38bbdaddb7
@ -0,0 +1,98 @@
|
||||
import { chromium, type Browser, type Page } from 'playwright-chromium'
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import {
|
||||
scaffold,
|
||||
build,
|
||||
createServer,
|
||||
serve,
|
||||
ScaffoldThemeType,
|
||||
type ScaffoldOptions
|
||||
} from 'vitepress'
|
||||
import type { ViteDevServer } from 'vite'
|
||||
import type { Server } from 'net'
|
||||
import getPort from 'get-port'
|
||||
|
||||
let browser: Browser
|
||||
let page: Page
|
||||
|
||||
beforeAll(async () => {
|
||||
browser = await chromium.connect(process.env['WS_ENDPOINT']!)
|
||||
page = await browser.newPage()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await page.close()
|
||||
await browser.close()
|
||||
})
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'temp')
|
||||
|
||||
async function testVariation(options: ScaffoldOptions) {
|
||||
fs.removeSync(root)
|
||||
scaffold({
|
||||
...options,
|
||||
root
|
||||
})
|
||||
|
||||
let server: ViteDevServer | Server
|
||||
const port = await getPort()
|
||||
|
||||
async function goto(path: string) {
|
||||
await page.goto(`http://localhost:${port}${path}`)
|
||||
await page.waitForSelector('#app div')
|
||||
}
|
||||
|
||||
if (process.env['VITE_TEST_BUILD']) {
|
||||
await build(root)
|
||||
server = (await serve({ root, port })).server
|
||||
} else {
|
||||
server = await createServer(root, { port })
|
||||
await server!.listen()
|
||||
}
|
||||
|
||||
try {
|
||||
await goto('/')
|
||||
expect(await page.textContent('h1')).toMatch('My Awesome Project')
|
||||
|
||||
await page.click('a[href="/markdown-examples.html"]')
|
||||
await page.waitForSelector('pre code')
|
||||
expect(await page.textContent('h1')).toMatch('Markdown Extension Examples')
|
||||
|
||||
await goto('/')
|
||||
expect(await page.textContent('h1')).toMatch('My Awesome Project')
|
||||
|
||||
await page.click('a[href="/api-examples.html"]')
|
||||
await page.waitForSelector('pre code')
|
||||
expect(await page.textContent('h1')).toMatch('Runtime API Examples')
|
||||
} finally {
|
||||
fs.removeSync(root)
|
||||
if ('ws' in server) {
|
||||
await server.close()
|
||||
} else {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.close((error) => (error ? reject(error) : resolve()))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const themes = [
|
||||
ScaffoldThemeType.Default,
|
||||
ScaffoldThemeType.DefaultCustom,
|
||||
ScaffoldThemeType.Custom
|
||||
]
|
||||
const usingTs = [false, true]
|
||||
|
||||
for (const theme of themes) {
|
||||
for (const useTs of usingTs) {
|
||||
test(`${theme}${useTs ? ` + TypeScript` : ``}`, () =>
|
||||
testVariation({
|
||||
root: '.',
|
||||
theme,
|
||||
useTs,
|
||||
injectNpmScripts: false
|
||||
}))
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"vitepress": "workspace:*"
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { dirname, resolve } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
const dir = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const timeout = 60_000
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
node: resolve(dir, '../../src/node')
|
||||
}
|
||||
},
|
||||
test: {
|
||||
watchExclude: ['**/node_modules/**', '**/temp/**'],
|
||||
globalSetup: ['__tests__/init/vitestGlobalSetup.ts'],
|
||||
testTimeout: timeout,
|
||||
hookTimeout: timeout,
|
||||
teardownTimeout: timeout,
|
||||
globals: true
|
||||
}
|
||||
})
|
@ -0,0 +1,17 @@
|
||||
import { chromium, type BrowserServer } from 'playwright-chromium'
|
||||
|
||||
let browserServer: BrowserServer
|
||||
|
||||
export async function setup() {
|
||||
browserServer = await chromium.launchServer({
|
||||
headless: !process.env.DEBUG,
|
||||
args: process.env.CI
|
||||
? ['--no-sandbox', '--disable-setuid-sandbox']
|
||||
: undefined
|
||||
})
|
||||
process.env['WS_ENDPOINT'] = browserServer.wsEndpoint()
|
||||
}
|
||||
|
||||
export async function teardown() {
|
||||
await browserServer.close()
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
import {
|
||||
intro,
|
||||
outro,
|
||||
group,
|
||||
text,
|
||||
select,
|
||||
cancel,
|
||||
confirm
|
||||
} from '@clack/prompts'
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { black, cyan, bgCyan, bold } from 'picocolors'
|
||||
import { fileURLToPath } from 'url'
|
||||
// @ts-ignore
|
||||
import template from 'lodash.template'
|
||||
|
||||
export enum ScaffoldThemeType {
|
||||
Default = 'default theme',
|
||||
DefaultCustom = 'default theme + customization',
|
||||
Custom = 'custom theme'
|
||||
}
|
||||
|
||||
export interface ScaffoldOptions {
|
||||
root: string
|
||||
title?: string
|
||||
description?: string
|
||||
theme: ScaffoldThemeType
|
||||
useTs: boolean
|
||||
injectNpmScripts: boolean
|
||||
}
|
||||
|
||||
export async function init() {
|
||||
intro(bgCyan(bold(black(` Welcome to VitePress! `))))
|
||||
|
||||
const options: ScaffoldOptions = await group(
|
||||
{
|
||||
root: () =>
|
||||
text({
|
||||
message: `Where should VitePress initialize the config?`,
|
||||
initialValue: './',
|
||||
validate(value) {
|
||||
// TODO make sure directory is inside
|
||||
}
|
||||
}),
|
||||
|
||||
title: () =>
|
||||
text({
|
||||
message: `Site title:`,
|
||||
placeholder: 'My Awesome Project'
|
||||
}),
|
||||
|
||||
description: () =>
|
||||
text({
|
||||
message: `Site description:`,
|
||||
placeholder: 'A VitePress Site'
|
||||
}),
|
||||
|
||||
theme: () =>
|
||||
select({
|
||||
message: 'Theme:',
|
||||
options: [
|
||||
{
|
||||
// @ts-ignore
|
||||
value: ScaffoldThemeType.Default,
|
||||
label: `Default Theme`,
|
||||
hint: `Out of the box, good-looking docs`
|
||||
},
|
||||
{
|
||||
// @ts-ignore
|
||||
value: ScaffoldThemeType.DefaultCustom,
|
||||
label: `Default Theme + Customization`,
|
||||
hint: `Add custom CSS and layout slots`
|
||||
},
|
||||
{
|
||||
// @ts-ignore
|
||||
value: ScaffoldThemeType.Custom,
|
||||
label: `Custom Theme`,
|
||||
hint: `Build your own or use external`
|
||||
}
|
||||
]
|
||||
}),
|
||||
|
||||
useTs: () =>
|
||||
confirm({ message: 'Use TypeScript for config and theme files?' }),
|
||||
|
||||
injectNpmScripts: () =>
|
||||
confirm({
|
||||
message: `Add VitePress npm scripts to package.json?`
|
||||
})
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
cancel('Cancelled.')
|
||||
process.exit(0)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
outro(scaffold(options))
|
||||
}
|
||||
|
||||
export function scaffold({
|
||||
root = './',
|
||||
title = 'My Awesome Project',
|
||||
description = 'A VitePress Site',
|
||||
theme,
|
||||
useTs,
|
||||
injectNpmScripts
|
||||
}: ScaffoldOptions) {
|
||||
const resolvedRoot = path.resolve(root)
|
||||
const templateDir = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'../../template'
|
||||
)
|
||||
|
||||
const data = {
|
||||
title: JSON.stringify(title),
|
||||
description: JSON.stringify(description),
|
||||
useTs,
|
||||
defaultTheme:
|
||||
theme === ScaffoldThemeType.Default ||
|
||||
theme === ScaffoldThemeType.DefaultCustom
|
||||
}
|
||||
|
||||
const renderFile = (file: string) => {
|
||||
const filePath = path.resolve(templateDir, file)
|
||||
let targetPath = path.resolve(resolvedRoot, file)
|
||||
if (useTs) {
|
||||
targetPath = targetPath.replace(/\.js$/, '.ts')
|
||||
}
|
||||
const src = fs.readFileSync(filePath, 'utf-8')
|
||||
const compiled = template(src)(data)
|
||||
fs.outputFileSync(targetPath, compiled)
|
||||
}
|
||||
|
||||
const filesToScaffold = [
|
||||
'index.md',
|
||||
'api-examples.md',
|
||||
'markdown-examples.md',
|
||||
`.vitepress/config.js`
|
||||
]
|
||||
|
||||
if (theme === ScaffoldThemeType.DefaultCustom) {
|
||||
filesToScaffold.push(
|
||||
`.vitepress/theme/index.js`,
|
||||
`.vitepress/theme/style.css`
|
||||
)
|
||||
} else if (theme === ScaffoldThemeType.Custom) {
|
||||
filesToScaffold.push(
|
||||
`.vitepress/theme/index.js`,
|
||||
`.vitepress/theme/style.css`,
|
||||
`.vitepress/theme/Layout.vue`
|
||||
)
|
||||
}
|
||||
|
||||
for (const file of filesToScaffold) {
|
||||
renderFile(file)
|
||||
}
|
||||
|
||||
const dir = root === './' ? `` : ` ${root.replace(/^\.\//, '')}`
|
||||
if (injectNpmScripts) {
|
||||
const scripts = {
|
||||
'docs:dev': `vitepress dev${dir}`,
|
||||
'docs:build': `vitepress build${dir}`,
|
||||
'docs:preview': `vitepress preview${dir}`
|
||||
}
|
||||
const pkgPath = path.resolve('package.json')
|
||||
let pkg
|
||||
if (!fs.existsSync(pkgPath)) {
|
||||
pkg = { scripts }
|
||||
} else {
|
||||
pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
|
||||
Object.assign(pkg.scripts || (pkg.scripts = {}), scripts)
|
||||
}
|
||||
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2))
|
||||
return `Done! Now run ${cyan(`npm run docs:dev`)} and start writing.`
|
||||
} else {
|
||||
return `You're all set! Now run ${cyan(
|
||||
`npx vitepress dev${dir}`
|
||||
)} and start writing.`
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<% if (useTs) { %>import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.vuejs.org/config/app-config
|
||||
export default defineConfig(<% } else { %>/**
|
||||
* @type {import('vitepress').UserConfig}
|
||||
* https://vitepress.vuejs.org/config/app-config
|
||||
*/
|
||||
const config = <% } %>{
|
||||
title: <%= title %>,
|
||||
description: <%= description %><% if (defaultTheme) { %>,
|
||||
themeConfig: {
|
||||
// https://vitepress.vuejs.org/config/default-theme-config
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Examples', link: '/markdown-examples' }
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Examples',
|
||||
items: [
|
||||
{ text: 'Markdown Examples', link: '/markdown-examples' },
|
||||
{ text: 'Runtime API Examples', link: '/api-examples' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||
]
|
||||
}<% } %>
|
||||
}<% if (useTs) { %>)<% } else { %>
|
||||
|
||||
export default config<% } %>
|
@ -0,0 +1,28 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.vuejs.org/config/app-config
|
||||
export default defineConfig({
|
||||
title: <%= title %>,
|
||||
description: <%= description %><% if (defaultTheme) { %>,
|
||||
themeConfig: {
|
||||
// https://vitepress.vuejs.org/config/default-theme-config
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Examples', link: '/markdown-examples' }
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Examples',
|
||||
items: [
|
||||
{ text: 'Markdown Examples', link: '/markdown-examples' },
|
||||
{ text: 'Runtime API Examples', link: '/api-examples' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||
]
|
||||
}<% } %>
|
||||
})
|
@ -0,0 +1,21 @@
|
||||
<script setup<%= useTs ? ' lang="ts"' : '' %>>
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
// https://vitepress.vuejs.org/api/
|
||||
const { site, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="frontmatter.home">
|
||||
<h1>{{ site.title }}</h1>
|
||||
<p>{{ site.description }}</p>
|
||||
<ul>
|
||||
<li><a href="/markdown-examples.html">Markdown Examples</a></li>
|
||||
<li><a href="/api-examples.html">API Examples</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a href="/">Home</a>
|
||||
<Content />
|
||||
</div>
|
||||
</template>
|
@ -0,0 +1,24 @@
|
||||
<% if (!defaultTheme) { %>import Layout from './Layout.vue'
|
||||
import './style.css'
|
||||
|
||||
export default {
|
||||
Layout,
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// TODO link to app level customizatin
|
||||
}
|
||||
}
|
||||
<% } else { %>import { h } from 'vue'
|
||||
import Theme from 'vitepress/theme'
|
||||
import './style.css'
|
||||
|
||||
export default {
|
||||
...Theme,
|
||||
Layout: () => {
|
||||
return h(Theme.Layout, null, {
|
||||
// TODO link to layout slots
|
||||
})
|
||||
},
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// TODO link to app level customizatin
|
||||
}
|
||||
}<% } %>
|
@ -0,0 +1,121 @@
|
||||
<% if (defaultTheme) { %>/**
|
||||
* Colors
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-c-brand: #646cff;
|
||||
--vp-c-brand-light: #747bff;
|
||||
--vp-c-brand-lighter: #9499ff;
|
||||
--vp-c-brand-lightest: #bcc0ff;
|
||||
--vp-c-brand-dark: #535bf2;
|
||||
--vp-c-brand-darker: #454ce1;
|
||||
--vp-c-brand-dimm: rgba(100, 108, 255, 0.08);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Button
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-button-brand-border: var(--vp-c-brand-light);
|
||||
--vp-button-brand-text: var(--vp-c-white);
|
||||
--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-white);
|
||||
--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-white);
|
||||
--vp-button-brand-active-bg: var(--vp-button-brand-bg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Home
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||
120deg,
|
||||
#bd34fe 30%,
|
||||
#41d1ff
|
||||
);
|
||||
|
||||
--vp-home-hero-image-background-image: linear-gradient(
|
||||
-45deg,
|
||||
#bd34fe 50%,
|
||||
#47caff 50%
|
||||
);
|
||||
--vp-home-hero-image-filter: blur(40px);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(56px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(72px);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Custom Block
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-custom-block-tip-border: var(--vp-c-brand);
|
||||
--vp-custom-block-tip-text: var(--vp-c-brand-darker);
|
||||
--vp-custom-block-tip-bg: var(--vp-c-brand-dimm);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-custom-block-tip-border: var(--vp-c-brand);
|
||||
--vp-custom-block-tip-text: var(--vp-c-brand-lightest);
|
||||
--vp-custom-block-tip-bg: var(--vp-c-brand-dimm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Algolia
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
.DocSearch {
|
||||
--docsearch-primary-color: var(--vp-c-brand) !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* VitePress: Custom fix
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
Use lighter colors for links in dark mode for a11y.
|
||||
Also specify some classes twice to have higher specificity
|
||||
over scoped class data attribute.
|
||||
*/
|
||||
.dark .vp-doc a,
|
||||
.dark .vp-doc a > code,
|
||||
.dark .VPNavBarMenuLink.VPNavBarMenuLink:hover,
|
||||
.dark .VPNavBarMenuLink.VPNavBarMenuLink.active,
|
||||
.dark .link.link:hover,
|
||||
.dark .link.link.active,
|
||||
.dark .edit-link-button.edit-link-button,
|
||||
.dark .pager-link .title {
|
||||
color: var(--vp-c-brand-lighter);
|
||||
}
|
||||
|
||||
.dark .vp-doc a:hover,
|
||||
.dark .vp-doc a > code:hover {
|
||||
color: var(--vp-c-brand-lightest);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Transition by color instead of opacity */
|
||||
.dark .vp-doc .custom-block a {
|
||||
transition: color 0.25s;
|
||||
}
|
||||
<% } else { %>
|
||||
html {
|
||||
font-family: Arial, Helvetica;
|
||||
}
|
||||
<% } %>
|
@ -0,0 +1,55 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Runtime API Examples
|
||||
|
||||
This page demonstrates usage of some of the runtime APIs provided by VitePress.
|
||||
|
||||
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
|
||||
|
||||
```md
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const { site, theme, page, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
## Results
|
||||
|
||||
### Site Data
|
||||
<pre>{{ site }}</pre>
|
||||
|
||||
### Theme Data
|
||||
<pre>{{ theme }}</pre>
|
||||
|
||||
### Page Data
|
||||
<pre>{{ page }}</pre>
|
||||
|
||||
### Page Frontmatter
|
||||
<pre>{{ frontmatter }}</pre>
|
||||
```
|
||||
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const { site, theme, page, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
## Results
|
||||
|
||||
### Site Data
|
||||
<pre>{{ site }}</pre>
|
||||
|
||||
### Theme Data
|
||||
<pre>{{ theme }}</pre>
|
||||
|
||||
### Page Data
|
||||
<pre>{{ page }}</pre>
|
||||
|
||||
### Page Frontmatter
|
||||
<pre>{{ frontmatter }}</pre>
|
||||
|
||||
## More
|
||||
|
||||
Check out the documentation for the [full list of runtime APIs](https://vitepress.vuejs.org/api/).
|
@ -0,0 +1,27 @@
|
||||
<% if (defaultTheme) { %>---
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: <%= title %>
|
||||
text: <%= description %>
|
||||
tagline: My great project tagline
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Markdown Examples
|
||||
link: /markdown-examples
|
||||
- theme: alt
|
||||
text: API Examples
|
||||
link: /api-examples
|
||||
|
||||
features:
|
||||
- title: Feature A
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
- title: Feature B
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
- title: Feature C
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
---
|
||||
<% } else { %>---
|
||||
home: true
|
||||
---
|
||||
<% } %>
|
@ -0,0 +1,85 @@
|
||||
# Markdown Extension Examples
|
||||
|
||||
This page demonstrates some of the built-in markdown extensions provided by VitePress.
|
||||
|
||||
## Syntax Highlighting
|
||||
|
||||
VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
|
||||
|
||||
**Input**
|
||||
|
||||
````
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
**Output**
|
||||
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Containers
|
||||
|
||||
**Input**
|
||||
|
||||
```md
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details
|
||||
This is a details block.
|
||||
:::
|
||||
```
|
||||
|
||||
**Output**
|
||||
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details
|
||||
This is a details block.
|
||||
:::
|
||||
|
||||
## More
|
||||
|
||||
Check out the documentation for the [full list of markdown extensions](https://vitepress.vuejs.org/guide/markdown).
|
Loading…
Reference in new issue