vuepress-plugin-md-power 1.0.0-rc.131 → 1.0.0-rc.133

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,98 @@
1
+ <script setup lang="ts">
2
+ import type { CSSProperties } from 'vue'
3
+ import { nextTick, ref, useTemplateRef, watch } from 'vue'
4
+
5
+ const show = ref(false)
6
+ const tooltip = useTemplateRef<HTMLSpanElement>('tooltip')
7
+ const styles = ref<CSSProperties>()
8
+
9
+ watch(show, () => nextTick(() => {
10
+ if (__VUEPRESS_SSR__)
11
+ return
12
+
13
+ if (show.value && tooltip.value) {
14
+ const { x, width } = tooltip.value.getBoundingClientRect()
15
+ const innerWidth = window.innerWidth
16
+ const space = 16
17
+ let translate = 0
18
+ if (x - space < 0)
19
+ translate = Math.abs(x) + space
20
+
21
+ else if (x + width + space > innerWidth)
22
+ translate = innerWidth - x - width - space
23
+
24
+ if (translate !== 0) {
25
+ styles.value = {
26
+ '--vp-abbr-transform': `translateX(${translate}px) translateX(-50%)`,
27
+ '--vp-abbr-space-transform': `translateX(${-translate}px) translateX(-50%)`,
28
+ }
29
+ }
30
+ }
31
+ }))
32
+ </script>
33
+
34
+ <template>
35
+ <span class="vp-abbr" @mouseenter="show = true" @mouseleave="show = false">
36
+ <slot />
37
+ <Transition name="fade">
38
+ <span v-show="show" ref="tooltip" class="vp-abbr-tooltip" :style="styles">
39
+ <slot name="tooltip" />
40
+ </span>
41
+ </Transition>
42
+ </span>
43
+ </template>
44
+
45
+ <style>
46
+ :root {
47
+ --vp-abbr-bg: var(--vp-c-bg);
48
+ --vp-abbr-text: var(--vp-c-text-2);
49
+ --vp-abbr-border: var(--vp-c-divider);
50
+ --vp-abbr-transform: translateX(-50%);
51
+ --vp-abbr-space-transform: translateX(-50%);
52
+ }
53
+
54
+ .vp-abbr {
55
+ position: relative;
56
+ text-decoration: underline dotted currentcolor;
57
+ text-underline-offset: 4px;
58
+ cursor: help;
59
+ }
60
+
61
+ .vp-abbr .vp-abbr-tooltip {
62
+ position: absolute;
63
+ top: calc(100% + 12px);
64
+ left: 50%;
65
+ z-index: 1;
66
+ width: max-content;
67
+ max-width: min(calc(100vw - 32px), 360px);
68
+ padding: 8px 14px;
69
+ font-size: 0.875em;
70
+ line-height: 1.7;
71
+ color: var(--vp-abbr-text);
72
+ cursor: auto;
73
+ background-color: var(--vp-abbr-bg);
74
+ border: solid 1px var(--vp-abbr-border);
75
+ border-radius: 4px;
76
+ box-shadow: var(--vp-shadow-2);
77
+ transform: var(--vp-abbr-transform);
78
+ }
79
+
80
+ .vp-abbr .vp-abbr-tooltip::before,
81
+ .vp-abbr .vp-abbr-tooltip::after {
82
+ position: absolute;
83
+ top: -16px;
84
+ left: 50%;
85
+ display: block;
86
+ width: 0;
87
+ height: 0;
88
+ content: "";
89
+ border: 8px solid transparent;
90
+ border-bottom-color: var(--vp-abbr-bg);
91
+ transform: var(--vp-abbr-space-transform);
92
+ }
93
+
94
+ .vp-abbr .vp-abbr-tooltip::before {
95
+ top: -17px;
96
+ border-bottom-color: var(--vp-abbr-border);
97
+ }
98
+ </style>
@@ -0,0 +1,120 @@
1
+ <script setup lang="ts">
2
+ import { onClickOutside, useEventListener } from '@vueuse/core'
3
+ import { computed, nextTick, ref, useTemplateRef, watch } from 'vue'
4
+
5
+ const props = defineProps<{
6
+ label: string
7
+ total: number
8
+ }>()
9
+
10
+ const active = ref(false)
11
+ const list = computed(() => Array.from({ length: props.total }, (_, i) => i))
12
+ const position = ref({ x: 0, y: 0 })
13
+
14
+ const popover = useTemplateRef<HTMLDivElement>('popover')
15
+ const button = useTemplateRef<HTMLButtonElement>('button')
16
+ onClickOutside(popover, () => (active.value = false), {
17
+ ignore: [button],
18
+ })
19
+
20
+ function updatePosition() {
21
+ if (__VUEPRESS_SSR__)
22
+ return
23
+ if (!active.value || !popover.value || !button.value)
24
+ return
25
+ const { x: _x, y: _y, width: w, height: h } = button.value.getBoundingClientRect()
26
+ const x = _x + w / 2
27
+ const y = _y + h
28
+
29
+ const { width, height } = popover.value.getBoundingClientRect()
30
+ const { clientWidth, clientHeight } = document.documentElement
31
+ position.value.x = x + width + 16 > clientWidth ? clientWidth - x - width - 16 : 0
32
+ position.value.y = y + height + 16 > clientHeight ? clientHeight - y - height - 16 : 0
33
+ }
34
+
35
+ watch(active, () => nextTick(updatePosition))
36
+ useEventListener('resize', updatePosition)
37
+ </script>
38
+
39
+ <template>
40
+ <span class="vp-annotation" :class="{ active, [label]: true }" :aria-label="label">
41
+ <span ref="button" class="vpi-annotation" @click="active = !active" />
42
+ <Transition name="fade">
43
+ <div
44
+ v-show="active" ref="popover"
45
+ class="annotations-popover" :class="{ list: list.length > 1 }"
46
+ :style="{ '--vp-annotation-x': `${position.x}px`, '--vp-annotation-y': `${position.y}px` }"
47
+ >
48
+ <div v-for="i in list" :key="label + i" class="annotation">
49
+ <slot :name="`item-${i}`" />
50
+ </div>
51
+ </div>
52
+ </Transition>
53
+ </span>
54
+ </template>
55
+
56
+ <style scoped>
57
+ .vp-annotation {
58
+ position: relative;
59
+ }
60
+
61
+ .vpi-annotation {
62
+ --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' fill-rule='evenodd' d='M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10a10 10 0 0 1-4.262-.951l-4.537.93a1 1 0 0 1-1.18-1.18l.93-4.537A10 10 0 0 1 2 12m10-4a1 1 0 0 1 1 1v2h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2H9a1 1 0 1 1 0-2h2V9a1 1 0 0 1 1-1' clip-rule='evenodd'/%3E%3C/svg%3E");
63
+
64
+ position: relative;
65
+ top: -2px;
66
+ z-index: 2;
67
+ width: 1.2em;
68
+ height: 1.2em;
69
+ color: currentcolor;
70
+ cursor: pointer;
71
+ opacity: 0.5;
72
+ transition: color var(--vp-t-color), opacity var(--vp-t-color), transform var(--vp-t-color);
73
+ transform: rotate(0deg);
74
+ }
75
+
76
+ .vp-annotation.active {
77
+ z-index: 10;
78
+ }
79
+
80
+ .vp-annotation:where(:hover, .active) .vpi-annotation {
81
+ color: var(--vp-c-brand-2);
82
+ opacity: 1;
83
+ }
84
+
85
+ .vp-annotation.active .vpi-annotation {
86
+ transform: rotate(-45deg);
87
+ }
88
+
89
+ .annotations-popover {
90
+ position: absolute;
91
+ top: 50%;
92
+ left: 50%;
93
+ width: max-content;
94
+ max-width: min(calc(100vw - 32px), 360px);
95
+ max-height: 360px;
96
+ padding: 8px 12px;
97
+ overflow-y: auto;
98
+ font-size: 14px;
99
+ background-color: var(--vp-c-bg);
100
+ border: solid 1px var(--vp-c-divider);
101
+ border-radius: 4px;
102
+ box-shadow: var(--vp-shadow-2);
103
+ transform: translateX(var(--vp-annotation-x, 0)) translateY(var(--vp-annotation-y, 0));
104
+ }
105
+
106
+ .annotations-popover.list {
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 12px;
110
+ padding: 12px;
111
+ background-color: var(--vp-c-bg-soft);
112
+ }
113
+
114
+ .annotations-popover.list .annotation {
115
+ padding: 4px 12px;
116
+ background-color: var(--vp-c-bg);
117
+ border-radius: 4px;
118
+ box-shadow: var(--vp-shadow-1);
119
+ }
120
+ </style>
@@ -77,9 +77,9 @@ function initCustomType(type: string): CustomType {
77
77
 
78
78
  if ((type === 'mpd' || type === 'dash') && installed.dashjs) {
79
79
  customType[type] = async function (video, url, art) {
80
- const dashjs = (await import(/* webpackChunkName: "dashjs" */ 'dashjs')).default
81
- if (dashjs.supportsMediaSource()) {
82
- const dashPlayer = dashjs.MediaPlayer().create()
80
+ const { supportsMediaSource, MediaPlayer } = (await import(/* webpackChunkName: "dashjs" */ 'dashjs'))
81
+ if (supportsMediaSource()) {
82
+ const dashPlayer = MediaPlayer().create()
83
83
  dashPlayer.initialize(video, url, props.autoplay, 0)
84
84
  art.on('destroy', () => dashPlayer.destroy())
85
85
  }
@@ -177,6 +177,12 @@ interface ReplEditorData {
177
177
  }
178
178
 
179
179
  interface MarkdownPowerPluginOptions {
180
+ /**
181
+ * 是否启用注释
182
+ * @default false
183
+ */
184
+ annotation?: boolean;
185
+ abbr?: boolean;
180
186
  /**
181
187
  * 配置代码块分组
182
188
  */
package/lib/node/index.js CHANGED
@@ -3044,6 +3044,198 @@ import { sup } from "@mdit/plugin-sup";
3044
3044
  import { tasklist } from "@mdit/plugin-tasklist";
3045
3045
  import { isPlainObject as isPlainObject3 } from "@vuepress/helper";
3046
3046
 
3047
+ // src/node/inline/abbr.ts
3048
+ var abbrPlugin = (md) => {
3049
+ const { arrayReplaceAt, escapeRE, lib } = md.utils;
3050
+ const OTHER_CHARS = " \r\n$+<=>^`|~";
3051
+ const UNICODE_PUNCTUATION_REGEXP = lib.ucmicro.P.source;
3052
+ const UNICODE_SPACE_REGEXP = lib.ucmicro.Z.source;
3053
+ const WORDING_REGEXP_TEXT = `${UNICODE_PUNCTUATION_REGEXP}|${UNICODE_SPACE_REGEXP}|[${OTHER_CHARS.split("").map(escapeRE).join("")}]`;
3054
+ const abbrDefinition = (state, startLine, _endLine, silent) => {
3055
+ let labelEnd = -1;
3056
+ let pos = state.bMarks[startLine] + state.tShift[startLine];
3057
+ const max = state.eMarks[startLine];
3058
+ if (pos + 2 >= max || state.src.charAt(pos++) !== "*" || state.src.charAt(pos++) !== "[") {
3059
+ return false;
3060
+ }
3061
+ const labelStart = pos;
3062
+ while (pos < max) {
3063
+ const ch = state.src.charAt(pos);
3064
+ if (ch === "[")
3065
+ return false;
3066
+ if (ch === "]") {
3067
+ labelEnd = pos;
3068
+ break;
3069
+ }
3070
+ if (ch === "\\")
3071
+ pos++;
3072
+ pos++;
3073
+ }
3074
+ if (labelEnd < 0 || state.src.charAt(labelEnd + 1) !== ":")
3075
+ return false;
3076
+ if (silent)
3077
+ return true;
3078
+ const label = state.src.slice(labelStart, labelEnd).replace(/\\(.)/g, "$1");
3079
+ const title = state.src.slice(labelEnd + 2, max).trim();
3080
+ if (!label.length || !title.length)
3081
+ return false;
3082
+ (state.env.abbreviations ??= {})[`:${label}`] ??= title;
3083
+ state.line = startLine + 1;
3084
+ return true;
3085
+ };
3086
+ const abbrReplace = (state) => {
3087
+ const tokens = state.tokens;
3088
+ const { abbreviations } = state.env;
3089
+ if (!abbreviations)
3090
+ return;
3091
+ const abbreviationsRegExpText = Object.keys(abbreviations).map((x) => x.substring(1)).sort((a, b) => b.length - a.length).map(escapeRE).join("|");
3092
+ const regexpSimple = new RegExp(`(?:${abbreviationsRegExpText})`);
3093
+ const regExp = new RegExp(
3094
+ `(^|${WORDING_REGEXP_TEXT})(${abbreviationsRegExpText})($|${WORDING_REGEXP_TEXT})`,
3095
+ "g"
3096
+ );
3097
+ for (const token of tokens) {
3098
+ if (token.type !== "inline")
3099
+ continue;
3100
+ let children = token.children;
3101
+ for (let index = children.length - 1; index >= 0; index--) {
3102
+ const currentToken = children[index];
3103
+ if (currentToken.type !== "text")
3104
+ continue;
3105
+ const text = currentToken.content;
3106
+ regExp.lastIndex = 0;
3107
+ if (!regexpSimple.test(text))
3108
+ continue;
3109
+ const nodes = [];
3110
+ let match;
3111
+ let pos = 0;
3112
+ while (match = regExp.exec(text)) {
3113
+ const [, before, word, after] = match;
3114
+ if (match.index > 0 || before.length > 0) {
3115
+ const token2 = new state.Token("text", "", 0);
3116
+ token2.content = text.slice(pos, match.index + before.length);
3117
+ nodes.push(token2);
3118
+ }
3119
+ const abbrToken = new state.Token("abbreviation", "Abbreviation", 0);
3120
+ abbrToken.content = word;
3121
+ abbrToken.info = abbreviations[`:${word}`];
3122
+ nodes.push(abbrToken);
3123
+ regExp.lastIndex -= after.length;
3124
+ pos = regExp.lastIndex;
3125
+ }
3126
+ if (!nodes.length)
3127
+ continue;
3128
+ if (pos < text.length) {
3129
+ const token2 = new state.Token("text", "", 0);
3130
+ token2.content = text.slice(pos);
3131
+ nodes.push(token2);
3132
+ }
3133
+ token.children = children = arrayReplaceAt(children, index, nodes);
3134
+ }
3135
+ }
3136
+ };
3137
+ md.block.ruler.before("reference", "abbr_definition", abbrDefinition, {
3138
+ alt: ["paragraph", "reference"]
3139
+ });
3140
+ md.core.ruler.after("linkify", "abbr_replace", abbrReplace);
3141
+ md.renderer.rules.abbreviation = (tokens, idx) => {
3142
+ const { content, info } = tokens[idx];
3143
+ return `<Abbreviation>
3144
+ ${content}
3145
+ ${info ? `<template #tooltip>${md.renderInline(info)}</template>` : ""}
3146
+ </Abbreviation>`;
3147
+ };
3148
+ };
3149
+
3150
+ // src/node/inline/annotation.ts
3151
+ var annotationDef = (state, startLine, endLine, silent) => {
3152
+ const start = state.bMarks[startLine] + state.tShift[startLine];
3153
+ const max = state.eMarks[startLine];
3154
+ if (
3155
+ // line should be at least 5 chars - "[+x]:"
3156
+ start + 4 > max || state.src.charAt(start) !== "[" || state.src.charAt(start + 1) !== "+"
3157
+ ) {
3158
+ return false;
3159
+ }
3160
+ let pos = start + 2;
3161
+ while (pos < max) {
3162
+ if (state.src.charAt(pos) === " ")
3163
+ return false;
3164
+ if (state.src.charAt(pos) === "]")
3165
+ break;
3166
+ pos++;
3167
+ }
3168
+ if (
3169
+ // empty footnote label
3170
+ pos === start + 2 || pos + 1 >= max || state.src.charAt(++pos) !== ":"
3171
+ ) {
3172
+ return false;
3173
+ }
3174
+ if (silent)
3175
+ return true;
3176
+ pos++;
3177
+ state.env.annotations ??= {};
3178
+ const label = state.src.slice(start + 2, pos - 2);
3179
+ const annotation = state.src.slice(pos, max).trim();
3180
+ state.env.annotations[`:${label}`] ??= [];
3181
+ state.env.annotations[`:${label}`].push(annotation);
3182
+ state.line += 1;
3183
+ return true;
3184
+ };
3185
+ var annotationRef = (state, silent) => {
3186
+ const start = state.pos;
3187
+ const max = state.posMax;
3188
+ if (
3189
+ // should be at least 4 chars - "[+x]"
3190
+ start + 3 > max || typeof state.env.annotations === "undefined" || state.src.charAt(start) !== "[" || state.src.charAt(start + 1) !== "+"
3191
+ ) {
3192
+ return false;
3193
+ }
3194
+ let pos = start + 2;
3195
+ while (pos < max) {
3196
+ if (state.src.charAt(pos) === " " || state.src.charAt(pos) === "\n")
3197
+ return false;
3198
+ if (state.src.charAt(pos) === "]")
3199
+ break;
3200
+ pos++;
3201
+ }
3202
+ if (
3203
+ // empty annotation labels
3204
+ pos === start + 2 || pos >= max
3205
+ ) {
3206
+ return false;
3207
+ }
3208
+ pos++;
3209
+ const label = state.src.slice(start + 2, pos - 1);
3210
+ const annotations = state.env.annotations?.[`:${label}`] ?? [];
3211
+ if (annotations.length === 0)
3212
+ return false;
3213
+ if (!silent) {
3214
+ const refToken = state.push("annotation_ref", "", 0);
3215
+ refToken.meta = {
3216
+ label,
3217
+ annotations
3218
+ };
3219
+ }
3220
+ state.pos = pos;
3221
+ state.posMax = max;
3222
+ return true;
3223
+ };
3224
+ var annotationPlugin = (md) => {
3225
+ md.renderer.rules.annotation_ref = (tokens, idx) => {
3226
+ const { label = "", annotations = [] } = tokens[idx].meta ?? {};
3227
+ return `<Annotation label="${label}" :total="${annotations.length}">
3228
+ ${annotations.map((annotation, i) => {
3229
+ return `<template #item-${i}>${md.renderInline(annotation)}</template>`;
3230
+ }).join("\n")}
3231
+ </Annotation>`;
3232
+ };
3233
+ md.inline.ruler.before("image", "annotation_ref", annotationRef);
3234
+ md.block.ruler.before("reference", "annotation", annotationDef, {
3235
+ alt: ["paragraph", "reference"]
3236
+ });
3237
+ };
3238
+
3047
3239
  // src/node/inline/icons.ts
3048
3240
  var iconsPlugin = (md, options = {}) => md.inline.ruler.before("emphasis", "iconify", createTokenizer(options));
3049
3241
  function createTokenizer(options) {
@@ -3144,6 +3336,12 @@ function inlineSyntaxPlugin(md, options) {
3144
3336
  md.use(sup);
3145
3337
  md.use(footnote);
3146
3338
  md.use(tasklist);
3339
+ if (options.annotation) {
3340
+ md.use(annotationPlugin);
3341
+ }
3342
+ if (options.abbr) {
3343
+ md.use(abbrPlugin);
3344
+ }
3147
3345
  if (options.icons) {
3148
3346
  md.use(iconsPlugin, isPlainObject3(options.icons) ? options.icons : {});
3149
3347
  }
@@ -3217,6 +3415,14 @@ async function prepareConfigFile(app, options) {
3217
3415
  enhances.add(`app.component('VPDemoBasic', VPDemoBasic)`);
3218
3416
  enhances.add(`app.component('VPDemoNormal', VPDemoNormal)`);
3219
3417
  }
3418
+ if (options.annotation) {
3419
+ imports.add(`import Annotation from '${CLIENT_FOLDER}components/Annotation.vue'`);
3420
+ enhances.add(`app.component('Annotation', Annotation)`);
3421
+ }
3422
+ if (options.abbr) {
3423
+ imports.add(`import Abbreviation from '${CLIENT_FOLDER}components/Abbreviation.vue'`);
3424
+ enhances.add(`app.component('Abbreviation', Abbreviation)`);
3425
+ }
3220
3426
  return app.writeTemp(
3221
3427
  "md-power/config.js",
3222
3428
  `import { defineClientConfig } from 'vuepress/client'
@@ -176,6 +176,12 @@ interface ReplEditorData {
176
176
  }
177
177
 
178
178
  interface MarkdownPowerPluginOptions {
179
+ /**
180
+ * 是否启用注释
181
+ * @default false
182
+ */
183
+ annotation?: boolean;
184
+ abbr?: boolean;
179
185
  /**
180
186
  * 配置代码块分组
181
187
  */
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.131",
4
+ "version": "1.0.0-rc.133",
5
5
  "description": "The Plugin for VuePress 2 - markdown power",
6
6
  "author": "pengzhanbo <volodymyr@foxmail.com>",
7
7
  "license": "MIT",
@@ -32,7 +32,7 @@
32
32
  ],
33
33
  "peerDependencies": {
34
34
  "artplayer": "^5.2.0",
35
- "dashjs": "^4.7.4",
35
+ "dashjs": "^5.0.0",
36
36
  "esbuild": ">=0.24.2",
37
37
  "hls.js": "^1.5.18",
38
38
  "less": "^4.2.1",
@@ -41,7 +41,7 @@
41
41
  "sass": "^1.83.0",
42
42
  "sass-embedded": "^1.83.0",
43
43
  "stylus": ">=0.64.0",
44
- "vuepress": "2.0.0-rc.19"
44
+ "vuepress": "2.0.0-rc.20"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "artplayer": {
@@ -68,17 +68,17 @@
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
- "@vuepress/helper": "2.0.0-rc.73",
71
+ "@vuepress/helper": "2.0.0-rc.79",
72
72
  "@vueuse/core": "^12.7.0",
73
73
  "chokidar": "3.6.0",
74
74
  "image-size": "^1.2.0",
75
75
  "local-pkg": "^1.0.0",
76
76
  "lru-cache": "^11.0.2",
77
77
  "markdown-it-container": "^4.0.0",
78
- "nanoid": "^5.1.0",
79
- "shiki": "^2.4.1",
80
- "tm-grammars": "^1.22.14",
81
- "tm-themes": "^1.9.12",
78
+ "nanoid": "^5.1.2",
79
+ "shiki": "^3.0.0",
80
+ "tm-grammars": "^1.22.17",
81
+ "tm-themes": "^1.9.13",
82
82
  "vue": "^3.5.13"
83
83
  },
84
84
  "devDependencies": {