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

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.
@@ -1,11 +1,27 @@
1
1
  <script setup lang="ts">
2
2
  import type { CSSProperties } from 'vue'
3
+ import { onClickOutside, useMediaQuery, useToggle } from '@vueuse/core'
3
4
  import { nextTick, ref, useTemplateRef, watch } from 'vue'
4
5
 
5
- const show = ref(false)
6
+ import '@vuepress/helper/transition/fade-in.css'
7
+
8
+ const [show, toggle] = useToggle(false)
9
+
10
+ const el = useTemplateRef<HTMLSpanElement>('el')
6
11
  const tooltip = useTemplateRef<HTMLSpanElement>('tooltip')
7
12
  const styles = ref<CSSProperties>()
8
13
 
14
+ const isMobile = useMediaQuery('(max-width: 768px)')
15
+ const showTooltip = () => toggle(true)
16
+ const hiddenTooltip = () => toggle(false)
17
+
18
+ onClickOutside(el, () => {
19
+ if (isMobile.value)
20
+ hiddenTooltip()
21
+ }, {
22
+ ignore: [tooltip],
23
+ })
24
+
9
25
  watch(show, () => nextTick(() => {
10
26
  if (__VUEPRESS_SSR__)
11
27
  return
@@ -32,11 +48,24 @@ watch(show, () => nextTick(() => {
32
48
  </script>
33
49
 
34
50
  <template>
35
- <span class="vp-abbr" @mouseenter="show = true" @mouseleave="show = false">
51
+ <span
52
+ ref="el"
53
+ class="vp-abbr"
54
+ role="tooltip"
55
+ tabindex="0"
56
+ v-bind="isMobile ? {
57
+ onClick: showTooltip,
58
+ } : {
59
+ onMouseenter: showTooltip,
60
+ onMouseleave: hiddenTooltip,
61
+ onFocus: showTooltip,
62
+ onBlur: hiddenTooltip,
63
+ }"
64
+ >
36
65
  <slot />
37
66
  <ClientOnly>
38
- <Transition name="fade">
39
- <span v-show="show" ref="tooltip" class="vp-abbr-tooltip ignore-header" :style="styles">
67
+ <Transition name="fade-in">
68
+ <span v-show="show" ref="tooltip" class="vp-abbr-tooltip ignore-header" :style="styles" aria-hidden="true">
40
69
  <slot name="tooltip" />
41
70
  </span>
42
71
  </Transition>
@@ -2,6 +2,8 @@
2
2
  import { onClickOutside, useEventListener } from '@vueuse/core'
3
3
  import { computed, nextTick, ref, useTemplateRef, watch } from 'vue'
4
4
 
5
+ import '@vuepress/helper/transition/fade-in.css'
6
+
5
7
  const props = defineProps<{
6
8
  label: string
7
9
  total: number
@@ -44,10 +46,15 @@ useEventListener('scroll', updatePosition, { passive: true })
44
46
  </script>
45
47
 
46
48
  <template>
47
- <span class="vp-annotation ignore-header" :class="{ active, [label]: true }" :aria-label="label">
48
- <span ref="button" class="vpi-annotation" @click="active = !active" />
49
+ <span class="vp-annotation ignore-header" :class="{ active, [label]: true }">
50
+ <span
51
+ ref="button"
52
+ :aria-label="label"
53
+ class="vpi-annotation"
54
+ @click="active = !active"
55
+ />
49
56
  <ClientOnly>
50
- <Transition name="fade">
57
+ <Transition name="fade-in">
51
58
  <div
52
59
  v-show="active" ref="popover"
53
60
  class="annotations-popover" :class="{ list: list.length > 1 }"
@@ -73,8 +80,8 @@ useEventListener('scroll', updatePosition, { passive: true })
73
80
  position: relative;
74
81
  top: -2px;
75
82
  z-index: 2;
76
- width: 1.2em;
77
- height: 1.2em;
83
+ width: 1.5em;
84
+ height: 1.5em;
78
85
  color: currentcolor;
79
86
  cursor: pointer;
80
87
  opacity: 0.5;
@@ -81,6 +81,7 @@ onUnmounted(() => {
81
81
  <template>
82
82
  <div ref="editorEl" class="code-repl-editor">
83
83
  <slot />
84
+ <!-- eslint-disable-next-line vue-a11y/form-control-has-label -->
84
85
  <textarea ref="textAreaEl" v-model="input" class="code-repl-input" />
85
86
  </div>
86
87
  </template>
@@ -1,8 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import type { Ref } from 'vue'
3
+ import { FadeInExpandTransition } from '@vuepress/helper/client'
3
4
  import { inject, ref, watch } from 'vue'
4
5
  import { INJECT_COLLAPSE_KEY } from '../options.js'
5
- import VPFadeInExpandTransition from './VPFadeInExpandTransition.vue'
6
+
7
+ import '@vuepress/helper/transition/fade-in-height-expand.css'
6
8
 
7
9
  const props = defineProps<{
8
10
  expand?: boolean
@@ -54,13 +56,13 @@ function toggle() {
54
56
  <slot name="title" />
55
57
  </p>
56
58
  </div>
57
- <VPFadeInExpandTransition>
59
+ <FadeInExpandTransition>
58
60
  <div v-show="expand" class="vp-collapse-content">
59
61
  <div class="vp-collapse-content-inner">
60
62
  <slot />
61
63
  </div>
62
64
  </div>
63
- </VPFadeInExpandTransition>
65
+ </FadeInExpandTransition>
64
66
  </div>
65
67
  </template>
66
68
 
@@ -1,6 +1,11 @@
1
1
  <script setup lang="ts">
2
+ import { FadeInExpandTransition } from '@vuepress/helper/client'
3
+ import { useResizeObserver } from '@vueuse/core'
4
+ import { useTemplateRef, watch } from 'vue'
5
+ import { ClientOnly, onContentUpdated } from 'vuepress/client'
2
6
  import { useExpand } from '../composables/demo.js'
3
7
 
8
+ import '@vuepress/helper/transition/fade-in-height-expand.css'
4
9
  import '../styles/demo.css'
5
10
 
6
11
  const props = defineProps<{
@@ -11,12 +16,51 @@ const props = defineProps<{
11
16
  }>()
12
17
 
13
18
  const [showCode, toggleCode] = useExpand(props.expanded)
19
+
20
+ const draw = useTemplateRef<HTMLIFrameElement>('draw')
21
+ const vueDraw = useTemplateRef<HTMLIFrameElement>('draw-vue')
22
+
23
+ function resizeAndPositionVueDraw() {
24
+ if (!draw.value || !vueDraw.value)
25
+ return
26
+ const rect = draw.value.getBoundingClientRect()
27
+ const { scrollLeft, scrollTop } = document.documentElement
28
+ vueDraw.value.style.width = `${draw.value.offsetWidth - 48}px`
29
+ vueDraw.value.style.top = `${rect.top + scrollTop}px`
30
+ vueDraw.value.style.left = `${rect.x + scrollLeft}px`
31
+ }
32
+
33
+ if (props.type === 'vue' && !__VUEPRESS_SSR__) {
34
+ watch([draw, vueDraw], () => {
35
+ resizeAndPositionVueDraw()
36
+ if (draw.value && vueDraw.value) {
37
+ requestAnimationFrame(() => {
38
+ draw.value!.style.height = `${vueDraw.value!.offsetHeight}px`
39
+ })
40
+ }
41
+ }, { immediate: true })
42
+ useResizeObserver(draw, resizeAndPositionVueDraw)
43
+ useResizeObserver(() => document.body, resizeAndPositionVueDraw)
44
+ onContentUpdated(resizeAndPositionVueDraw)
45
+
46
+ useResizeObserver(vueDraw, () => {
47
+ if (draw.value && vueDraw.value)
48
+ draw.value.style.height = `${vueDraw.value.offsetHeight}px`
49
+ })
50
+ }
14
51
  </script>
15
52
 
16
53
  <template>
17
- <div class="vp-demo-wrapper">
18
- <div class="demo-draw">
19
- <slot />
54
+ <div class="vp-demo-wrapper" :class="{ type }">
55
+ <div ref="draw" class="demo-draw">
56
+ <slot v-if="type !== 'vue'" />
57
+ <ClientOnly v-else>
58
+ <Teleport to="body">
59
+ <div ref="draw-vue" class="demo-draw-vue">
60
+ <slot />
61
+ </div>
62
+ </Teleport>
63
+ </ClientOnly>
20
64
  </div>
21
65
  <div v-if="title || desc" class="demo-info">
22
66
  <p v-if="title" class="title">
@@ -27,10 +71,14 @@ const [showCode, toggleCode] = useExpand(props.expanded)
27
71
  </p>
28
72
  </div>
29
73
  <div class="demo-ctrl">
30
- <span class="vpi-demo-code" @click="toggleCode" />
31
- </div>
32
- <div v-show="showCode" class="demo-code">
33
- <slot name="code" />
74
+ <button type="button" aria-label="Toggle Code" @click="toggleCode">
75
+ <span class="vpi-demo-code" />
76
+ </button>
34
77
  </div>
78
+ <FadeInExpandTransition>
79
+ <div v-show="showCode" class="demo-code">
80
+ <slot name="code" />
81
+ </div>
82
+ </FadeInExpandTransition>
35
83
  </div>
36
84
  </template>
@@ -1,8 +1,11 @@
1
1
  <script setup lang="ts">
2
2
  import type { DemoConfig } from '../composables/demo.js'
3
+ import { FadeInExpandTransition } from '@vuepress/helper/client'
3
4
  import { useTemplateRef } from 'vue'
4
5
  import { useExpand, useFence, useNormalDemo, useResources } from '../composables/demo.js'
5
6
 
7
+ import '@vuepress/helper/transition/fade-in.css'
8
+ import '@vuepress/helper/transition/fade-in-height-expand.css'
6
9
  import '../styles/demo.css'
7
10
 
8
11
  const props = defineProps<{
@@ -37,6 +40,7 @@ const data = useFence(
37
40
  <iframe
38
41
  :id="`VPDemoNormalDraw${id}`"
39
42
  ref="draw"
43
+ :title="title || 'Demo'"
40
44
  class="draw-iframe"
41
45
  allow="accelerometer *; bluetooth *; camera *; encrypted-media *; display-capture *; geolocation *; gyroscope *; microphone *; midi *; clipboard-read *; clipboard-write *; web-share *; serial *; xr-spatial-tracking *"
42
46
  allowfullscreen="true"
@@ -90,7 +94,7 @@ const data = useFence(
90
94
  </div>
91
95
  <div v-if="resources.length" class="demo-resources">
92
96
  <span ref="resourcesEl" class="vpi-demo-resources" title="Resources" aria-label="Resources" @click="toggleResources" />
93
- <Transition name="fade">
97
+ <Transition name="fade-in">
94
98
  <div v-show="showResources" class="demo-resources-container">
95
99
  <div v-for="{ name, items } in resources" :key="name" class="demo-resources-list">
96
100
  <p>{{ name }}</p>
@@ -103,10 +107,14 @@ const data = useFence(
103
107
  </div>
104
108
  </Transition>
105
109
  </div>
106
- <span class="vpi-demo-code" @click="toggleCode" />
107
- </div>
108
- <div v-show="showCode" ref="fence" class="demo-code">
109
- <slot />
110
+ <button type="button" aria-label="Toggle Code" @click="toggleCode">
111
+ <span class="vpi-demo-code" />
112
+ </button>
110
113
  </div>
114
+ <FadeInExpandTransition>
115
+ <div v-show="showCode" ref="fence" class="demo-code">
116
+ <slot />
117
+ </div>
118
+ </FadeInExpandTransition>
111
119
  </div>
112
120
  </template>
@@ -1,5 +1,12 @@
1
1
  import type { ReplEditorData } from '../shared/repl.js'
2
2
 
3
+ declare module '*.vue' {
4
+ import type { ComponentOptions } from 'vue'
5
+
6
+ const comp: ComponentOptions
7
+ export default comp
8
+ }
9
+
3
10
  declare module '@internal/md-power/replEditorData' {
4
11
 
5
12
  const res: ReplEditorData
@@ -0,0 +1,129 @@
1
+ :root {
2
+ --vp-chat-c-bg: var(--vp-c-bg-soft);
3
+ --vp-chat-c-bg-header: var(--vp-c-bg-soft);
4
+ --vp-chat-c-bg-content: var(--vp-c-bg-soft);
5
+ --vp-chat-c-bg-user: var(--vp-c-bg);
6
+ --vp-chat-c-bg-self: var(--vp-c-brand-soft);
7
+ --vp-chat-c-title: var(--vp-c-text-1);
8
+ --vp-chat-c-text: var(--vp-c-text-1);
9
+ --vp-chat-c-date: var(--vp-c-text-3);
10
+ --vp-chat-c-username: var(--vp-c-text-2);
11
+ }
12
+
13
+ .vp-chat {
14
+ width: 100%;
15
+ margin: 16px 0;
16
+ overflow: hidden;
17
+ background-color: var(--vp-chat-c-bg);
18
+ border-radius: 6px;
19
+ transition: background-color var(--vp-t-color);
20
+ }
21
+
22
+ @media (min-width: 640px) {
23
+ .vp-chat {
24
+ width: 320px;
25
+ margin: 16px auto;
26
+ }
27
+ }
28
+
29
+ @media (min-width: 768px) {
30
+ .vp-chat {
31
+ width: 360px;
32
+ }
33
+ }
34
+
35
+ @media (min-width: 960px) {
36
+ .vp-chat {
37
+ width: 480px;
38
+ }
39
+ }
40
+
41
+ .vp-chat .vp-chat-header {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ height: 44px;
46
+ background-color: var(--vp-chat-c-bg-header);
47
+ transition: background-color var(--vp-t-color);
48
+ }
49
+
50
+ .vp-chat .vp-chat-title {
51
+ flex: 1 2;
52
+ font-weight: 600;
53
+ color: var(--vp-chat-c-title);
54
+ text-align: center;
55
+ transition: color var(--vp-t-color);
56
+ }
57
+
58
+ .vp-chat .vp-chat-content {
59
+ padding: 0 16px 24px;
60
+ background-color: var(--vp-chat-c-bg-content);
61
+ transition: background-color var(--vp-t-color);
62
+ }
63
+
64
+ .vp-chat .vp-chat-date {
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ margin: 16px 0;
69
+ font-size: 12px;
70
+ color: var(--vp-chat-c-date);
71
+ transition: color var(--vp-t-color);
72
+ }
73
+
74
+ .vp-chat .vp-chat-message {
75
+ display: flex;
76
+ margin-bottom: 16px;
77
+ }
78
+
79
+ .vp-chat .vp-chat-message.self {
80
+ justify-content: flex-end;
81
+ }
82
+
83
+ .vp-chat .vp-chat-message:last-child {
84
+ margin-bottom: 0;
85
+ }
86
+
87
+ .vp-chat .vp-chat-message-body {
88
+ flex-shrink: 2;
89
+ padding-right: 32px;
90
+ }
91
+
92
+ .vp-chat .vp-chat-message.self .vp-chat-message-body {
93
+ padding-right: 0;
94
+ padding-left: 32px;
95
+ }
96
+
97
+ .vp-chat .vp-chat-username {
98
+ margin: 0;
99
+ font-size: 14px;
100
+ font-weight: 500;
101
+ color: var(--vp-chat-c-username);
102
+ }
103
+
104
+ .vp-chat .vp-chat-message-body .message-content {
105
+ max-width: 100%;
106
+ padding: 8px 16px;
107
+ font-size: 14px;
108
+ line-height: 22px;
109
+ color: var(--vp-chat-c-text);
110
+ background-color: var(--vp-chat-c-bg-user);
111
+ border-radius: 6px;
112
+ box-shadow: var(--vp-shadow-1);
113
+ }
114
+
115
+ .vp-chat .vp-chat-message.self .vp-chat-message-body .message-content {
116
+ background-color: var(--vp-chat-c-bg-self);
117
+ }
118
+
119
+ .vp-chat .vp-chat-message-body .message-content :where(p, ul, ol) {
120
+ margin: 8px 0;
121
+ }
122
+
123
+ .vp-chat .vp-chat-message-body .message-content :first-child {
124
+ margin-top: 0;
125
+ }
126
+
127
+ .vp-chat .vp-chat-message-body .message-content :last-child {
128
+ margin-bottom: 0;
129
+ }
@@ -147,6 +147,17 @@
147
147
  list-style: none;
148
148
  }
149
149
 
150
+ .demo-draw-vue {
151
+ position: absolute;
152
+ top: -99999px;
153
+ left: -99999px;
154
+ z-index: 1;
155
+ padding: 24px;
156
+ overflow: hidden;
157
+ transform: translate3d(0, 0, 0);
158
+ will-change: top, left, width, height;
159
+ }
160
+
150
161
  .vpi-demo-code {
151
162
  --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='M14.18 4.276a.75.75 0 0 1 .531.918l-3.973 14.83a.75.75 0 0 1-1.45-.389l3.974-14.83a.75.75 0 0 1 .919-.53m2.262 3.053a.75.75 0 0 1 1.059-.056l1.737 1.564c.737.662 1.347 1.212 1.767 1.71c.44.525.754 1.088.754 1.784c0 .695-.313 1.258-.754 1.782c-.42.499-1.03 1.049-1.767 1.711l-1.737 1.564a.75.75 0 0 1-1.004-1.115l1.697-1.527c.788-.709 1.319-1.19 1.663-1.598c.33-.393.402-.622.402-.818s-.072-.424-.402-.817c-.344-.409-.875-.89-1.663-1.598l-1.697-1.527a.75.75 0 0 1-.056-1.06m-8.94 1.06a.75.75 0 1 0-1.004-1.115L4.761 8.836c-.737.662-1.347 1.212-1.767 1.71c-.44.525-.754 1.088-.754 1.784c0 .695.313 1.258.754 1.782c.42.499 1.03 1.049 1.767 1.711l1.737 1.564a.75.75 0 0 0 1.004-1.115l-1.697-1.527c-.788-.709-1.319-1.19-1.663-1.598c-.33-.393-.402-.622-.402-.818s.072-.424.402-.817c.344-.409.875-.89 1.663-1.598z'/%3E%3C/svg%3E");
152
163
  }
@@ -251,6 +251,23 @@ interface MarkdownPowerPluginOptions {
251
251
  * @default false
252
252
  */
253
253
  collapse?: boolean;
254
+ /**
255
+ * 是否启用 chat 容器 语法
256
+ *
257
+ * ```md
258
+ * ::: chat
259
+ * {:date}
260
+ *
261
+ * {user}
262
+ * message
263
+ *
264
+ * {.}
265
+ * message
266
+ * :::
267
+ * ```
268
+ * @default false
269
+ */
270
+ chat?: boolean;
254
271
  /**
255
272
  * 是否启用 bilibili 视频嵌入
256
273
  *
package/lib/node/index.js CHANGED
@@ -1209,6 +1209,101 @@ function cardPlugin(md) {
1209
1209
  });
1210
1210
  }
1211
1211
 
1212
+ // src/node/container/chat.ts
1213
+ var chatPlugin = (md) => {
1214
+ md.block.ruler.before("fence", "chat_def", chatDef);
1215
+ md.renderer.rules.chat_container = (tokens, idx, _, env) => {
1216
+ const { meta, content } = tokens[idx];
1217
+ const { title } = meta;
1218
+ const messages = parseChatContent(content);
1219
+ return `<div class="vp-chat">
1220
+ <div class="vp-chat-header">
1221
+ <p class="vp-chat-title">${title || "Chat"}</p>
1222
+ </div>
1223
+ <div class="vp-chat-content">
1224
+ ${chatMessagesRender(md, env, messages)}
1225
+ </div>
1226
+ </div>`;
1227
+ };
1228
+ };
1229
+ function chatDef(state, startLine, endLine, silent) {
1230
+ const start = state.bMarks[startLine] + state.tShift[startLine];
1231
+ const max = state.eMarks[startLine];
1232
+ let pos = start;
1233
+ if (state.src.slice(pos, pos + 3) !== ":::")
1234
+ return false;
1235
+ pos += 3;
1236
+ const info = state.src.slice(start + 3, max).trim();
1237
+ if (!info.startsWith("chat"))
1238
+ return false;
1239
+ if (silent)
1240
+ return true;
1241
+ let line = startLine;
1242
+ let content = "";
1243
+ while (++line < endLine) {
1244
+ if (state.src.slice(state.bMarks[line], state.eMarks[line]).trim() === ":::") {
1245
+ break;
1246
+ }
1247
+ content += `${state.src.slice(state.bMarks[line], state.eMarks[line])}
1248
+ `;
1249
+ }
1250
+ const token = state.push("chat_container", "", 0);
1251
+ token.meta = resolveAttrs(info).attrs;
1252
+ token.content = content;
1253
+ token.markup = "::: chat";
1254
+ token.map = [startLine, line + 1];
1255
+ state.line = line + 1;
1256
+ return true;
1257
+ }
1258
+ function chatMessagesRender(md, env, messages) {
1259
+ let currentDate = "";
1260
+ return messages.map(({ sender, username, date, content }) => {
1261
+ let messageContent = "";
1262
+ if (!currentDate || currentDate !== date) {
1263
+ currentDate = date;
1264
+ messageContent += `<div class="vp-chat-date"><span>${currentDate}</span></div>
1265
+ `;
1266
+ }
1267
+ messageContent += `<div class="vp-chat-message ${sender}">
1268
+ <div class="vp-chat-message-body"> ${sender === "user" ? `
1269
+ <p class="vp-chat-username">${username}</p>` : ""}
1270
+ <div class="message-content">
1271
+ ${md.render(content.join("\n"), cleanMarkdownEnv(env)).trim()}
1272
+ </div>
1273
+ </div>
1274
+ </div>`;
1275
+ return messageContent;
1276
+ }).join("\n");
1277
+ }
1278
+ function parseChatContent(content) {
1279
+ const lines = content.split("\n");
1280
+ const messages = [];
1281
+ let currentDate = "";
1282
+ let message;
1283
+ for (const line of lines) {
1284
+ const lineStr = line.trim();
1285
+ if (lineStr.startsWith("{:") && lineStr.endsWith("}")) {
1286
+ currentDate = lineStr.slice(2, -1).trim();
1287
+ continue;
1288
+ }
1289
+ if (lineStr.startsWith("{") && lineStr.endsWith("}")) {
1290
+ const username = lineStr.slice(1, -1).trim();
1291
+ message = {
1292
+ sender: username === "." ? "self" : "user",
1293
+ username,
1294
+ date: currentDate,
1295
+ content: []
1296
+ };
1297
+ messages.push(message);
1298
+ continue;
1299
+ }
1300
+ if (message?.sender) {
1301
+ message.content.push(line);
1302
+ }
1303
+ }
1304
+ return messages;
1305
+ }
1306
+
1212
1307
  // src/node/container/collapse.ts
1213
1308
  function collapsePlugin(md) {
1214
1309
  createContainerPlugin(md, "collapse", {
@@ -1468,7 +1563,7 @@ function updateInlineToken(inline, info, icon) {
1468
1563
  import { promises as fs2 } from "node:fs";
1469
1564
  import { resolveModule } from "local-pkg";
1470
1565
  import container3 from "markdown-it-container";
1471
- import { path as path2 } from "vuepress/utils";
1566
+ import { colors, logger as logger2, path as path2 } from "vuepress/utils";
1472
1567
  var RE_INFO = /^(#editable)?(.*)$/;
1473
1568
  function createReplContainer(md, lang) {
1474
1569
  const type2 = `${lang}-repl`;
@@ -1501,24 +1596,28 @@ async function langReplPlugin(app, md, {
1501
1596
  }
1502
1597
  theme ??= { light: "github-light", dark: "github-dark" };
1503
1598
  const data = { grammars: {} };
1504
- const themesPath = path2.dirname(resolveModule("tm-themes"));
1505
- const grammarsPath = path2.dirname(resolveModule("tm-grammars"));
1506
- const readTheme = (theme2) => read(path2.join(themesPath, "themes", `${theme2}.json`));
1507
- const readGrammar = (grammar) => read(path2.join(grammarsPath, "grammars", `${grammar}.json`));
1508
- if (typeof theme === "string") {
1509
- data.theme = await readTheme(theme);
1510
- } else {
1511
- data.theme = await Promise.all([
1512
- readTheme(theme.light),
1513
- readTheme(theme.dark)
1514
- ]).then(([light, dark]) => ({ light, dark }));
1515
- }
1516
- if (kotlin)
1517
- data.grammars.kotlin = await readGrammar("kotlin");
1518
- if (go)
1519
- data.grammars.go = await readGrammar("go");
1520
- if (rust)
1521
- data.grammars.rust = await readGrammar("rust");
1599
+ try {
1600
+ const themesPath = path2.dirname(resolveModule("tm-themes"));
1601
+ const grammarsPath = path2.dirname(resolveModule("tm-grammars"));
1602
+ const readTheme = (theme2) => read(path2.join(themesPath, "themes", `${theme2}.json`));
1603
+ const readGrammar = (grammar) => read(path2.join(grammarsPath, "grammars", `${grammar}.json`));
1604
+ if (typeof theme === "string") {
1605
+ data.theme = await readTheme(theme);
1606
+ } else {
1607
+ data.theme = await Promise.all([
1608
+ readTheme(theme.light),
1609
+ readTheme(theme.dark)
1610
+ ]).then(([light, dark]) => ({ light, dark }));
1611
+ }
1612
+ if (kotlin)
1613
+ data.grammars.kotlin = await readGrammar("kotlin");
1614
+ if (go)
1615
+ data.grammars.go = await readGrammar("go");
1616
+ if (rust)
1617
+ data.grammars.rust = await readGrammar("rust");
1618
+ } catch {
1619
+ logger2.error("[vuepress-plugin-md-power]", `Failed to load packages: ${colors.green("tm-themes")}, ${colors.green("tm-grammars")}, Please install them manually.`);
1620
+ }
1522
1621
  await app.writeTemp(
1523
1622
  "internal/md-power/replEditorData.js",
1524
1623
  `export default ${JSON.stringify(data, null, 2)}`
@@ -2021,6 +2120,8 @@ async function containerPlugin(app, md, options) {
2021
2120
  timelinePlugin(md);
2022
2121
  if (options.collapse)
2023
2122
  collapsePlugin(md);
2123
+ if (options.chat)
2124
+ chatPlugin(md);
2024
2125
  }
2025
2126
 
2026
2127
  // src/node/demo/demo.ts
@@ -2584,7 +2685,7 @@ var vueContainerRender = {
2584
2685
  insertSetupScript(style, env);
2585
2686
  }
2586
2687
  }
2587
- return `<VPDemoBasic${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2688
+ return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2588
2689
  <${componentName2} />
2589
2690
  <template #code>
2590
2691
  `;
@@ -2967,7 +3068,7 @@ var pdfPlugin = (md) => {
2967
3068
 
2968
3069
  // src/node/embed/video/artPlayer.ts
2969
3070
  import { isPackageExists as isPackageExists2 } from "local-pkg";
2970
- import { colors } from "vuepress/utils";
3071
+ import { colors as colors2 } from "vuepress/utils";
2971
3072
  var installed = {
2972
3073
  dashjs: isPackageExists2("dashjs"),
2973
3074
  hlsjs: isPackageExists2("hls.js"),
@@ -3023,10 +3124,10 @@ function checkSupportType(type2) {
3023
3124
  break;
3024
3125
  }
3025
3126
  if (name) {
3026
- console.warn(`${colors.yellow("[vuepress-plugin-md-power] artPlayer: ")} ${colors.cyan(name)} is not installed, please install it via npm or yarn or pnpm`);
3127
+ console.warn(`${colors2.yellow("[vuepress-plugin-md-power] artPlayer: ")} ${colors2.cyan(name)} is not installed, please install it via npm or yarn or pnpm`);
3027
3128
  }
3028
3129
  } else {
3029
- console.warn(`${colors.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors.cyan(type2)}`);
3130
+ console.warn(`${colors2.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors2.cyan(type2)}`);
3030
3131
  }
3031
3132
  }
3032
3133
 
@@ -3087,6 +3188,7 @@ var bilibiliPlugin = (md) => {
3087
3188
  params.set("t", meta.time.toString());
3088
3189
  }
3089
3190
  params.set("autoplay", meta.autoplay ? "1" : "0");
3191
+ params.set("high_quality", "1");
3090
3192
  const source = `${BILIBILI_LINK}?${params.toString()}`;
3091
3193
  return `<VideoBilibili src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`;
3092
3194
  }
@@ -3314,7 +3416,9 @@ var abbrPlugin = (md) => {
3314
3416
  md.core.ruler.after("linkify", "abbr_replace", abbrReplace);
3315
3417
  md.renderer.rules.abbreviation = (tokens, idx, _, env) => {
3316
3418
  const { content, info } = tokens[idx];
3317
- return `<Abbreviation>${content}${info ? `<template #tooltip>${md.renderInline(info, cleanMarkdownEnv(env))}</template>` : ""}</Abbreviation>`;
3419
+ const rendered = md.renderInline(info, cleanMarkdownEnv(env));
3420
+ const label = rendered.replace(/<[^>]*>/g, "");
3421
+ return `<Abbreviation aria-label="${label}">${content}${info ? `<template #tooltip>${rendered}</template>` : ""}</Abbreviation>`;
3318
3422
  };
3319
3423
  };
3320
3424
 
@@ -3622,6 +3726,9 @@ async function prepareConfigFile(app, options) {
3622
3726
  enhances.add(`app.component('VPCollapse', VPCollapse)`);
3623
3727
  enhances.add(`app.component('VPCollapseItem', VPCollapseItem)`);
3624
3728
  }
3729
+ if (options.chat) {
3730
+ imports.add(`import '${CLIENT_FOLDER}styles/chat.css'`);
3731
+ }
3625
3732
  return app.writeTemp(
3626
3733
  "md-power/config.js",
3627
3734
  `import { defineClientConfig } from 'vuepress/client'
@@ -3695,5 +3802,5 @@ export {
3695
3802
  resolveImageSize
3696
3803
  };
3697
3804
  /* istanbul ignore if -- @preserve */
3698
- /* istanbul ignore else -- @preserve */
3699
3805
  /* istanbul ignore next -- @preserve */
3806
+ /* istanbul ignore else -- @preserve */
@@ -250,6 +250,23 @@ interface MarkdownPowerPluginOptions {
250
250
  * @default false
251
251
  */
252
252
  collapse?: boolean;
253
+ /**
254
+ * 是否启用 chat 容器 语法
255
+ *
256
+ * ```md
257
+ * ::: chat
258
+ * {:date}
259
+ *
260
+ * {user}
261
+ * message
262
+ *
263
+ * {.}
264
+ * message
265
+ * :::
266
+ * ```
267
+ * @default false
268
+ */
269
+ chat?: boolean;
253
270
  /**
254
271
  * 是否启用 bilibili 视频嵌入
255
272
  *
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.137",
4
+ "version": "1.0.0-rc.139",
5
5
  "description": "The Plugin for VuePress 2 - markdown power",
6
6
  "author": "pengzhanbo <volodymyr@foxmail.com>",
7
7
  "license": "MIT",
@@ -33,13 +33,13 @@
33
33
  "peerDependencies": {
34
34
  "artplayer": "^5.2.2",
35
35
  "dashjs": "^5.0.0",
36
- "esbuild": "^0.25.1",
37
- "hls.js": "^1.5.20",
38
- "less": "^4.2.2",
36
+ "esbuild": "^0.25.2",
37
+ "hls.js": "^1.6.1",
38
+ "less": "^4.3.0",
39
39
  "markdown-it": "^14.1.0",
40
40
  "mpegts.js": "^1.7.3",
41
- "sass": "^1.86.0",
42
- "sass-embedded": "^1.86.0",
41
+ "sass": "^1.86.3",
42
+ "sass-embedded": "^1.86.3",
43
43
  "stylus": "^0.64.0",
44
44
  "vuepress": "2.0.0-rc.20"
45
45
  },
@@ -69,24 +69,24 @@
69
69
  "@mdit/plugin-tab": "^0.16.0",
70
70
  "@mdit/plugin-tasklist": "^0.16.0",
71
71
  "@pengzhanbo/utils": "^1.2.0",
72
- "@vuepress/helper": "2.0.0-rc.82",
72
+ "@vuepress/helper": "2.0.0-rc.91",
73
73
  "@vueuse/core": "^13.0.0",
74
74
  "chokidar": "3.6.0",
75
- "image-size": "^2.0.1",
75
+ "image-size": "^2.0.2",
76
76
  "local-pkg": "^1.1.1",
77
- "lru-cache": "^11.0.2",
77
+ "lru-cache": "^11.1.0",
78
78
  "markdown-it-container": "^4.0.0",
79
79
  "nanoid": "^5.1.5",
80
80
  "shiki": "^3.2.1",
81
- "tm-grammars": "^1.23.5",
82
- "tm-themes": "^1.10.1",
81
+ "tm-grammars": "^1.23.8",
82
+ "tm-themes": "^1.10.3",
83
83
  "vue": "^3.5.13"
84
84
  },
85
85
  "devDependencies": {
86
86
  "@types/markdown-it": "^14.1.2",
87
87
  "artplayer": "^5.2.2",
88
88
  "dashjs": "^5.0.0",
89
- "hls.js": "^1.5.20",
89
+ "hls.js": "^1.6.1",
90
90
  "mpegts.js": "1.7.3"
91
91
  },
92
92
  "publishConfig": {
@@ -1,154 +0,0 @@
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>