feat(plugin-md-power): rename demo-wrapper container to window (#858)
This commit is contained in:
parent
f7d3546962
commit
ce32605aee
@ -81,7 +81,7 @@ content right
|
||||
|
||||
**demo wrapper:**
|
||||
|
||||
::: demo-wrapper title="Demo" no-padding height="200px"
|
||||
::: window title="Demo" height="200px"
|
||||
<style scoped>
|
||||
.open-door {
|
||||
display: flex;
|
||||
|
||||
@ -95,9 +95,9 @@ H~2~O
|
||||
- vscode - <Icon name="skill-icons:vscode-dark" size="2em" />
|
||||
- twitter - <Icon name="skill-icons:twitter" size="2em" />
|
||||
|
||||
**demo wrapper:**
|
||||
**示例容器:**
|
||||
|
||||
::: demo-wrapper title="示例" no-padding height="200px"
|
||||
::: window title="示例" height="200px"
|
||||
<style scoped>
|
||||
.open-door {
|
||||
display: flex;
|
||||
|
||||
@ -102,9 +102,9 @@ H~2~O
|
||||
- vscode - <Icon name="skill-icons:vscode-dark" size="2em" />
|
||||
- twitter - <Icon name="skill-icons:twitter" size="2em" />
|
||||
|
||||
**demo wrapper:**
|
||||
**示例容器:**
|
||||
|
||||
::: demo-wrapper title="示例" no-padding height="200px"
|
||||
::: window title="示例" height="200px"
|
||||
<style scoped>
|
||||
.open-door {
|
||||
display: flex;
|
||||
|
||||
@ -129,8 +129,7 @@ config:
|
||||
|
||||
**Result:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
|
||||
::: window
|
||||

|
||||
:::
|
||||
|
||||
@ -246,7 +245,7 @@ config:
|
||||
|
||||
**Result:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
::: window
|
||||
<img src="/images/custom-doc-hero.jpg" alt="Theme Plume" />
|
||||
:::
|
||||
|
||||
@ -359,7 +358,7 @@ config:
|
||||
|
||||
**Result:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-features.jpg" alt="custom-features" />
|
||||
:::
|
||||
|
||||
@ -432,11 +431,11 @@ config:
|
||||
|
||||
**Result:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-image-text.jpg" alt="image-text" />
|
||||
:::
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-text-image.jpg" alt="text-image" />
|
||||
:::
|
||||
|
||||
@ -505,7 +504,7 @@ config:
|
||||
|
||||
**Result:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-profile.jpg" alt="profile" />
|
||||
:::
|
||||
|
||||
@ -551,7 +550,7 @@ yarn add vuepress@next vuepress-theme-plume
|
||||
|
||||
**Result:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-content.jpg" alt="content" />
|
||||
:::
|
||||
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
---
|
||||
title: Demo Container
|
||||
createTime: 2025/10/08 14:47:12
|
||||
icon: icon-park-outline:eyes
|
||||
permalink: /en/guide/markdown/demo-wrapper/
|
||||
icon: fxemoji:window
|
||||
permalink: /en/guide/markdown/window/
|
||||
outline: 2
|
||||
badge:
|
||||
text: Change
|
||||
type: warning
|
||||
---
|
||||
|
||||
## Overview
|
||||
@ -14,7 +17,7 @@ separately from other content. The theme supports adding demo containers in Mark
|
||||
## Syntax
|
||||
|
||||
````md
|
||||
::: demo-wrapper
|
||||
::: window
|
||||
Add your demo here
|
||||
:::
|
||||
````
|
||||
@ -31,20 +34,20 @@ Add your demo here
|
||||
Containing only images:
|
||||
|
||||
```md
|
||||
::: demo-wrapper img no-padding
|
||||
::: window
|
||||

|
||||
:::
|
||||
```
|
||||
|
||||
**Output:**
|
||||
::: demo-wrapper img no-padding
|
||||
::: window
|
||||

|
||||
:::
|
||||
|
||||
Containing markdown syntax:
|
||||
|
||||
```md
|
||||
::: demo-wrapper title="Title"
|
||||
::: window title="Title"
|
||||
### Level 3 Heading
|
||||
|
||||
This is content inside the demo container.
|
||||
@ -52,7 +55,7 @@ This is content inside the demo container.
|
||||
```
|
||||
|
||||
**Output:**
|
||||
::: demo-wrapper title="Title"
|
||||
::: window title="Title"
|
||||
|
||||
### Level 3 Heading
|
||||
|
||||
@ -62,7 +65,7 @@ This is content inside the demo container.
|
||||
Containing HTML/Vue code:
|
||||
|
||||
```md
|
||||
::: demo-wrapper
|
||||
::: window
|
||||
<h1 class="your-demo-title">This is a heading</h1>
|
||||
<p class="your-demo-paragraph">This is a paragraph</p>
|
||||
|
||||
@ -78,7 +81,7 @@ Containing HTML/Vue code:
|
||||
```
|
||||
|
||||
**Output:**
|
||||
::: demo-wrapper
|
||||
::: window
|
||||
|
||||
<h1 class="your-demo-title">This is a heading</h1>
|
||||
<p class="your-demo-paragraph">This is a paragraph</p>
|
||||
|
||||
@ -144,18 +144,18 @@ Included via `<!-- @include: ./foo.snippet.md#snippet -->`.
|
||||
|
||||
Using `<!-- @include: ./foo.snippet.md -->` to include the entire file:
|
||||
|
||||
:::: demo-wrapper title="Include by file"
|
||||
:::: window title="Include by file"
|
||||
<!-- @include: ../../snippet/include-2.snippet.md -->
|
||||
::::
|
||||
|
||||
Using `<!-- @include: ./foo.snippet.md{5-7} -->` to include lines 5-7 of the file:
|
||||
|
||||
:::: demo-wrapper title="Include by lines"
|
||||
:::: window title="Include by lines"
|
||||
<!-- @include: ../../snippet/include-2.snippet.md{5-7} -->
|
||||
::::
|
||||
|
||||
Using `<!-- @include: ./foo.snippet.md#snippet -->` to include the `snippet` region:
|
||||
|
||||
:::: demo-wrapper title="Include by file region"
|
||||
:::: window title="Include by file region"
|
||||
<!-- @include: ../../snippet/include-2.snippet.md#snippet -->
|
||||
::::
|
||||
|
||||
@ -12,7 +12,7 @@ This could be to pique readers' curiosity or simply to add a bit of reading diff
|
||||
|
||||
To satisfy this playful intention, the theme provides a fun little feature called **"plot" text**. It looks like this:
|
||||
|
||||
:::demo-wrapper
|
||||
:::window
|
||||
Did you know that !!Lu Xun!! once said: "!!I never said this!!!" It was an enlightening revelation that deeply
|
||||
inspired me, filling me with unparalleled strength! So, !!I turned over in bed!!!
|
||||
:::
|
||||
@ -102,7 +102,7 @@ Did you know that !!Lu Xun!! once said: "!!I never said this!!!" It was an enlig
|
||||
|
||||
**Output**:
|
||||
|
||||
:::demo-wrapper
|
||||
:::window
|
||||
Did you know that !!Lu Xun!! once said: "!!I never said this!!!" It was an enlightening revelation that
|
||||
deeply inspired me, filling me with unparalleled strength! So, !!I turned over in bed!!!!
|
||||
:::
|
||||
@ -118,7 +118,7 @@ Blur effect + click: !!Click to see me!!{.blur .click}
|
||||
|
||||
**Output**:
|
||||
|
||||
:::demo-wrapper
|
||||
:::window
|
||||
Mask effect + hover: !!Hover to see me!!{.mask .hover}
|
||||
|
||||
Mask effect + click: !!Click to see me!!{.mask .click}
|
||||
|
||||
@ -128,7 +128,7 @@ config:
|
||||
|
||||
**效果:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
|
||||

|
||||
:::
|
||||
@ -245,7 +245,7 @@ config:
|
||||
|
||||
**效果:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-doc-hero.jpg" alt="Theme Plume" />
|
||||
:::
|
||||
|
||||
@ -358,7 +358,7 @@ config:
|
||||
|
||||
**效果:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-features.jpg" alt="custom-features" />
|
||||
:::
|
||||
|
||||
@ -431,11 +431,11 @@ config:
|
||||
|
||||
**效果:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-image-text.jpg" alt="image-text" />
|
||||
:::
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-text-image.jpg" alt="text-image" />
|
||||
:::
|
||||
|
||||
@ -504,7 +504,7 @@ config:
|
||||
|
||||
**效果:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-profile.jpg" alt="profile" />
|
||||
:::
|
||||
|
||||
@ -550,7 +550,7 @@ yarn add vuepress@next vuepress-theme-plume
|
||||
|
||||
**效果:**
|
||||
|
||||
:::demo-wrapper img no-padding
|
||||
:::window
|
||||
<img src="/images/custom-content.jpg" alt="content" />
|
||||
:::
|
||||
|
||||
|
||||
@ -1,20 +1,23 @@
|
||||
---
|
||||
title: 示例容器
|
||||
createTime: 2024/09/30 14:47:12
|
||||
icon: icon-park-outline:eyes
|
||||
permalink: /guide/markdown/demo-wrapper/
|
||||
icon: fxemoji:window
|
||||
permalink: /guide/markdown/window/
|
||||
outline: 2
|
||||
badge:
|
||||
text: 变更
|
||||
type: warning
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
有时候,你可能需要在 内容中补充一些 示例,但期望能与 其它内容 分隔开来呈现。
|
||||
主题支持在 Markdown 文件中添加示例容器。
|
||||
主题支持在 Markdown 文件中添加示例窗口容器。
|
||||
|
||||
## 语法
|
||||
|
||||
````md
|
||||
::: demo-wrapper
|
||||
::: window
|
||||
添加你的示例
|
||||
:::
|
||||
````
|
||||
@ -22,29 +25,28 @@ outline: 2
|
||||
## 选项
|
||||
|
||||
- `title="xxx"`:标题
|
||||
- `no-padding`:不添加内边距
|
||||
- `img`: 仅包含图片时使用
|
||||
- `height="xxx"`: 高度
|
||||
- `height="200px"`: 高度
|
||||
- `gap="20px"`: 左右内边距
|
||||
|
||||
## 示例
|
||||
|
||||
仅包含图片:
|
||||
|
||||
```md
|
||||
::: demo-wrapper img no-padding
|
||||
::: window
|
||||

|
||||
:::
|
||||
```
|
||||
|
||||
**输出:**
|
||||
::: demo-wrapper img no-padding
|
||||
::: window
|
||||

|
||||
:::
|
||||
|
||||
包含 markdown 语法:
|
||||
|
||||
```md
|
||||
::: demo-wrapper title="标题"
|
||||
::: window title="标题"
|
||||
### 三级标题
|
||||
|
||||
这是示例容器中的内容。
|
||||
@ -52,7 +54,7 @@ outline: 2
|
||||
```
|
||||
|
||||
**输出:**
|
||||
::: demo-wrapper title="标题"
|
||||
::: window title="标题"
|
||||
|
||||
### 三级标题
|
||||
|
||||
@ -62,8 +64,8 @@ outline: 2
|
||||
包含 html /vue 代码:
|
||||
|
||||
```md
|
||||
::: demo-wrapper
|
||||
<h1 class="your-demo-title">这是标题</h1>
|
||||
::: window
|
||||
<h2 class="your-demo-title">这是标题</h2>
|
||||
<p class="your-demo-paragraph">这是段落</p>
|
||||
|
||||
<style>
|
||||
@ -78,9 +80,9 @@ outline: 2
|
||||
```
|
||||
|
||||
**输出:**
|
||||
::: demo-wrapper
|
||||
::: window
|
||||
|
||||
<h1 class="your-demo-title">这是标题</h1>
|
||||
<h2 class="your-demo-title">这是标题</h2>
|
||||
<p class="your-demo-paragraph">这是段落</p>
|
||||
|
||||
<style>
|
||||
|
||||
@ -144,18 +144,18 @@ export default defineUserConfig({
|
||||
|
||||
使用 `<!-- @include: ./foo.snippet.md -->` 导入文件:
|
||||
|
||||
:::: demo-wrapper title="Include by file"
|
||||
:::: window title="Include by file"
|
||||
<!-- @include: ../../snippet/include-2.snippet.md -->
|
||||
::::
|
||||
|
||||
使用 `<!-- @include: ./foo.snippet.md{5-7} -->` 导入文件内的 5 到 7 行:
|
||||
|
||||
:::: demo-wrapper title="Include by lines"
|
||||
:::: window title="Include by lines"
|
||||
<!-- @include: ../../snippet/include-2.snippet.md{5-7} -->
|
||||
::::
|
||||
|
||||
使用 `<!-- @include: ./foo.snippet.md#snippet -->` 导入 `snippet` 区域
|
||||
|
||||
:::: demo-wrapper title="Include by file region"
|
||||
:::: window title="Include by file region"
|
||||
<!-- @include: ../../snippet/include-2.snippet.md#snippet -->
|
||||
::::
|
||||
|
||||
@ -12,7 +12,7 @@ permalink: /guide/markdown/plot/
|
||||
|
||||
为了满足这种小小的心思,主题提供了一个 **“隐秘”文本** 的有趣小功能。它看起来像这样:
|
||||
|
||||
:::demo-wrapper
|
||||
:::window
|
||||
你知道吗, !!鲁迅!! 曾说过:“ !!我没说过这句话!!! ” 令我醍醐灌顶,深受启发,浑身迸发出无可匹敌的
|
||||
力量!于是,!!我在床上翻了个身!! !
|
||||
:::
|
||||
@ -102,7 +102,7 @@ plot:
|
||||
|
||||
**输出**:
|
||||
|
||||
:::demo-wrapper
|
||||
:::window
|
||||
你知道吗, !!鲁迅!! 曾说过:“ !!我没说过这句话!!!” 令我醍醐灌顶,深受启发,浑身迸发出无可匹敌的
|
||||
力量!于是,!!我在床上翻了个身!! !
|
||||
:::
|
||||
@ -118,7 +118,7 @@ plot:
|
||||
|
||||
**输出**:
|
||||
|
||||
:::demo-wrapper
|
||||
:::window
|
||||
遮罩层效果 + 鼠标悬停:!!鼠标悬停看到我了!!{.mask .hover}
|
||||
|
||||
遮罩层效果 + 点击:!!点击看到我了!!{.mask .click}
|
||||
|
||||
@ -97,9 +97,9 @@ H~2~O
|
||||
- vscode - <Icon name="skill-icons:vscode-dark" size="2em" />
|
||||
- twitter - <Icon name="skill-icons:twitter" size="2em" />
|
||||
|
||||
**demo wrapper:**
|
||||
**示例容器:**
|
||||
|
||||
::: demo-wrapper title="示例" no-padding height="200px"
|
||||
::: window title="示例" height="200px"
|
||||
<style scoped>
|
||||
.open-door {
|
||||
display: flex;
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`demoWrapperPlugin > should work 1`] = `
|
||||
"<div class="demo-wrapper">
|
||||
<div class="demo-head">
|
||||
<div class="demo-ctrl"><i></i><i></i><i></i></div>
|
||||
|
||||
</div>
|
||||
<div class="demo-container" >
|
||||
<p>content</p>
|
||||
</div></div><div class="demo-wrapper has-title">
|
||||
<div class="demo-head">
|
||||
<div class="demo-ctrl"><i></i><i></i><i></i></div>
|
||||
<h4 class="demo-title"><p>test</p></h4>
|
||||
</div>
|
||||
<div class="demo-container" >
|
||||
<p>content</p>
|
||||
</div></div><div class="demo-wrapper only-img no-padding has-height">
|
||||
<div class="demo-head">
|
||||
<div class="demo-ctrl"><i></i><i></i><i></i></div>
|
||||
|
||||
</div>
|
||||
<div class="demo-container" style="--demo-container-height: 100px;">
|
||||
<p><a href="/img.jpg">xxx</a></p>
|
||||
</div></div><div class="demo-wrapper only-img no-padding has-height">
|
||||
<div class="demo-head">
|
||||
<div class="demo-ctrl"><i></i><i></i><i></i></div>
|
||||
|
||||
</div>
|
||||
<div class="demo-container" style="--demo-container-height: 100px;">
|
||||
<p><a href="/img.jpg">xxx</a></p>
|
||||
</div></div>"
|
||||
`;
|
||||
@ -0,0 +1,80 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`windowPlugin > legacy demo-wrapper container 1`] = `
|
||||
"<article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;"><p>content</p>
|
||||
</section></article><article class="window-wrapper has-title">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
<div class="window-center"><h4 class="window-title ignore-header"><span>test</span><i class="vpi-window-reload"></i></h4></div>
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;"><p>content</p>
|
||||
</section></article><article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;--window-height:100px"><p><img src="/img.jpg" alt="xxx"></p>
|
||||
</section></article><article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;--window-height:100px"><p><img src="/img.jpg" alt="xxx"></p>
|
||||
</section></article>"
|
||||
`;
|
||||
|
||||
exports[`windowPlugin > should work 1`] = `
|
||||
"<article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;"><p>content</p>
|
||||
</section></article><article class="window-wrapper has-title">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
<div class="window-center"><h4 class="window-title ignore-header"><span>test</span><i class="vpi-window-reload"></i></h4></div>
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;"><p>content</p>
|
||||
</section></article><article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:0;--window-height:100px"><img src="/img.jpg" alt="xxx"></section></article><article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:20px;--window-height:100px"><img src="/img.jpg" alt="xxx"></section></article><article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:0;"> <img src="/img.jpg" alt="xxx">
|
||||
</section></article><article class="window-wrapper">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:0;"> <picture>
|
||||
<source srcset="/img.jpg" type="image/webp" />
|
||||
<img src="/img.jpg" alt="xxx" />
|
||||
</picture>
|
||||
</section></article>"
|
||||
`;
|
||||
@ -1,29 +0,0 @@
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { demoWrapperPlugin } from '../src/node/container/demoWrapper.js'
|
||||
|
||||
describe('demoWrapperPlugin', () => {
|
||||
const md = new MarkdownIt().use(demoWrapperPlugin)
|
||||
it('should work', () => {
|
||||
const code = `\
|
||||
::: demo-wrapper
|
||||
content
|
||||
:::
|
||||
|
||||
::: demo-wrapper title="test"
|
||||
content
|
||||
:::
|
||||
|
||||
::: demo-wrapper no-padding img height="100px"
|
||||
|
||||
[xxx](/img.jpg)
|
||||
:::
|
||||
|
||||
::: demo-wrapper no-padding img height="100"
|
||||
|
||||
[xxx](/img.jpg)
|
||||
:::
|
||||
`
|
||||
expect(md.render(code)).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
61
plugins/plugin-md-power/__test__/windowPlugin.spec.ts
Normal file
61
plugins/plugin-md-power/__test__/windowPlugin.spec.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { windowPlugin } from '../src/node/container/window.js'
|
||||
|
||||
describe('windowPlugin', () => {
|
||||
const md = new MarkdownIt({ html: true }).use(windowPlugin)
|
||||
it('should work', () => {
|
||||
const code = `\
|
||||
::: window
|
||||
content
|
||||
:::
|
||||
|
||||
::: window title="test"
|
||||
content
|
||||
:::
|
||||
|
||||
::: window height="100px"
|
||||

|
||||
:::
|
||||
|
||||
::: window height="100" gap="20px"
|
||||

|
||||
:::
|
||||
|
||||
::: window
|
||||
|
||||
<img src="/img.jpg" alt="xxx">
|
||||
:::
|
||||
|
||||
::: window
|
||||
|
||||
<picture>
|
||||
<source srcset="/img.jpg" type="image/webp" />
|
||||
<img src="/img.jpg" alt="xxx" />
|
||||
</picture>
|
||||
:::
|
||||
`
|
||||
expect(md.render(code)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('legacy demo-wrapper container', () => {
|
||||
const code = `\
|
||||
::: demo-wrapper
|
||||
content
|
||||
:::
|
||||
|
||||
::: demo-wrapper title="test"
|
||||
content
|
||||
:::
|
||||
|
||||
::: demo-wrapper height="100px"
|
||||

|
||||
:::
|
||||
|
||||
::: demo-wrapper height="100" gap="20px"
|
||||

|
||||
:::
|
||||
`
|
||||
expect(md.render(code)).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
@ -1,140 +0,0 @@
|
||||
.vp-doc .demo-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 40px;
|
||||
margin: 40px -16px;
|
||||
border: solid 1px var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--vp-shadow-2);
|
||||
transition: var(--vp-t-color);
|
||||
transition-property: border, box-shadow;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
min-height: 0;
|
||||
border-bottom: solid 1px var(--vp-c-divider);
|
||||
transition: border-bottom var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-container {
|
||||
min-height: 0;
|
||||
padding: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
transition: background-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper.has-title .demo-head {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper.only-img {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper.only-img img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper.only-img .demo-container,
|
||||
.vp-doc .demo-wrapper.no-padding .demo-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper.has-height .demo-container {
|
||||
height: var(--demo-container-height);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-ctrl {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 5px 0 5px 8px;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-ctrl i {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #ccc;
|
||||
border-radius: 100%;
|
||||
transition: background-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-ctrl i:nth-child(1) {
|
||||
background-color: var(--vp-c-danger-3);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-ctrl i:nth-child(2) {
|
||||
background-color: var(--vp-c-warning-3);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-ctrl i:nth-child(3) {
|
||||
background-color: var(--vp-c-green-3);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-title {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
padding: 0 16px;
|
||||
margin: 0 20px -1px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
transition: var(--vp-t-color);
|
||||
transition-property: color, background-color;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-title p {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-title::after,
|
||||
.vp-doc .demo-wrapper .demo-title::before {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
content: " ";
|
||||
transition: background var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-title::before {
|
||||
left: 100%;
|
||||
background: radial-gradient(16px at right top, transparent 50%, var(--vp-c-bg-alt) 50%);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-title::after {
|
||||
right: 100%;
|
||||
background: radial-gradient(16px at left top, transparent 50%, var(--vp-c-bg-alt) 50%);
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-container > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.vp-doc .demo-wrapper .demo-container > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 419px) {
|
||||
.vp-doc .demo-wrapper {
|
||||
margin: 40px 0;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@import url("./demo-wrapper.css");
|
||||
@import url("./window.css");
|
||||
@import url("./steps.css");
|
||||
|
||||
156
plugins/plugin-md-power/src/client/styles/window.css
Normal file
156
plugins/plugin-md-power/src/client/styles/window.css
Normal file
@ -0,0 +1,156 @@
|
||||
.window-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 40px;
|
||||
margin: 16px -16px;
|
||||
border: solid 1px var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--vp-shadow-2);
|
||||
transition: var(--vp-t-color);
|
||||
transition-property: border, box-shadow;
|
||||
}
|
||||
|
||||
@media (min-width: 419px) {
|
||||
.window-wrapper {
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.window-wrapper .window-header {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 28px;
|
||||
background-color: rgb(241 242 243);
|
||||
border-bottom: solid 1px var(--vp-c-divider);
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
transition: border-bottom var(--vp-t-color), background-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .window-wrapper .window-header {
|
||||
background-color: rgb(52 53 54);
|
||||
}
|
||||
|
||||
.window-wrapper.has-title .window-header {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.window-wrapper .window-left {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 5px 0 5px 8px;
|
||||
}
|
||||
|
||||
.window-wrapper .window-left i {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #ccc;
|
||||
border-radius: 100%;
|
||||
transition: background-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
.window-wrapper .window-left i:nth-child(1) {
|
||||
background-color: var(--vp-c-danger-3);
|
||||
}
|
||||
|
||||
.window-wrapper .window-left i:nth-child(2) {
|
||||
background-color: var(--vp-c-warning-3);
|
||||
}
|
||||
|
||||
.window-wrapper .window-left i:nth-child(3) {
|
||||
background-color: var(--vp-c-green-3);
|
||||
}
|
||||
|
||||
.window-wrapper .window-right {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-right: 8px;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.window-wrapper .window-center {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.window-wrapper .window-title {
|
||||
display: inline-flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
min-width: 200px;
|
||||
max-width: 100%;
|
||||
padding: 0 8px;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
border: solid 1px var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
transition: border-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.window-wrapper .window-title {
|
||||
min-width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
.window-wrapper .window-title span {
|
||||
flex: 1;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
|
||||
.window-wrapper .window-title [class*="vpi-window-"] {
|
||||
color: var(--vp-c-text-3);
|
||||
transition: color var(--vp-t-color);
|
||||
}
|
||||
|
||||
.window-wrapper .window-content {
|
||||
height: var(--window-height, auto);
|
||||
min-height: 0;
|
||||
padding: 0 var(--window-gap, 20px);
|
||||
overflow: auto;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
background-color: var(--vp-c-bg);
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
transition: background-color var(--vp-t-color);
|
||||
}
|
||||
|
||||
.window-wrapper .window-content > img:only-child {
|
||||
display: block;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
.vpi-window-share {
|
||||
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M11.293 2.293a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1-1.414 1.414L13 5.414V15a1 1 0 1 1-2 0V5.414L9.707 6.707a1 1 0 0 1-1.414-1.414zM4 11a2 2 0 0 1 2-2h2a1 1 0 0 1 0 2H6v9h12v-9h-2a1 1 0 1 1 0-2h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.vpi-window-add {
|
||||
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 4a1 1 0 0 1 1 1v6h6a1 1 0 1 1 0 2h-6v6a1 1 0 1 1-2 0v-6H5a1 1 0 1 1 0-2h6V5a1 1 0 0 1 1-1'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.vpi-window-copy {
|
||||
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M2 4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v4h4a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2v-4H4a2 2 0 0 1-2-2zm8 12v4h10V10h-4v4a2 2 0 0 1-2 2zm4-2V4H4v10z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.vpi-window-reload {
|
||||
--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M19.933 13.041a8 8 0 1 1-9.925-8.788c3.899-1 7.935 1.007 9.425 4.747'/%3E%3Cpath d='M20 4v5h-5'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import { resolveAttrs } from '.././utils/resolveAttrs.js'
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
|
||||
/**
|
||||
* Demo wrapper attributes
|
||||
*
|
||||
* 演示包装器属性
|
||||
*/
|
||||
interface DemoWrapperAttrs {
|
||||
title?: string
|
||||
img?: string
|
||||
noPadding?: boolean
|
||||
height?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Demo wrapper plugin - Enable demo wrapper container
|
||||
*
|
||||
* 演示包装器插件 - 启用演示包装器容器
|
||||
*
|
||||
* Syntax: :::demo-wrapper img no-padding title="xxx" height="100px"
|
||||
* 语法::::demo-wrapper img no-padding title="xxx" height="100px"
|
||||
*
|
||||
* @param md - Markdown instance / Markdown 实例
|
||||
*/
|
||||
export function demoWrapperPlugin(md: Markdown): void {
|
||||
createContainerPlugin(md, 'demo-wrapper', {
|
||||
before: (info: string) => {
|
||||
const { attrs } = resolveAttrs<DemoWrapperAttrs>(info)
|
||||
const wrapperClasses: string[] = ['demo-wrapper']
|
||||
let containerStyle = ''
|
||||
if (attrs.title)
|
||||
wrapperClasses.push('has-title')
|
||||
|
||||
if (attrs.img)
|
||||
wrapperClasses.push('only-img')
|
||||
|
||||
if (attrs.noPadding)
|
||||
wrapperClasses.push('no-padding')
|
||||
|
||||
if (attrs.height) {
|
||||
const h = Number.parseFloat(attrs.height) === Number(attrs.height) ? `${attrs.height}px` : attrs.height
|
||||
containerStyle += `--demo-container-height: ${h};`
|
||||
wrapperClasses.push('has-height')
|
||||
}
|
||||
|
||||
return `<div class="${wrapperClasses.join(' ')}">
|
||||
<div class="demo-head">
|
||||
<div class="demo-ctrl"><i></i><i></i><i></i></div>
|
||||
${attrs.title ? `<h4 class="demo-title"><p>${attrs.title}</p></h4>` : ''}
|
||||
</div>
|
||||
<div class="demo-container" ${containerStyle ? `style="${containerStyle}"` : ''}>\n`
|
||||
},
|
||||
after: () => '</div></div>',
|
||||
})
|
||||
}
|
||||
@ -10,7 +10,6 @@ import { chatPlugin } from './chat.js'
|
||||
import { codeTabs } from './codeTabs.js'
|
||||
import { codeTreePlugin } from './codeTree.js'
|
||||
import { collapsePlugin } from './collapse.js'
|
||||
import { demoWrapperPlugin } from './demoWrapper.js'
|
||||
import { encryptPlugin } from './encrypt.js'
|
||||
import { fieldPlugin } from './field.js'
|
||||
import { fileTreePlugin } from './fileTree.js'
|
||||
@ -20,6 +19,7 @@ import { stepsPlugin } from './steps.js'
|
||||
import { tablePlugin } from './table.js'
|
||||
import { tabs } from './tabs.js'
|
||||
import { timelinePlugin } from './timeline.js'
|
||||
import { windowPlugin } from './window.js'
|
||||
|
||||
/**
|
||||
* Container plugin - Register all container plugins
|
||||
@ -44,8 +44,8 @@ export async function containerPlugin(
|
||||
// ::: code-tabs
|
||||
codeTabs(md, options.codeTabs)
|
||||
|
||||
// ::: demo-wrapper
|
||||
demoWrapperPlugin(md)
|
||||
// ::: window
|
||||
windowPlugin(md)
|
||||
|
||||
// ::: steps
|
||||
stepsPlugin(md)
|
||||
|
||||
91
plugins/plugin-md-power/src/node/container/window.ts
Normal file
91
plugins/plugin-md-power/src/node/container/window.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { Markdown, MarkdownEnv } from 'vuepress/markdown'
|
||||
import { isNumber, isString } from '@pengzhanbo/utils'
|
||||
import { colors } from 'vuepress/utils'
|
||||
import { logger } from '../utils/logger.js'
|
||||
import { parseRect } from '../utils/parseRect.js'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
import { type ContainerOptions, createContainerPlugin } from './createContainer.js'
|
||||
|
||||
interface WindowAttrs {
|
||||
title?: string
|
||||
height?: string
|
||||
gap?: string
|
||||
/** @deprecated */
|
||||
noPadding?: boolean
|
||||
}
|
||||
|
||||
const RE_IMAGE_SYNTAX = /^!?\[[^\]]*\]\([^)]+\)$/
|
||||
|
||||
const render: NonNullable<ContainerOptions['before']> = (info, tokens, idx) => {
|
||||
const elms: Token[] = []
|
||||
for (let i = idx + 1; i < tokens.length; i++) {
|
||||
if (tokens[i].type === 'container_window_close')
|
||||
break
|
||||
elms.push(tokens[i])
|
||||
}
|
||||
const { attrs } = resolveAttrs<WindowAttrs>(info)
|
||||
let onlyImg = false
|
||||
if (elms.length === 1) {
|
||||
const { type } = elms[0]
|
||||
const content = elms[0].content.trim()
|
||||
if (type === 'html_block'
|
||||
&& (content.startsWith('<img') || content.startsWith('<picture'))) {
|
||||
onlyImg = true
|
||||
}
|
||||
}
|
||||
if (elms.length === 3) {
|
||||
const [op, img, cp] = elms
|
||||
if (op.type === 'paragraph_open'
|
||||
&& cp.type === 'paragraph_close'
|
||||
&& img.type === 'inline'
|
||||
&& RE_IMAGE_SYNTAX.test(img.content.trim())) {
|
||||
op.type = 'text'
|
||||
cp.type = 'text'
|
||||
onlyImg = true
|
||||
}
|
||||
}
|
||||
|
||||
const { title, height, noPadding } = attrs
|
||||
const gap = isString(attrs.gap) || isNumber(attrs.gap)
|
||||
? parseRect(attrs.gap)
|
||||
: (onlyImg || noPadding) ? '0' : '20px'
|
||||
|
||||
const classes: string[] = ['window-wrapper']
|
||||
title && classes.push('has-title')
|
||||
|
||||
return `<article class="${classes.join(' ')}">
|
||||
<header class="window-header">
|
||||
<div class="window-left"><i></i><i></i><i></i></div>
|
||||
${title ? `<div class="window-center"><h4 class="window-title ignore-header"><span>${title}</span><i class="vpi-window-reload"></i></h4></div>` : ''}
|
||||
<div class="window-right"><i class="vpi-window-share"></i><i class="vpi-window-add"></i><i class="vpi-window-copy"></i></div>
|
||||
</header>
|
||||
<section class="window-content" style="--window-gap:${gap};${height ? `--window-height:${parseRect(height)}` : ''}">`
|
||||
}
|
||||
|
||||
/**
|
||||
* window plugin - Enable window container
|
||||
*
|
||||
* 窗口插件 - 启用窗口容器
|
||||
*
|
||||
* Syntax: :::window title="xxx" height="100px" gap="20px"
|
||||
* 语法::::window title="xxx" height="100px" gap="20px"
|
||||
*
|
||||
* @param md - Markdown instance / Markdown 实例
|
||||
*/
|
||||
export function windowPlugin(md: Markdown): void {
|
||||
const after = () => '</section></article>'
|
||||
|
||||
createContainerPlugin(md, 'window', {
|
||||
before: render,
|
||||
after,
|
||||
})
|
||||
// legacy demo-wrapper container, keep for compatibility
|
||||
createContainerPlugin(md, 'demo-wrapper', {
|
||||
before: (info, tokens, idx, _, env: MarkdownEnv) => {
|
||||
logger.warn('container', `::: demo-wrapper container is deprecated, please use ::: window container instead. (${colors.gray(env.filePathRelative || '')})`)
|
||||
return render(info, tokens, idx, _, env)
|
||||
},
|
||||
after,
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user