vuepress-plugin-md-power 1.0.0-rc.136 → 1.0.0-rc.137

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ <script setup lang="ts">
2
+ import { provide, ref } from 'vue'
3
+ import { INJECT_COLLAPSE_KEY } from '../options.js'
4
+
5
+ const props = defineProps<{
6
+ accordion?: boolean
7
+ index?: number
8
+ }>()
9
+
10
+ const currentIndex = ref<number | undefined>(props.index)
11
+
12
+ provide(INJECT_COLLAPSE_KEY, {
13
+ accordion: props.accordion ?? false,
14
+ index: currentIndex,
15
+ })
16
+ </script>
17
+
18
+ <template>
19
+ <div class="vp-collapse">
20
+ <slot />
21
+ </div>
22
+ </template>
23
+
24
+ <style>
25
+ .vp-collapse {
26
+ display: flex;
27
+ flex-direction: column;
28
+ gap: 16px;
29
+ margin: 16px 0;
30
+ }
31
+ </style>
@@ -0,0 +1,118 @@
1
+ <script setup lang="ts">
2
+ import type { Ref } from 'vue'
3
+ import { inject, ref, watch } from 'vue'
4
+ import { INJECT_COLLAPSE_KEY } from '../options.js'
5
+ import VPFadeInExpandTransition from './VPFadeInExpandTransition.vue'
6
+
7
+ const props = defineProps<{
8
+ expand?: boolean
9
+ index: number
10
+ }>()
11
+
12
+ const collapse = inject<{
13
+ accordion: boolean
14
+ index: Ref<number | undefined>
15
+ }>(INJECT_COLLAPSE_KEY)
16
+
17
+ if (__VUEPRESS_DEV__ && !collapse) {
18
+ throw new Error('<VPCollapseItem /> must be used inside <VPCollapse />')
19
+ }
20
+
21
+ const expand = ref(
22
+ collapse?.accordion && typeof collapse.index.value !== 'undefined'
23
+ ? props.index === collapse.index.value
24
+ : props.expand,
25
+ )
26
+
27
+ if (collapse?.accordion) {
28
+ watch(collapse?.index, () => {
29
+ expand.value = collapse?.index.value === props.index
30
+ })
31
+ }
32
+
33
+ function toggle() {
34
+ if (collapse?.accordion) {
35
+ if (collapse.index.value === props.index && expand.value) {
36
+ expand.value = false
37
+ }
38
+ else {
39
+ collapse!.index.value = props.index!
40
+ expand.value = true
41
+ }
42
+ }
43
+ else {
44
+ expand.value = !expand.value
45
+ }
46
+ }
47
+ </script>
48
+
49
+ <template>
50
+ <div class="vp-collapse-item" :class="{ expand }">
51
+ <div class="vp-collapse-header" @click="toggle">
52
+ <span class="vpi-chevron-right" />
53
+ <p class="vp-collapse-title">
54
+ <slot name="title" />
55
+ </p>
56
+ </div>
57
+ <VPFadeInExpandTransition>
58
+ <div v-show="expand" class="vp-collapse-content">
59
+ <div class="vp-collapse-content-inner">
60
+ <slot />
61
+ </div>
62
+ </div>
63
+ </VPFadeInExpandTransition>
64
+ </div>
65
+ </template>
66
+
67
+ <style>
68
+ .vp-collapse-item {
69
+ display: flex;
70
+ flex-direction: column;
71
+ padding-top: 16px;
72
+ border-top: solid 1px var(--vp-c-divider);
73
+ }
74
+
75
+ .vp-collapse-item:first-child {
76
+ border-top: none;
77
+ }
78
+
79
+ .vp-collapse-header {
80
+ display: flex;
81
+ gap: 6px;
82
+ align-items: center;
83
+ font-size: 16px;
84
+ font-weight: 600;
85
+ cursor: pointer;
86
+ }
87
+
88
+ .vp-collapse-header .vpi-chevron-right {
89
+ align-self: baseline;
90
+ width: 20px;
91
+ height: 20px;
92
+ transition: transform var(--vp-t-color);
93
+ transform: rotate(0deg);
94
+ }
95
+
96
+ .vp-collapse-item.expand .vpi-chevron-right {
97
+ transform: rotate(90deg);
98
+ }
99
+
100
+ .vp-collapse-header .vp-collapse-title {
101
+ flex: 1 2;
102
+ margin: 0;
103
+ line-height: 1;
104
+ }
105
+
106
+ .vp-collapse-content-inner {
107
+ padding-top: 12px;
108
+ padding-left: 24px;
109
+ }
110
+
111
+ .vp-collapse-content-inner > *:first-child {
112
+ margin-top: 0;
113
+ }
114
+
115
+ .vp-collapse-content-inner > *:last-child {
116
+ margin-bottom: 0;
117
+ }
118
+ </style>
@@ -0,0 +1,154 @@
1
+ <script setup lang="ts">
2
+ import { Transition, TransitionGroup } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ group?: boolean
6
+ appear?: boolean
7
+ mode?: 'in-out' | 'out-in' | 'default'
8
+ onLeave?: () => void
9
+ onAfterLeave?: () => void
10
+ onAfterEnter?: () => void
11
+ width?: boolean
12
+ }>()
13
+
14
+ function handleBeforeLeave(el: HTMLElement): void {
15
+ if (props.width) {
16
+ el.style.maxWidth = `${el.offsetWidth}px`
17
+ }
18
+ else {
19
+ el.style.maxHeight = `${el.offsetHeight}px`
20
+ }
21
+ void el.offsetWidth
22
+ }
23
+
24
+ function handleLeave(el: HTMLElement): void {
25
+ if (props.width) {
26
+ el.style.maxWidth = '0'
27
+ }
28
+ else {
29
+ el.style.maxHeight = '0'
30
+ }
31
+ void el.offsetWidth
32
+ props.onLeave?.()
33
+ }
34
+
35
+ function handleAfterLeave(el: HTMLElement): void {
36
+ if (props.width) {
37
+ el.style.maxWidth = ''
38
+ }
39
+ else {
40
+ el.style.maxHeight = ''
41
+ }
42
+ props.onAfterLeave?.()
43
+ }
44
+
45
+ function handleEnter(el: HTMLElement): void {
46
+ el.style.transition = 'none'
47
+ if (props.width) {
48
+ const memorizedWidth = el.offsetWidth
49
+ el.style.maxWidth = '0'
50
+ void el.offsetWidth
51
+ el.style.transition = ''
52
+ el.style.maxWidth = `${memorizedWidth}px`
53
+ }
54
+ else {
55
+ const memorizedHeight = el.offsetHeight
56
+ el.style.maxHeight = '0'
57
+ void el.offsetWidth
58
+ el.style.transition = ''
59
+ el.style.maxHeight = `${memorizedHeight}px`
60
+ }
61
+ void el.offsetWidth
62
+ }
63
+
64
+ function handleAfterEnter(el: HTMLElement): void {
65
+ if (props.width) {
66
+ el.style.maxWidth = ''
67
+ }
68
+ else {
69
+ el.style.maxHeight = ''
70
+ }
71
+ props.onAfterEnter?.()
72
+ }
73
+ </script>
74
+
75
+ <template>
76
+ <component
77
+ :is="group ? TransitionGroup : Transition"
78
+ :name="width ? 'fade-in-width-expand' : 'fade-in-height-expand'"
79
+ :mode
80
+ :appear
81
+ @enter="handleEnter"
82
+ @after-enter="handleAfterEnter"
83
+ @before-leave="handleBeforeLeave"
84
+ @leave="handleLeave"
85
+ @after-leave="handleAfterLeave"
86
+ >
87
+ <slot />
88
+ </component>
89
+ </template>
90
+
91
+ <style>
92
+ .fade-in-height-expand-leave-from,
93
+ .fade-in-height-expand-enter-to,
94
+ .fade-in-width-expand-leave-from,
95
+ .fade-in-width-expand-enter-to {
96
+ opacity: 1;
97
+ }
98
+
99
+ .fade-in-height-expand-leave-to,
100
+ .fade-in-height-expand-enter-from {
101
+ padding-top: 0 !important;
102
+ padding-bottom: 0 !important;
103
+ margin-top: 0 !important;
104
+ margin-bottom: 0 !important;
105
+ opacity: 0;
106
+ }
107
+
108
+ .fade-in-height-expand-leave-active {
109
+ overflow: hidden;
110
+ transition:
111
+ max-height cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
112
+ opacity cubic-bezier(0, 0, 0.2, 1) 0.3s,
113
+ margin-top cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
114
+ margin-bottom cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
115
+ padding-top cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
116
+ padding-bottom cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
117
+ }
118
+
119
+ .fade-in-height-expand-enter-active {
120
+ overflow: hidden;
121
+ transition:
122
+ max-height cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
123
+ opacity cubic-bezier(0.4, 0, 1, 1) 0.3s,
124
+ margin-top cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
125
+ margin-bottom cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
126
+ padding-top cubic-bezier(0.4, 0, 0.2, 1) 0.3s,
127
+ padding-bottom cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
128
+ }
129
+
130
+ .fade-in-width-expand-leave-to,
131
+ .fade-in-width-expand-enter-from {
132
+ margin-right: 0 !important;
133
+ margin-left: 0 !important;
134
+ opacity: 0 !important;
135
+ }
136
+
137
+ .fade-in-width-expand-leave-active {
138
+ overflow: hidden;
139
+ transition:
140
+ max-width cubic-bezier(0.4, 0, 0.2, 1) 0.2s 0.1s,
141
+ opacity cubic-bezier(0.4, 0, 0.2, 1) 0.2s,
142
+ margin-right cubic-bezier(0.4, 0, 0.2, 1) 0.2s 0.1s,
143
+ margin-left cubic-bezier(0.4, 0, 0.2, 1) 0.2s 0.1s;
144
+ }
145
+
146
+ .fade-in-width-expand-enter-active {
147
+ overflow: hidden;
148
+ transition:
149
+ max-width cubic-bezier(0.4, 0, 0.2, 1) 0.2s,
150
+ opacity cubic-bezier(0.4, 0, 0.2, 1) 0.2s 0.1s,
151
+ margin-right cubic-bezier(0.4, 0, 0.2, 1) 0.2s,
152
+ margin-left cubic-bezier(0.4, 0, 0.2, 1) 0.2s;
153
+ }
154
+ </style>
@@ -0,0 +1,52 @@
1
+ <script lang="ts" setup>
2
+ import { computed, provide } from 'vue'
3
+ import { INJECT_TIMELINE_KEY } from '../options.js'
4
+
5
+ const props = defineProps<{
6
+ horizontal?: boolean
7
+ card?: boolean
8
+ placement?: 'left' | 'right' | 'between'
9
+ line?: 'solid' | 'dashed' | 'dotted'
10
+ }>()
11
+
12
+ provide(INJECT_TIMELINE_KEY, computed(() => ({
13
+ line: props.line || 'solid',
14
+ card: props.card ?? false,
15
+ horizontal: props.horizontal ?? false,
16
+ placement: props.placement || 'left',
17
+ })))
18
+ </script>
19
+
20
+ <template>
21
+ <div class="vp-timeline" :class="{ horizontal }">
22
+ <div class="vp-timeline-box">
23
+ <slot />
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <style>
29
+ .vp-timeline {
30
+ position: relative;
31
+ margin: 32px 0;
32
+ }
33
+
34
+ .vp-timeline.horizontal {
35
+ padding-bottom: 7px;
36
+ overflow-x: auto;
37
+ }
38
+
39
+ .vp-timeline-box {
40
+ display: flex;
41
+ gap: 24px 36px;
42
+ }
43
+
44
+ .vp-timeline:not(.horizontal) .vp-timeline-box {
45
+ flex-direction: column;
46
+ }
47
+
48
+ .vp-timeline.horizontal .vp-timeline-box {
49
+ flex-direction: row;
50
+ width: max-content;
51
+ }
52
+ </style>
@@ -0,0 +1,330 @@
1
+ <script lang="ts" setup>
2
+ import type { ComputedRef } from 'vue'
3
+ import { useMediaQuery } from '@vueuse/core'
4
+ import { computed, inject } from 'vue'
5
+ import { INJECT_TIMELINE_KEY } from '../options.js'
6
+
7
+ const props = defineProps<{
8
+ time?: string
9
+ type?: 'info' | 'tip' | 'success' | 'warning' | 'danger' | 'caution' | 'important' | (string & {})
10
+ card?: boolean
11
+ line?: 'solid' | 'dashed' | 'dotted'
12
+ icon?: string
13
+ color?: string
14
+ placement?: 'left' | 'right'
15
+ }>()
16
+
17
+ const is639 = useMediaQuery('(max-width: 639px)')
18
+
19
+ const defaultOptions = inject<ComputedRef<{
20
+ line?: 'solid' | 'dashed' | 'dotted'
21
+ card?: boolean
22
+ horizontal?: boolean
23
+ placement?: 'left' | 'right' | 'between'
24
+ }>>(INJECT_TIMELINE_KEY)
25
+
26
+ const timeline = computed(() => {
27
+ const between = defaultOptions?.value.placement === 'between' && !is639.value
28
+ const placement = defaultOptions?.value.placement === 'between' ? 'left' : defaultOptions?.value.placement
29
+ return {
30
+ time: props.time,
31
+ type: props.type || 'info',
32
+ line: props.line || defaultOptions?.value.line || 'solid',
33
+ icon: props.icon,
34
+ color: props.color,
35
+ horizontal: defaultOptions?.value.horizontal ?? false,
36
+ between: between ? props.placement || 'left' : false,
37
+ placement: between ? '' : (placement || 'left'),
38
+ card: props.card ?? defaultOptions?.value.card ?? false,
39
+ }
40
+ })
41
+ </script>
42
+
43
+ <template>
44
+ <div
45
+ class="vp-timeline-item" :class="{
46
+ card: timeline.card,
47
+ horizontal: timeline.horizontal,
48
+ [timeline.type]: true,
49
+ [`line-${timeline.line}`]: true,
50
+ [`placement-${timeline.placement}`]: !timeline.horizontal && timeline.placement,
51
+ between: timeline.between,
52
+ [`between-${timeline.between}`]: timeline.between,
53
+ }"
54
+ :style="timeline.color ? {
55
+ '--vp-timeline-c-line': timeline.color,
56
+ '--vp-timeline-c-point': timeline.color,
57
+ } : null"
58
+ >
59
+ <div class="vp-timeline-line" :class="{ 'has-icon': timeline.icon }">
60
+ <span class="vp-timeline-point">
61
+ <slot name="icon">
62
+ <VPIcon v-if="timeline.icon" :name="timeline.icon" />
63
+ </slot>
64
+ </span>
65
+ </div>
66
+ <div class="vp-timeline-container">
67
+ <div class="vp-timeline-content">
68
+ <p class="vp-timeline-title">
69
+ <slot name="title" />
70
+ </p>
71
+ <slot />
72
+ </div>
73
+ <p v-if="timeline.time" class="vp-timeline-time">
74
+ {{ timeline.time }}
75
+ </p>
76
+ </div>
77
+ </div>
78
+ </template>
79
+
80
+ <style>
81
+ :root,
82
+ .vp-timeline-item.info {
83
+ --vp-timeline-c-line: var(--vp-c-border);
84
+ --vp-timeline-c-point: var(--vp-c-border);
85
+ --vp-timeline-c-title: var(--vp-c-text-1);
86
+ --vp-timeline-c-text: var(--vp-c-text-1);
87
+ --vp-timeline-c-time: var(--vp-c-text-3);
88
+ --vp-timeline-c-icon: var(--vp-c-bg);
89
+ --vp-timeline-bg-card: var(--vp-c-bg-soft);
90
+ }
91
+
92
+ .vp-timeline-item.tip {
93
+ --vp-timeline-c-line: var(--vp-c-tip-1);
94
+ --vp-timeline-c-point: var(--vp-c-tip-1);
95
+ --vp-timeline-bg-card: var(--vp-c-tip-soft);
96
+ }
97
+
98
+ .vp-timeline-item.success {
99
+ --vp-timeline-c-line: var(--vp-c-success-3);
100
+ --vp-timeline-c-point: var(--vp-c-success-3);
101
+ --vp-timeline-bg-card: var(--vp-c-success-soft);
102
+ }
103
+
104
+ .vp-timeline-item.warning {
105
+ --vp-timeline-c-line: var(--vp-c-warning-3);
106
+ --vp-timeline-c-point: var(--vp-c-warning-3);
107
+ --vp-timeline-bg-card: var(--vp-c-warning-soft);
108
+ }
109
+
110
+ .vp-timeline-item.danger {
111
+ --vp-timeline-c-line: var(--vp-c-danger-3);
112
+ --vp-timeline-c-point: var(--vp-c-danger-3);
113
+ --vp-timeline-bg-card: var(--vp-c-danger-soft);
114
+ }
115
+
116
+ .vp-timeline-item.caution {
117
+ --vp-timeline-c-line: var(--vp-c-caution-3);
118
+ --vp-timeline-c-point: var(--vp-c-caution-3);
119
+ --vp-timeline-bg-card: var(--vp-c-caution-soft);
120
+ }
121
+
122
+ .vp-timeline-item.important {
123
+ --vp-timeline-c-line: var(--vp-c-important-3);
124
+ --vp-timeline-c-point: var(--vp-c-important-3);
125
+ --vp-timeline-bg-card: var(--vp-c-important-soft);
126
+ }
127
+
128
+ .vp-timeline-item {
129
+ position: relative;
130
+ display: flex;
131
+ }
132
+
133
+ .vp-timeline-item:not(.horizontal).between {
134
+ width: calc(50% - 18px);
135
+ }
136
+
137
+ .vp-timeline-item.horizontal {
138
+ padding-top: 36px;
139
+ }
140
+
141
+ .vp-timeline-item > .vp-timeline-line {
142
+ position: absolute;
143
+ }
144
+
145
+ .vp-timeline-item:not(.horizontal).placement-left {
146
+ justify-content: flex-start;
147
+ padding-left: 36px;
148
+ }
149
+
150
+ .vp-timeline-item:not(.horizontal).placement-right,
151
+ .vp-timeline-item:not(.horizontal).between {
152
+ justify-content: flex-end;
153
+ padding-right: 36px;
154
+ text-align: right;
155
+ }
156
+
157
+ .vp-timeline-item:not(.horizontal) > .vp-timeline-line {
158
+ top: 0;
159
+ bottom: 0;
160
+ width: 0;
161
+ }
162
+
163
+ .vp-timeline-item.horizontal > .vp-timeline-line {
164
+ top: 12px;
165
+ right: 0;
166
+ left: 0;
167
+ height: 0;
168
+ }
169
+
170
+ .vp-timeline-item:not(.horizontal).card > .vp-timeline-line {
171
+ top: 14px;
172
+ }
173
+
174
+ .vp-timeline-item:not(.horizontal).placement-left > .vp-timeline-line {
175
+ left: 12px;
176
+ }
177
+
178
+ .vp-timeline-item:not(.horizontal).placement-right > .vp-timeline-line,
179
+ .vp-timeline-item:not(.horizontal).between > .vp-timeline-line {
180
+ right: 12px;
181
+ }
182
+
183
+ .vp-timeline-item > .vp-timeline-line::before {
184
+ position: absolute;
185
+ display: block;
186
+ content: "";
187
+ border: none;
188
+ }
189
+
190
+ .vp-timeline-item:not(.horizontal) > .vp-timeline-line::before {
191
+ top: 10px;
192
+ bottom: -48px;
193
+ border-left: 2px solid var(--vp-timeline-c-line);
194
+ }
195
+
196
+ .vp-timeline-item.horizontal > .vp-timeline-line::before {
197
+ right: -46px;
198
+ left: 8px;
199
+ border-top: 2px solid var(--vp-timeline-c-line);
200
+ }
201
+
202
+ .vp-timeline-item:not(.horizontal):last-of-type > .vp-timeline-line::before {
203
+ bottom: 0 !important;
204
+ }
205
+
206
+ .vp-timeline-item.horizontal:last-of-type > .vp-timeline-line::before {
207
+ right: 0 !important;
208
+ }
209
+
210
+ .vp-timeline-item:not(.horizontal).line-dashed > .vp-timeline-line::before {
211
+ border-left-style: dashed;
212
+ }
213
+
214
+ .vp-timeline-item:not(.horizontal).line-dotted > .vp-timeline-line::before {
215
+ border-left-style: dotted;
216
+ }
217
+
218
+ .vp-timeline-item.horizontal.line-dashed > .vp-timeline-line::before {
219
+ border-top-style: dashed;
220
+ }
221
+
222
+ .vp-timeline-item.horizontal.line-dotted > .vp-timeline-line::before {
223
+ border-top-style: dotted;
224
+ }
225
+
226
+ .vp-timeline-item > .vp-timeline-line .vp-timeline-point {
227
+ position: absolute;
228
+ width: 16px;
229
+ height: 16px;
230
+ background-color: var(--vp-timeline-c-point);
231
+ border-radius: 50%;
232
+ transition: background-color var(--vp-t-color);
233
+ }
234
+
235
+ .vp-timeline-item:not(.horizontal) > .vp-timeline-line .vp-timeline-point {
236
+ top: 4px;
237
+ left: -7px;
238
+ }
239
+
240
+ .vp-timeline-item.horizontal > .vp-timeline-line .vp-timeline-point {
241
+ top: -7px;
242
+ left: 0;
243
+ }
244
+
245
+ .vp-timeline-item > .vp-timeline-line.has-icon .vp-timeline-point {
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ width: 24px;
250
+ height: 24px;
251
+ }
252
+
253
+ .vp-timeline-item:not(.horizontal) > .vp-timeline-line.has-icon .vp-timeline-point {
254
+ top: -1px;
255
+ left: -11px;
256
+ }
257
+
258
+ .vp-timeline-item.horizontal > .vp-timeline-line.has-icon .vp-timeline-point {
259
+ top: -11px;
260
+ left: 0;
261
+ }
262
+
263
+ .vp-timeline-item > .vp-timeline-line.has-icon .vp-timeline-point .vp-icon {
264
+ width: 16px;
265
+ height: 16px;
266
+ margin: 0;
267
+ color: var(--vp-timeline-c-icon);
268
+ }
269
+
270
+ .vp-timeline-item .vp-timeline-container {
271
+ width: max-content;
272
+ max-width: 100%;
273
+ font-size: 16px;
274
+ line-height: 1.5;
275
+ color: var(--vp-timeline-c-text);
276
+ transition: color var(--vp-t-color);
277
+ }
278
+
279
+ .vp-timeline-item.horizontal .vp-timeline-container {
280
+ max-width: 240px;
281
+ }
282
+
283
+ .vp-timeline-item:not(.horizontal).between-right .vp-timeline-container {
284
+ text-align: left;
285
+ transform: translateX(calc(100% + 48px));
286
+ }
287
+
288
+ .vp-timeline-item.card .vp-timeline-content {
289
+ padding: 16px;
290
+ background-color: var(--vp-timeline-bg-card);
291
+ border-radius: 6px;
292
+ }
293
+
294
+ .vp-timeline-item .vp-timeline-content :where(p, ul, ol) {
295
+ margin: 8px 0;
296
+ line-height: 22px;
297
+ }
298
+
299
+ .vp-doc .vp-timeline-item .vp-timeline-content div[class*="language-"] {
300
+ margin: 16px 0;
301
+ }
302
+
303
+ .vp-timeline-item .vp-timeline-content li + li {
304
+ margin-top: 4px;
305
+ }
306
+
307
+ .vp-timeline-item .vp-timeline-content .vp-timeline-title {
308
+ margin: 0 0 8px;
309
+ font-size: 16px;
310
+ font-weight: 900;
311
+ color: var(--vp-timeline-c-title);
312
+ transition: color var(--vp-t-color);
313
+ }
314
+
315
+ .vp-timeline-item .vp-timeline-content > .vp-timeline-title + * {
316
+ margin-top: 0 !important;
317
+ }
318
+
319
+ .vp-timeline-item .vp-timeline-content > :last-child {
320
+ margin-bottom: 0 !important;
321
+ }
322
+
323
+ .vp-timeline-item .vp-timeline-time {
324
+ margin: 4px 0 0;
325
+ font-size: 14px;
326
+ font-weight: 500;
327
+ color: var(--vp-timeline-c-time);
328
+ transition: color var(--vp-t-color);
329
+ }
330
+ </style>
@@ -7,5 +7,7 @@ declare const installed: {
7
7
  mpegtsjs: boolean;
8
8
  };
