refactor(plugin-md-power): improve timeline syntax parsing (#534)
This commit is contained in:
parent
7b8fae22b1
commit
dd5c984578
@ -37,11 +37,13 @@ export default defineUserConfig({
|
||||
|
||||
```md{1,9} title="timeline.md"
|
||||
::: timeline 配置
|
||||
- 标题 配置
|
||||
- 标题
|
||||
配置
|
||||
|
||||
正文内容
|
||||
|
||||
- 标题 配置
|
||||
- 标题
|
||||
配置
|
||||
|
||||
正文内容
|
||||
:::
|
||||
@ -49,8 +51,12 @@ export default defineUserConfig({
|
||||
|
||||
对于列表的每一个项:
|
||||
|
||||
- __第一行__: 从起始位置定义 __标题__,在标题之后跟着 `key=value` 的格式配置时间点的 __属性__。
|
||||
- __后续行__: 正文内容,==请注意添加正确的缩进=={.important}。
|
||||
- 从 __首行开始__ 到 __首个空行__,均为 __标题__ ,在标题后紧跟随的一行,用于 __配置__ 当前项的行为
|
||||
|
||||
- __首个空行之后__: 正文内容
|
||||
|
||||
:::important 请注意添加正确的缩进
|
||||
:::
|
||||
|
||||
__一个简单的例子:__
|
||||
|
||||
@ -58,15 +64,18 @@ __输入:__
|
||||
|
||||
```md
|
||||
::: timeline
|
||||
- 节点一 time=2025-03-20 type=success
|
||||
- 节点一
|
||||
time=2025-03-20 type=success
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点二 time=2025-02-21 type=warning
|
||||
- 节点二
|
||||
time=2025-02-21 type=warning
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
:::
|
||||
@ -76,15 +85,18 @@ __输出:__
|
||||
|
||||
::: timeline
|
||||
|
||||
- 节点一 time=2025-03-20 type=success
|
||||
- 节点一
|
||||
time=2025-03-20 type=success
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点二 time=2025-02-21 type=warning
|
||||
- 节点二
|
||||
time=2025-02-21 type=warning
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
:::
|
||||
@ -100,9 +112,17 @@ __时间线__ 支持非常灵活且灵活的配置项,配置主要分为两个
|
||||
|
||||
`::: timeline horizontal` 表示 渲染为 水平方向的时间线。
|
||||
|
||||
- __列表项配置__: 在列表的每一个项上的配置,配置项列表项的第一行,跟随在标题之后,如:
|
||||
- __列表项配置__: 列表的每一个项的配置,紧跟随在标题之后的一行,如:
|
||||
|
||||
`- 节点一 time=2025-03-20 type=success` 表示 时间点为 `2025-03-20`,节点类型为 `success`。
|
||||
```md
|
||||
::: timeline
|
||||
- 标题 <!--标题行-->
|
||||
也是标题 <!--标题行-->
|
||||
time=2025-03-20 type=success <!--配置跟随在最后的标题行之后的单独一行,可选-->
|
||||
<!--空行,有正文时必须-->
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
|
||||
### 容器配置
|
||||
|
||||
@ -202,13 +222,24 @@ __输入:__
|
||||
|
||||
```md /horizontal/
|
||||
::: timeline horizontal
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -217,15 +248,25 @@ __输出:__
|
||||
|
||||
::: timeline horizontal
|
||||
|
||||
- 节点一 time=2025-03-20
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
### 右对齐
|
||||
@ -236,13 +277,24 @@ __输入:__
|
||||
|
||||
```md /placement="right"/
|
||||
::: timeline placement="right"
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -251,13 +303,24 @@ __输出:__
|
||||
|
||||
::: timeline placement="right"
|
||||
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
@ -271,13 +334,24 @@ __输入:__
|
||||
|
||||
```md /placement="between"/ /placement=right/
|
||||
::: timeline placement="between"
|
||||
- 节点一 time=2025-03-20 placement=right
|
||||
- 节点一
|
||||
time=2025-03-20 placement=right
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger placement=right
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger placement=right
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -286,31 +360,53 @@ __输出:__
|
||||
|
||||
::: timeline placement="between"
|
||||
|
||||
- 节点一 time=2025-03-20 placement=right
|
||||
- 节点一
|
||||
time=2025-03-20 placement=right
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger placement=right
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger placement=right
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
### 节点类型
|
||||
|
||||
在列表项首行标题之后,添加 `type=节点类型` 可以为当前节点设置节点类型。
|
||||
在列表项配置中,添加 `type=节点类型` 可以为当前节点设置节点类型。
|
||||
|
||||
__输入:__
|
||||
|
||||
```md /type=success/ /type=warning/ /type=danger/ /type=important/
|
||||
::: timeline
|
||||
- 节点一 time=2025-03-20 type=success
|
||||
- 节点一
|
||||
time=2025-03-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=warning
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=warning
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -319,32 +415,54 @@ __输出:__
|
||||
|
||||
::: timeline
|
||||
|
||||
- 节点一 time=2025-03-20 type=success
|
||||
- 节点一
|
||||
time=2025-03-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=warning
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=warning
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
### 线条风格
|
||||
|
||||
- 在容器配置中添加 `line=线条风格` 可以为所有节点设置默认线条风格。
|
||||
- 在列表项首行标题之后,添加 `line=线条风格` 可以为节点设置线条风格。
|
||||
- 在列表项配置中,添加 `line=线条风格` 可以为节点设置线条风格。
|
||||
|
||||
__输入:__
|
||||
|
||||
```md /line="dotted"/ /line=solid/ /line=dashed/
|
||||
::: timeline line="dotted"
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger line=dashed
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger line=dashed
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important line=solid
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important line=solid
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -353,19 +471,30 @@ __输出:__
|
||||
|
||||
::: timeline line="dotted"
|
||||
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger line=dashed
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger line=dashed
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important line=solid
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important line=solid
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
### 带图标的节点
|
||||
|
||||
在列表项首行标题之后,添加 `icon=图标名称` 可以为节点添加图标。
|
||||
在列表项配置中,添加 `icon=图标名称` 可以为节点添加图标。
|
||||
|
||||
图标名称支持 [iconify](https://icon-sets.iconify.design/) 的图标名称。
|
||||
|
||||
@ -373,13 +502,24 @@ __输入:__
|
||||
|
||||
```md /icon=mdi:balloon/ /icon=mdi:bookmark/
|
||||
::: timeline placement="between"
|
||||
- 节点一 time=2025-03-20 placement=right icon=mdi:balloon
|
||||
- 节点一
|
||||
time=2025-03-20 placement=right icon=mdi:balloon
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success icon=mdi:bookmark
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success icon=mdi:bookmark
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger placement=right icon=mdi:bullhorn-variant-outline
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger placement=right icon=mdi:bullhorn-variant-outline
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important card=true icon="mdi:cake-variant-outline"
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important card=true icon="mdi:cake-variant-outline"
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -388,13 +528,24 @@ __输出:__
|
||||
|
||||
::: timeline placement="between"
|
||||
|
||||
- 节点一 time=2025-03-20 placement=right icon=mdi:balloon
|
||||
- 节点一
|
||||
time=2025-03-20 placement=right icon=mdi:balloon
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success icon=mdi:bookmark
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success icon=mdi:bookmark
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger placement=right icon=mdi:bullhorn-variant-outline
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger placement=right icon=mdi:bullhorn-variant-outline
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important card=true icon="mdi:cake-variant-outline"
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important card=true icon="mdi:cake-variant-outline"
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
@ -403,25 +554,36 @@ __输出:__
|
||||
卡片节点可以很灵活的进行控制:
|
||||
|
||||
- 在 容器配置中添加 `card` 即可使每个列表项都是卡片节点。
|
||||
- 在列表项首行标题之后,添加 `card=true` 即可为节点设置为卡片节点。
|
||||
- 在列表项首行标题之后,添加 `card=false` 即可为节点设置为非卡片节点。
|
||||
- 在列表项配置中,添加 `card=true` 即可为节点设置为卡片节点。
|
||||
- 在列表项配置中,添加 `card=false` 即可为节点设置为非卡片节点。
|
||||
|
||||
卡片节点的样式会受到 `type` 配置的影响。
|
||||
|
||||
::: tip 在列表项首行标题之后添加 `card=true` / `card=false` 可以覆盖容器节点的 `card` 配置
|
||||
::: tip 在列表项配置中添加 `card=true` / `card=false` 可以覆盖容器节点的 `card` 配置
|
||||
:::
|
||||
|
||||
__输入:__
|
||||
|
||||
```md{1} /card=false/
|
||||
::: timeline card
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success card=false
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success card=false
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
@ -430,13 +592,24 @@ __输出:__
|
||||
|
||||
::: timeline card
|
||||
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=success card=false
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=success card=false
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
- 节点四 time=2025-01-22 type=important
|
||||
|
||||
- 节点四
|
||||
time=2025-01-22 type=important
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
@ -480,22 +653,38 @@ __示例:__
|
||||
|
||||
```md /type=your-type/
|
||||
::: timeline
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=your-type card=true
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=your-type card=true
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
:::
|
||||
```
|
||||
|
||||
::: timeline
|
||||
|
||||
- 节点一 time=2025-03-20
|
||||
- 节点一
|
||||
time=2025-03-20
|
||||
|
||||
正文内容
|
||||
- 节点二 time=2025-04-20 type=your-type card=true
|
||||
|
||||
- 节点二
|
||||
time=2025-04-20 type=your-type card=true
|
||||
|
||||
正文内容
|
||||
- 节点三 time=2025-01-22 type=danger
|
||||
|
||||
- 节点三
|
||||
time=2025-01-22 type=danger
|
||||
|
||||
正文内容
|
||||
:::
|
||||
|
||||
|
||||
@ -1,16 +1,10 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`timeline > timelinePlugin() > should work 1`] = `
|
||||
"<VPTimeline :card="undefined"><VPTimelineItem :card="undefined">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容</VPTimelineItem><VPTimelineItem :card="undefined">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容</VPTimelineItem></VPTimeline><VPTimeline horizontal card line="dashed"><VPTimelineItem time="q1" :card="undefined">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容
|
||||
"<VPTimeline :card="undefined"><VPTimelineItem :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem :card="undefined"><template #title>这是标题
|
||||
这也是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline horizontal card line="dashed"><VPTimelineItem time="q1" :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
@ -21,24 +15,11 @@ exports[`timeline > timelinePlugin() > should work 1`] = `
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</VPTimelineItem><VPTimelineItem time="q2" color="red">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容</VPTimelineItem></VPTimeline><VPTimeline :card="undefined" placement="right"><VPTimelineItem type="warning" icon="xxx" card>
|
||||
<template #title>这是标题</template>
|
||||
<template #icon><VPIcon name="xxx"/></template>
|
||||
这是内容</VPTimelineItem><VPTimelineItem type="danger" line="dotted" :card="undefined">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容</VPTimelineItem></VPTimeline><VPTimeline :card="undefined" placement="between"><VPTimelineItem card placement="right">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容</VPTimelineItem><VPTimelineItem card placement="left">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
这是内容</VPTimelineItem><VPTimelineItem :card="undefined">
|
||||
<template #title>这是标题</template>
|
||||
|
||||
<p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem time="q2" color="red"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline :card="undefined" placement="right"><VPTimelineItem type="warning" icon="xxx" card><template #icon><VPIcon name="xxx"/></template><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem type="danger" line="dotted" :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline><VPTimeline :card="undefined" placement="between"><VPTimelineItem card placement="right"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem card placement="left"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem><VPTimelineItem :card="undefined"><template #title>这是标题</template><p>这是内容</p>
|
||||
</VPTimelineItem></VPTimeline>"
|
||||
`;
|
||||
|
||||
@ -4,24 +4,24 @@ import { extractTimelineAttributes, timelinePlugin } from '../src/node/container
|
||||
|
||||
describe('timeline > extractTimelineAttributes()', () => {
|
||||
it('should work', () => {
|
||||
const meta = extractTimelineAttributes('这是标题 time=Q1')
|
||||
expect(meta).toEqual({ title: '这是标题', time: 'Q1' })
|
||||
const meta = extractTimelineAttributes('这time=Q1')
|
||||
expect(meta).toEqual({ time: 'Q1' })
|
||||
})
|
||||
|
||||
it('should work with multi attrs', () => {
|
||||
const meta = extractTimelineAttributes('这是标题 time=Q1 icon=ri:clockwise-line card=true placement=left line=dashed')
|
||||
expect(meta).toEqual({ title: '这是标题', time: 'Q1', icon: 'ri:clockwise-line', card: 'true', placement: 'left', line: 'dashed' })
|
||||
const meta = extractTimelineAttributes('time=Q1 icon=ri:clockwise-line card=true placement=left line=dashed')
|
||||
expect(meta).toEqual({ time: 'Q1', icon: 'ri:clockwise-line', card: 'true', placement: 'left', line: 'dashed' })
|
||||
})
|
||||
|
||||
it('should work with title include space', () => {
|
||||
const meta = extractTimelineAttributes('这是标题 这也是标题 time=Q1 icon=ri:clockwise-line card=true placement=left line=dashed')
|
||||
const meta = extractTimelineAttributes('time=Q1 icon=ri:clockwise-line card=true placement=left line=dashed')
|
||||
|
||||
expect(meta).toEqual({ title: '这是标题 这也是标题', time: 'Q1', icon: 'ri:clockwise-line', card: 'true', placement: 'left', line: 'dashed' })
|
||||
expect(meta).toEqual({ time: 'Q1', icon: 'ri:clockwise-line', card: 'true', placement: 'left', line: 'dashed' })
|
||||
})
|
||||
|
||||
it('should work with unknown attr', () => {
|
||||
const meta = extractTimelineAttributes('这是标题 time=Q1 unknown=true card=true')
|
||||
expect(meta).toEqual({ title: '这是标题 unknown=true card=true', time: 'Q1' })
|
||||
const meta = extractTimelineAttributes('time=Q1 unknown=true card=true')
|
||||
expect(meta).toEqual({ time: 'Q1' })
|
||||
})
|
||||
})
|
||||
|
||||
@ -33,14 +33,19 @@ describe('timeline > timelinePlugin()', () => {
|
||||
const source = `\
|
||||
::: timeline
|
||||
- 这是标题
|
||||
|
||||
这是内容
|
||||
|
||||
- 这是标题
|
||||
这也是标题
|
||||
|
||||
这是内容
|
||||
:::
|
||||
|
||||
::: timeline horizontal line="dashed" card
|
||||
- 这是标题 time=q1
|
||||
- 这是标题
|
||||
time=q1
|
||||
|
||||
这是内容
|
||||
- 1
|
||||
- 2
|
||||
@ -48,23 +53,33 @@ describe('timeline > timelinePlugin()', () => {
|
||||
- 1.1
|
||||
- 1.2
|
||||
|
||||
- 这是标题 time=q2 color=red card=false
|
||||
- 这是标题
|
||||
time=q2 color=red card=false
|
||||
|
||||
这是内容
|
||||
:::
|
||||
|
||||
::: timeline placement="right"
|
||||
- 这是标题 icon=xxx card=true type=warning
|
||||
- 这是标题
|
||||
icon=xxx card=true type=warning
|
||||
|
||||
这是内容
|
||||
|
||||
- 这是标题 type=danger line=dotted
|
||||
- 这是标题
|
||||
type=danger line=dotted
|
||||
|
||||
这是内容
|
||||
:::
|
||||
|
||||
::: timeline placement="between"
|
||||
- 这是标题 card=true placement=right
|
||||
- 这是标题
|
||||
card=true placement=right
|
||||
|
||||
这是内容
|
||||
|
||||
- 这是标题 card=true placement=left
|
||||
- 这是标题
|
||||
card=true placement=left
|
||||
|
||||
这是内容
|
||||
|
||||
- 这是标题
|
||||
|
||||
@ -77,6 +77,7 @@
|
||||
"@mdit/plugin-sup": "catalog:prod",
|
||||
"@mdit/plugin-tab": "catalog:prod",
|
||||
"@mdit/plugin-tasklist": "catalog:prod",
|
||||
"@pengzhanbo/utils": "catalog:prod",
|
||||
"@vuepress/helper": "catalog:vuepress",
|
||||
"@vueuse/core": "catalog:prod",
|
||||
"chokidar": "catalog:prod",
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
/**
|
||||
* ::: timeline
|
||||
*
|
||||
* - title time="Q1" icon="ri:clockwise-line" line="dashed" type="warning" color="red"
|
||||
* xxx
|
||||
* - title time="Q2" icon="ri:clockwise-line" line="dashed" type="warning" color="red"
|
||||
* - title
|
||||
* time="Q1" icon="ri:clockwise-line" line="dashed" type="warning" color="red"
|
||||
*
|
||||
* content
|
||||
*
|
||||
* - title
|
||||
* time="Q2" icon="ri:clockwise-line" line="dashed" type="warning" color="red"
|
||||
*
|
||||
* content
|
||||
* :::
|
||||
*/
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import { isEmptyObject } from '@pengzhanbo/utils'
|
||||
import { resolveAttrs } from '.././utils/resolveAttrs.js'
|
||||
import { cleanMarkdownEnv } from '../utils/cleanMarkdownEnv.js'
|
||||
import { createContainerPlugin } from './createContainer.js'
|
||||
|
||||
export interface TimelineAttrs {
|
||||
@ -20,7 +26,6 @@ export interface TimelineAttrs {
|
||||
}
|
||||
|
||||
export interface TimelineItemMeta {
|
||||
title: string
|
||||
time?: string
|
||||
type?: string
|
||||
icon?: string
|
||||
@ -54,9 +59,9 @@ export function timelinePlugin(md: Markdown) {
|
||||
after: () => '</VPTimeline>',
|
||||
})
|
||||
|
||||
md.renderer.rules.timeline_item_open = (tokens, idx, _, env) => {
|
||||
md.renderer.rules.timeline_item_open = (tokens, idx) => {
|
||||
const token = tokens[idx]
|
||||
const { title, time, type, icon, color, line, card, placement } = token.meta as TimelineItemMeta
|
||||
const { time, type, icon, color, line, card, placement } = token.meta as TimelineItemMeta
|
||||
return `<VPTimelineItem${
|
||||
time ? ` time="${time}"` : ''
|
||||
}${
|
||||
@ -69,12 +74,12 @@ export function timelinePlugin(md: Markdown) {
|
||||
card === 'true' ? ' card' : card === 'false' ? '' : ' :card="undefined"'
|
||||
}${
|
||||
placement ? ` placement="${placement}"` : ''
|
||||
}>
|
||||
<template #title>${md.renderInline(title, cleanMarkdownEnv(env))}</template>
|
||||
${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ''}`
|
||||
}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ''}`
|
||||
}
|
||||
|
||||
md.renderer.rules.timeline_item_close = () => '</VPTimelineItem>'
|
||||
md.renderer.rules.timeline_item_title_open = () => '<template #title>'
|
||||
md.renderer.rules.timeline_item_title_close = () => '</template>'
|
||||
}
|
||||
|
||||
function parseTimeline(tokens: Token[], index: number) {
|
||||
@ -101,20 +106,27 @@ function parseTimeline(tokens: Token[], index: number) {
|
||||
// 仅处理根级列表项(层级1)
|
||||
if (currentLevel === 1) {
|
||||
token.type = 'timeline_item_open'
|
||||
const titleOpenToken = tokens[i + 1]
|
||||
const titleCloseToken = tokens[i + 3]
|
||||
titleOpenToken.hidden = true
|
||||
titleCloseToken.hidden = true
|
||||
tokens[i + 1].type = 'timeline_item_title_open'
|
||||
tokens[i + 3].type = 'timeline_item_title_close'
|
||||
|
||||
// - title
|
||||
// attrs
|
||||
// 列表项 `-` 后面包括紧跟随的后续行均在 type=inline 的 token 中, 并作为 children
|
||||
const inlineToken = tokens[i + 2]
|
||||
const softbreakIndex = inlineToken.children!.findIndex(
|
||||
// 找到最后一个 softbreak,最后一行作为 attrs 进行解析
|
||||
const softbreakIndex = inlineToken.children!.findLastIndex(
|
||||
token => token.type === 'softbreak',
|
||||
)
|
||||
inlineToken.children = softbreakIndex !== -1
|
||||
? inlineToken.children!.slice(softbreakIndex)
|
||||
: []
|
||||
|
||||
const content = inlineToken.content.replace(/\n[\s\S]*/, '')
|
||||
token.meta = extractTimelineAttributes(content.trim())
|
||||
if (softbreakIndex !== -1) {
|
||||
const lastToken = inlineToken.children![inlineToken.children!.length - 1]
|
||||
token.meta = extractTimelineAttributes(lastToken.content.trim())
|
||||
if (!isEmptyObject(token.meta)) {
|
||||
inlineToken.children = inlineToken.children!.slice(0, softbreakIndex)
|
||||
}
|
||||
}
|
||||
else {
|
||||
token.meta = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (token.type === 'list_item_close') {
|
||||
@ -128,27 +140,22 @@ function parseTimeline(tokens: Token[], index: number) {
|
||||
|
||||
export function extractTimelineAttributes(rawText: string): TimelineItemMeta {
|
||||
const attrKeys = ['time', 'type', 'icon', 'line', 'color', 'card', 'placement'] as const
|
||||
const attrs: Partial<TimelineItemMeta> = {}
|
||||
const attrs: TimelineItemMeta = {}
|
||||
let buffer = rawText.trim()
|
||||
const titleSegments: string[] = []
|
||||
|
||||
while (buffer.length) {
|
||||
// 匹配属性键 (支持大小写)
|
||||
const keyMatch = buffer.match(RE_KEY)
|
||||
if (!keyMatch) {
|
||||
titleSegments.push(buffer)
|
||||
break
|
||||
}
|
||||
|
||||
// 提取可能的关键字
|
||||
const matchedKey = keyMatch[1].toLowerCase()
|
||||
if (!attrKeys.includes(matchedKey as any)) {
|
||||
titleSegments.push(buffer)
|
||||
break
|
||||
}
|
||||
const keyStart = keyMatch.index!
|
||||
// 记录非属性内容为标题
|
||||
titleSegments.push(buffer.slice(0, keyStart).trim())
|
||||
|
||||
// 跳过已匹配的 key:
|
||||
const keyEnd = keyStart + keyMatch[0].length
|
||||
@ -167,8 +174,5 @@ export function extractTimelineAttributes(rawText: string): TimelineItemMeta {
|
||||
buffer = buffer.slice(valueEnd)
|
||||
}
|
||||
|
||||
return {
|
||||
title: titleSegments.join(' ').trim(),
|
||||
...attrs,
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user