9
9
  declare const ART_PLAYER_SUPPORTED_VIDEO_TYPES: string[];
10
+ declare const INJECT_TIMELINE_KEY: unique symbol;
11
+ declare const INJECT_COLLAPSE_KEY: unique symbol;
10
12
 
11
- export { ART_PLAYER_SUPPORTED_VIDEO_TYPES, installed, pluginOptions };
13
+ export { ART_PLAYER_SUPPORTED_VIDEO_TYPES, INJECT_COLLAPSE_KEY, INJECT_TIMELINE_KEY, installed, pluginOptions };
@@ -15,8 +15,16 @@ if (installed.hlsjs) {
15
15
  if (installed.mpegtsjs) {
16
16
  ART_PLAYER_SUPPORTED_VIDEO_TYPES.push("ts", "flv");
17
17
  }
18
+ var INJECT_TIMELINE_KEY = Symbol(
19
+ __VUEPRESS_DEV__ ? "timeline" : ""
20
+ );
21
+ var INJECT_COLLAPSE_KEY = Symbol(
22
+ __VUEPRESS_DEV__ ? "collapse" : ""
23
+ );
18
24
  export {
19
25
  ART_PLAYER_SUPPORTED_VIDEO_TYPES,
26
+ INJECT_COLLAPSE_KEY,
27
+ INJECT_TIMELINE_KEY,
20
28
  installed,
21
29
  pluginOptions
22
30
  };
@@ -218,6 +218,39 @@ interface MarkdownPowerPluginOptions {
218
218
  * @default false
219
219
  */
220
220
  plot?: boolean | PlotOptions;
221
+ /**
222
+ * 是否启用 timeline 语法
223
+ *
224
+ * ```md
225
+ * ::: timeline
226
+ * - title
227
+ * time="Q1" icon="ri:clockwise-line" line="dashed" type="warning" color="red"
228
+ *
229
+ * xxx
230
+ * :::
231
+ * ```
232
+ *
233
+ * @default false
234
+ */
235
+ timeline?: boolean;
236
+ /**
237
+ * 是否启用 collapse 折叠面板 语法
238
+ *
239
+ * ```md
240
+ * ::: collapse accordion
241
+ * - + title
242
+ *
243
+ * content
244
+ *
245
+ * - - title
246
+ *
247
+ * content
248
+ * :::
249
+ * ```
250
+ *
251
+ * @default false
252
+ */
253
+ collapse?: boolean;
221
254
  /**
222
255
  * 是否启用 bilibili 视频嵌入
223
256
  *
package/lib/node/index.js CHANGED
@@ -1158,14 +1158,14 @@ import { isPlainObject as isPlainObject2 } from "@vuepress/helper";
1158
1158
 
1159
1159
  // src/node/container/createContainer.ts
1160
1160
  import container from "markdown-it-container";
1161
- function createContainerPlugin(md, type2, options = {}) {
1162
- const render = (tokens, index) => {
1161
+ function createContainerPlugin(md, type2, { before, after } = {}) {
1162
+ const render = (tokens, index, options, env) => {
1163
1163
  const token = tokens[index];
1164
1164
  const info = token.info.trim().slice(type2.length).trim() || "";
1165
1165
  if (token.nesting === 1) {
1166
- return options.before?.(info, tokens, index) || `<div class="custom-container ${type2}">`;
1166
+ return before?.(info, tokens, index, options, env) || `<div class="custom-container ${type2}">`;
1167
1167
  } else {
1168
- return options.after?.(info, tokens, index) || "</div>";
1168
+ return after?.(info, tokens, index, options, env) || "</div>";
1169
1169
  }
1170
1170
  };
1171
1171
  md.use(container, type2, { render });
@@ -1209,6 +1209,91 @@ function cardPlugin(md) {
1209
1209
  });
1210
1210
  }
1211
1211
 
1212
+ // src/node/container/collapse.ts
1213
+ function collapsePlugin(md) {
1214
+ createContainerPlugin(md, "collapse", {
1215
+ before: (info, tokens, index) => {
1216
+ const { attrs: attrs2 } = resolveAttrs(info);
1217
+ const idx = parseCollapse(tokens, index, attrs2);
1218
+ const { accordion } = attrs2;
1219
+ return `<VPCollapse${accordion ? " accordion" : ""}${idx !== void 0 ? ` :index="${idx}"` : ""}>`;
1220
+ },
1221
+ after: () => `</VPCollapse>`
1222
+ });
1223
+ md.renderer.rules.collapse_item_open = (tokens, idx) => {
1224
+ const token = tokens[idx];
1225
+ const { expand, index } = token.meta;
1226
+ return `<VPCollapseItem${expand ? " expand" : ""}${` :index="${index}"`}>`;
1227
+ };
1228
+ md.renderer.rules.collapse_item_close = () => "</VPCollapseItem>";
1229
+ md.renderer.rules.collapse_item_title_open = () => "<template #title>";
1230
+ md.renderer.rules.collapse_item_title_close = () => "</template>";
1231
+ }
1232
+ function parseCollapse(tokens, index, attrs2) {
1233
+ const listStack = [];
1234
+ let idx = -1;
1235
+ let defaultIndex;
1236
+ let hashExpand = false;
1237
+ for (let i = index + 1; i < tokens.length; i++) {
1238
+ const token = tokens[i];
1239
+ if (token.type === "container_collapse_close") {
1240
+ break;
1241
+ }
1242
+ if (token.type === "bullet_list_open") {
1243
+ listStack.push(0);
1244
+ if (listStack.length === 1)
1245
+ token.hidden = true;
1246
+ } else if (token.type === "bullet_list_close") {
1247
+ listStack.pop();
1248
+ if (listStack.length === 0)
1249
+ token.hidden = true;
1250
+ } else if (token.type === "list_item_open") {
1251
+ const currentLevel = listStack.length;
1252
+ if (currentLevel === 1) {
1253
+ token.type = "collapse_item_open";
1254
+ tokens[i + 1].type = "collapse_item_title_open";
1255
+ tokens[i + 3].type = "collapse_item_title_close";
1256
+ idx++;
1257
+ const inlineToken = tokens[i + 2];
1258
+ const firstToken = inlineToken.children[0];
1259
+ let flag = "";
1260
+ let expand;
1261
+ if (firstToken.type === "text") {
1262
+ firstToken.content = firstToken.content.trim().replace(/^:[+\-]\s*/, (match) => {
1263
+ flag = match.trim();
1264
+ return "";
1265
+ });
1266
+ }
1267
+ if (attrs2.accordion) {
1268
+ if (!hashExpand && flag === ":+") {
1269
+ expand = hashExpand = true;
1270
+ defaultIndex = idx;
1271
+ }
1272
+ } else if (flag === ":+") {
1273
+ expand = true;
1274
+ } else if (flag === ":-") {
1275
+ expand = false;
1276
+ } else {
1277
+ expand = !!attrs2.expand;
1278
+ }
1279
+ token.meta = {
1280
+ index: idx,
1281
+ expand
1282
+ };
1283
+ }
1284
+ } else if (token.type === "list_item_close") {
1285
+ const currentLevel = listStack.length;
1286
+ if (currentLevel === 1) {
1287
+ token.type = "collapse_item_close";
1288
+ }
1289
+ }
1290
+ }
1291
+ if (attrs2.accordion && attrs2.expand && !hashExpand) {
1292
+ defaultIndex = 0;
1293
+ }
1294
+ return defaultIndex;
1295
+ }
1296
+
1212
1297
  // src/node/container/demoWrapper.ts
1213
1298
  function demoWrapperPlugin(md) {
1214
1299
  createContainerPlugin(md, "demo-wrapper", {
@@ -1823,6 +1908,99 @@ ${titles.map(
1823
1908
  });
1824
1909
  };
1825
1910
 
1911
+ // src/node/container/timeline.ts
1912
+ import { isEmptyObject } from "@pengzhanbo/utils";
1913
+ var RE_KEY = /(\w+)=\s*/;
1914
+ var RE_SEARCH_KEY = /\s+\w+=\s*|$/;
1915
+ var RE_CLEAN_VALUE = /(?<quote>["'])(.*?)(\k<quote>)/;
1916
+ function timelinePlugin(md) {
1917
+ createContainerPlugin(md, "timeline", {
1918
+ before(info, tokens, index) {
1919
+ parseTimeline(tokens, index);
1920
+ const { attrs: attrs2 } = resolveAttrs(info);
1921
+ const { horizontal, card, placement, line } = attrs2;
1922
+ return `<VPTimeline${horizontal ? " horizontal" : ""}${card ? " card" : ' :card="undefined"'}${placement ? ` placement="${placement}"` : ""}${line ? ` line="${line}"` : ""}>`;
1923
+ },
1924
+ after: () => "</VPTimeline>"
1925
+ });
1926
+ md.renderer.rules.timeline_item_open = (tokens, idx) => {
1927
+ const token = tokens[idx];
1928
+ const { time, type: type2, icon, color, line, card, placement } = token.meta;
1929
+ return `<VPTimelineItem${time ? ` time="${time}"` : ""}${type2 ? ` type="${type2}"` : ""}${color ? ` color="${color}"` : ""}${line ? ` line="${line}"` : ""}${icon ? ` icon="${icon}"` : ""}${card === "true" ? " card" : card === "false" ? "" : ' :card="undefined"'}${placement ? ` placement="${placement}"` : ""}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ""}`;
1930
+ };
1931
+ md.renderer.rules.timeline_item_close = () => "</VPTimelineItem>";
1932
+ md.renderer.rules.timeline_item_title_open = () => "<template #title>";
1933
+ md.renderer.rules.timeline_item_title_close = () => "</template>";
1934
+ }
1935
+ function parseTimeline(tokens, index) {
1936
+ const listStack = [];
1937
+ for (let i = index + 1; i < tokens.length; i++) {
1938
+ const token = tokens[i];
1939
+ if (token.type === "container_timeline_close") {
1940
+ break;
1941
+ }
1942
+ if (token.type === "bullet_list_open") {
1943
+ listStack.push(0);
1944
+ if (listStack.length === 1)
1945
+ token.hidden = true;
1946
+ } else if (token.type === "bullet_list_close") {
1947
+ listStack.pop();
1948
+ if (listStack.length === 0)
1949
+ token.hidden = true;
1950
+ } else if (token.type === "list_item_open") {
1951
+ const currentLevel = listStack.length;
1952
+ if (currentLevel === 1) {
1953
+ token.type = "timeline_item_open";
1954
+ tokens[i + 1].type = "timeline_item_title_open";
1955
+ tokens[i + 3].type = "timeline_item_title_close";
1956
+ const inlineToken = tokens[i + 2];
1957
+ const softbreakIndex = inlineToken.children.findLastIndex(
1958
+ (token2) => token2.type === "softbreak"
1959
+ );
1960
+ if (softbreakIndex !== -1) {
1961
+ const lastToken = inlineToken.children[inlineToken.children.length - 1];
1962
+ token.meta = extractTimelineAttributes(lastToken.content.trim());
1963
+ if (!isEmptyObject(token.meta)) {
1964
+ inlineToken.children = inlineToken.children.slice(0, softbreakIndex);
1965
+ }
1966
+ } else {
1967
+ token.meta = {};
1968
+ }
1969
+ }
1970
+ } else if (token.type === "list_item_close") {
1971
+ const currentLevel = listStack.length;
1972
+ if (currentLevel === 1) {
1973
+ token.type = "timeline_item_close";
1974
+ }
1975
+ }
1976
+ }
1977
+ }
1978
+ function extractTimelineAttributes(rawText) {
1979
+ const attrKeys = ["time", "type", "icon", "line", "color", "card", "placement"];
1980
+ const attrs2 = {};
1981
+ let buffer = rawText.trim();
1982
+ while (buffer.length) {
1983
+ const keyMatch = buffer.match(RE_KEY);
1984
+ if (!keyMatch) {
1985
+ break;
1986
+ }
1987
+ const matchedKey = keyMatch[1].toLowerCase();
1988
+ if (!attrKeys.includes(matchedKey)) {
1989
+ break;
1990
+ }
1991
+ const keyStart = keyMatch.index;
1992
+ const keyEnd = keyStart + keyMatch[0].length;
1993
+ buffer = buffer.slice(keyEnd);
1994
+ let valueEnd = buffer.search(RE_SEARCH_KEY);
1995
+ if (valueEnd === -1)
1996
+ valueEnd = buffer.length;
1997
+ const value = buffer.slice(0, valueEnd).trim();
1998
+ attrs2[matchedKey] = value.replace(RE_CLEAN_VALUE, "$2");
1999
+ buffer = buffer.slice(valueEnd);
2000
+ }
2001
+ return attrs2;
2002
+ }
2003
+
1826
2004
  // src/node/container/index.ts
1827
2005
  async function containerPlugin(app, md, options) {
1828
2006
  alignPlugin(md);
@@ -1839,6 +2017,10 @@ async function containerPlugin(app, md, options) {
1839
2017
  if (options.fileTree) {
1840
2018
  fileTreePlugin(md, isPlainObject2(options.fileTree) ? options.fileTree : {});
1841
2019
  }
2020
+ if (options.timeline)
2021
+ timelinePlugin(md);
2022
+ if (options.collapse)
2023
+ collapsePlugin(md);
1842
2024
  }
1843
2025
 
1844
2026
  // src/node/demo/demo.ts
@@ -3428,6 +3610,18 @@ async function prepareConfigFile(app, options) {
3428
3610
  imports.add(`import Abbreviation from '${CLIENT_FOLDER}components/Abbreviation.vue'`);
3429
3611
  enhances.add(`app.component('Abbreviation', Abbreviation)`);
3430
3612
  }
3613
+ if (options.timeline) {
3614
+ imports.add(`import VPTimeline from '${CLIENT_FOLDER}components/VPTimeline.vue'`);
3615
+ imports.add(`import VPTimelineItem from '${CLIENT_FOLDER}components/VPTimelineItem.vue'`);
3616
+ enhances.add(`app.component('VPTimeline', VPTimeline)`);
3617
+ enhances.add(`app.component('VPTimelineItem', VPTimelineItem)`);
3618
+ }
3619
+ if (options.collapse) {
3620
+ imports.add(`import VPCollapse from '${CLIENT_FOLDER}components/VPCollapse.vue'`);
3621
+ imports.add(`import VPCollapseItem from '${CLIENT_FOLDER}components/VPCollapseItem.vue'`);
3622
+ enhances.add(`app.component('VPCollapse', VPCollapse)`);
3623
+ enhances.add(`app.component('VPCollapseItem', VPCollapseItem)`);
3624
+ }
3431
3625
  return app.writeTemp(
3432
3626
  "md-power/config.js",
3433
3627
  `import { defineClientConfig } from 'vuepress/client'
@@ -217,6 +217,39 @@ interface MarkdownPowerPluginOptions {
217
217
  * @default false
218
218
  */
219
219
  plot?: boolean | PlotOptions;
220
+ /**
221
+ * 是否启用 timeline 语法
222
+ *
223
+ * ```md
224
+ * ::: timeline
225
+ * - title
226
+ * time="Q1" icon="ri:clockwise-line" line="dashed" type="warning" color="red"
227
+ *
228
+ * xxx
229
+ * :::
230
+ * ```
231
+ *
232
+ * @default false
233
+ */
234
+ timeline?: boolean;
235
+ /**
236
+ * 是否启用 collapse 折叠面板 语法
237
+ *
238
+ * ```md
239
+ * ::: collapse accordion
240
+ * - + title
241
+ *
242
+ * content
243
+ *
244
+ * - - title
245
+ *
246
+ * content
247
+ * :::
248
+ * ```
249
+ *
250
+ * @default false
251
+ */
252
+ collapse?: boolean;
220
253
  /**
221
254
  * 是否启用 bilibili 视频嵌入
222
255
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vuepress-plugin-md-power",
3
3
  "type": "module",
4
- "version": "1.0.0-rc.136",
4
+ "version": "1.0.0-rc.137",
5
5
  "description": "The Plugin for VuePress 2 - markdown power",
6
6
  "author": "pengzhanbo <volodymyr@foxmail.com>",
7
7
  "license": "MIT",
@@ -38,8 +38,8 @@
38
38
  "less": "^4.2.2",
39
39
  "markdown-it": "^14.1.0",
40
40
  "mpegts.js": "^1.7.3",
41
- "sass": "^1.85.1",
42
- "sass-embedded": "^1.85.1",
41
+ "sass": "^1.86.0",
42
+ "sass-embedded": "^1.86.0",
43
43
  "stylus": "^0.64.0",
44
44
  "vuepress": "2.0.0-rc.20"
45
45
  },
@@ -68,6 +68,7 @@
68
68
  "@mdit/plugin-sup": "^0.16.0",
69
69
  "@mdit/plugin-tab": "^0.16.0",
70
70
  "@mdit/plugin-tasklist": "^0.16.0",
71
+ "@pengzhanbo/utils": "^1.2.0",
71
72
  "@vuepress/helper": "2.0.0-rc.82",
72
73
  "@vueuse/core": "^13.0.0",
73
74
  "chokidar": "3.6.0",
@@ -75,9 +76,9 @@
75
76
  "local-pkg": "^1.1.1",
76
77
  "lru-cache": "^11.0.2",
77
78
  "markdown-it-container": "^4.0.0",
78
- "nanoid": "^5.1.3",
79
+ "nanoid": "^5.1.5",
79
80
  "shiki": "^3.2.1",
80
- "tm-grammars": "^1.23.3",
81
+ "tm-grammars": "^1.23.5",
81
82
  "tm-themes": "^1.10.1",
82
83
  "vue": "^3.5.13"
83
84
  },