vitepress-plugin-annotation 0.7.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pengzhanbo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # vitepress-plugin-annotation
2
+
3
+ Add annotation support to your VitePress site, rendering annotation references as interactive
4
+ markers that reveal a popover with the annotation content on click.
5
+
6
+ 为 VitePress 添加注释支持,将注释引用渲染为可交互的标记,点击后弹出包含注释内容的浮层。
7
+
8
+ ## Usage
9
+
10
+ ### With Vitepress-tuck
11
+
12
+ **Installation:**
13
+
14
+ ```bash
15
+ # npm
16
+ npm install -D vitepress-tuck vitepress-plugin-annotation
17
+ # pnpm
18
+ pnpm add -D vitepress-tuck vitepress-plugin-annotation
19
+ # yarn
20
+ yarn add -D vitepress-tuck vitepress-plugin-annotation
21
+ ```
22
+
23
+ **Configuration:**
24
+
25
+ ```ts
26
+ // .vitepress/config.ts
27
+ import annotation from 'vitepress-plugin-annotation'
28
+ import { defineConfig } from 'vitepress-tuck'
29
+
30
+ export default defineConfig({
31
+ plugins: [annotation()],
32
+ })
33
+ ```
34
+
35
+ ```ts
36
+ // .vitepress/theme/index.ts
37
+ import type { Theme } from 'vitepress'
38
+ import enhanceApp from 'virtual:enhance-app'
39
+ import DefaultTheme from 'vitepress/theme'
40
+
41
+ export default {
42
+ extends: DefaultTheme,
43
+ enhanceApp(ctx) {
44
+ enhanceApp(ctx)
45
+ },
46
+ } satisfies Theme
47
+ ```
48
+
49
+ ### With Vitepress
50
+
51
+ **Installation:**
52
+
53
+ ```bash
54
+ # npm
55
+ npm install -D vitepress-plugin-annotation
56
+ # pnpm
57
+ pnpm add -D vitepress-plugin-annotation
58
+ # yarn
59
+ yarn add -D vitepress-plugin-annotation
60
+ ```
61
+
62
+ **Configuration:**
63
+
64
+ ```ts
65
+ // .vitepress/config.ts
66
+ import { defineConfig } from 'vitepress'
67
+ import { annotationMarkdownPlugin } from 'vitepress-plugin-annotation'
68
+
69
+ export default defineConfig({
70
+ markdown: {
71
+ config: (md) => {
72
+ md.use(annotationMarkdownPlugin)
73
+ },
74
+ },
75
+ })
76
+ ```
77
+
78
+ ```ts
79
+ // .vitepress/theme/index.ts
80
+ import type { Theme } from 'vitepress'
81
+ import { enhanceAppWithAnnotation } from 'vitepress-plugin-annotation/client'
82
+ import DefaultTheme from 'vitepress/theme'
83
+
84
+ export default {
85
+ extends: DefaultTheme,
86
+ enhanceApp(ctx) {
87
+ enhanceAppWithAnnotation(ctx)
88
+ },
89
+ } satisfies Theme
90
+ ```
91
+
92
+ ## Syntax
93
+
94
+ Define an annotation with the `[+label]: annotation content` syntax, then reference it anywhere
95
+ in your markdown content using `[+label]`. The reference is rendered as a small interactive
96
+ marker that, on click, reveals a popover displaying the annotation content.
97
+
98
+ 使用 `[+标签]: 注释内容` 语法定义注释,然后在 markdown 内容的任意位置使用 `[+标签]`
99
+ 进行引用。引用会渲染为一个小的可交互标记,点击后弹出显示注释内容的浮层。
100
+
101
+ ```md
102
+ The **four great classical novels** [+novels] of Chinese literature are widely known.
103
+
104
+ [+novels]:
105
+ **Romance of the Three Kingdoms** — a historical novel set in the Three Kingdoms period.
106
+
107
+ [+novels]:
108
+ **Journey to the West** — a mythological tale of a pilgrimage to the West.
109
+ ```
110
+
111
+ The annotation content supports full block-level markdown, including headings, paragraphs,
112
+ lists, code blocks, and more.
113
+
114
+ 注释内容支持完整的块级 markdown 语法,包括标题、段落、列表、代码块等。
115
+
116
+ ```md
117
+ The framework is built on [+vue].
118
+
119
+ [+vue]:
120
+ ## Vue
121
+
122
+ A progressive framework for building user interfaces.
123
+
124
+ - Reactive data binding
125
+ - Component-based architecture
126
+ - [Learn more](https://vuejs.org/)
127
+ ```
128
+
129
+ ### Multi-line Definitions
130
+
131
+ Annotation definitions can span multiple lines. Continuation lines must be indented by at
132
+ least two spaces relative to the definition. Empty lines within the indented block are
133
+ preserved as part of the annotation content. A non-indented content line (such as the next
134
+ definition or a new paragraph) terminates the multi-line definition.
135
+
136
+ 注释定义可以跨多行。续行必须相对于定义至少缩进两个空格。缩进块内的空行会作为
137
+ 注释内容的一部分被保留。非缩进的内容行(如下一个定义或新段落)会终止多行定义。
138
+
139
+ ```md
140
+ This concept is explained in [+detail].
141
+
142
+ [+detail]:
143
+ This is the first paragraph of the annotation.
144
+
145
+ This is the second paragraph, separated by an empty line
146
+ but still part of the same annotation.
147
+
148
+ The annotation definition ends here because this line is not indented.
149
+ ```
150
+
151
+ ### Multiple Definitions per Label
152
+
153
+ A single label can be defined multiple times. All definitions are collected and displayed
154
+ as separate items in the popover, allowing you to provide multiple pieces of related
155
+ information for the same reference.
156
+
157
+ 同一标签可以多次定义。所有定义会被收集并作为独立条目展示在浮层中,允许你为同一
158
+ 引用提供多条相关信息。
159
+
160
+ ```md
161
+ JavaScript has multiple [+js] versions.
162
+
163
+ [+js]:
164
+ **ES2015 (ES6)** — Introduced classes, modules, arrows, and more.
165
+
166
+ [+js]:
167
+ **ES2020** — Added optional chaining, nullish coalescing, and BigInt.
168
+ ```
169
+
170
+ ## Global Annotations
171
+
172
+ Instead of (or in addition to) defining annotations inline in each markdown file, you can
173
+ provide a global preset of annotations through the plugin options. This is useful for terms
174
+ that should be annotated consistently across all pages.
175
+
176
+ 可以在每个 markdown 文件中内联定义注释,也可以通过插件选项提供全局注释预设。
177
+ 这对于需要在所有页面中一致注释的术语很有用。
178
+
179
+ ```ts
180
+ // .vitepress/config.ts
181
+ import annotation from 'vitepress-plugin-annotation'
182
+ import { defineConfig } from 'vitepress-tuck'
183
+
184
+ export default defineConfig({
185
+ plugins: [
186
+ annotation({
187
+ HTML: 'HyperText Markup Language',
188
+ CSS: ['Cascading Style Sheets', 'A style sheet language used for describing the presentation of a document.'],
189
+ }),
190
+ ],
191
+ })
192
+ ```
193
+
194
+ Each global annotation value can be a string or an array of strings. When an array is
195
+ provided, each element becomes a separate item in the popover, just like multiple inline
196
+ definitions for the same label.
197
+
198
+ 每个全局注释值可以是字符串或字符串数组。当提供数组时,每个元素成为浮层中的
199
+ 一个独立条目,就像同一标签的多个内联定义一样。
@@ -0,0 +1,47 @@
1
+ import { EnhanceAppContext } from "vitepress";
2
+
3
+ //#region src/client/VPAnnotation.vue.d.ts
4
+ type __VLS_Props = {
5
+ label: string;
6
+ total: number;
7
+ };
8
+ declare var __VLS_20: `item-${number}`, __VLS_21: {};
9
+ type __VLS_Slots = {} & { [K in NonNullable<typeof __VLS_20>]?: (props: typeof __VLS_21) => any };
10
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ type __VLS_WithSlots<T, S> = T & {
14
+ new (): {
15
+ $slots: S;
16
+ };
17
+ };
18
+ //#endregion
19
+ //#region src/client/index.d.ts
20
+ /**
21
+ * Enhances the VitePress application by registering the `VPAnnotation`
22
+ * component globally under the name `VPAnnotation`, so it can be used
23
+ * directly in Vue templates or rendered markdown content.
24
+ *
25
+ * 通过全局注册 `VPAnnotation` 组件来增强 VitePress 应用,
26
+ * 使其可在 Vue 模板或渲染的 markdown 内容中直接使用。
27
+ *
28
+ * @example
29
+ * `.vitepress/theme/index.ts`
30
+ * ```ts
31
+ * import type { Theme } from 'vitepress'
32
+ * import { enhanceAppWithAnnotation } from 'vitepress-plugin-annotation/client'
33
+ * import DefaultTheme from 'vitepress/theme'
34
+ *
35
+ * export default {
36
+ * extends: DefaultTheme,
37
+ * enhanceApp(ctx) {
38
+ * enhanceAppWithAnnotation(ctx)
39
+ * },
40
+ * } satisfies Theme
41
+ * ```
42
+ */
43
+ declare function enhanceAppWithAnnotation({
44
+ app
45
+ }: EnhanceAppContext): void;
46
+ //#endregion
47
+ export { _default as VPAnnotation, enhanceAppWithAnnotation };
@@ -0,0 +1,126 @@
1
+ import "../style.css";
2
+ import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, resolveComponent, unref, useTemplateRef, withCtx } from "vue";
3
+ import { autoUpdate, flip, shift, useFloating } from "@floating-ui/vue";
4
+ import { onClickOutside, useIntersectionObserver } from "@vueuse/core";
5
+ //#region src/client/VPAnnotation.vue
6
+ const _hoisted_1 = ["aria-label", "aria-expanded"];
7
+ const _sfc_main = /*@__PURE__*/ defineComponent({
8
+ inheritAttrs: false,
9
+ __name: "VPAnnotation",
10
+ props: {
11
+ label: {},
12
+ total: {}
13
+ },
14
+ setup(__props) {
15
+ /**
16
+ * VPAnnotation component for rendering annotation references with an
17
+ * interactive popover in VitePress.
18
+ *
19
+ * VPAnnotation 组件,用于在 VitePress 中渲染带有可交互浮层的注释引用。
20
+ *
21
+ * The annotation marker is rendered as a small inline span (styled via CSS as
22
+ * a superscript-like icon). When the user clicks or focuses the marker, a
23
+ * floating popover anchored to the marker is shown, displaying the annotation
24
+ * content provided via the `#item-0`, `#item-1`, … named slots. Each slot
25
+ * corresponds to one definition of the annotation label. The popover is
26
+ * teleported to `body` and positioned with `@floating-ui/vue`, applying
27
+ * offset, flip, and shift middleware for robust placement near viewport edges.
28
+ *
29
+ * 注释标记渲染为一个小型行内 span(通过 CSS 样式为类上标图标)。当用户点击或
30
+ * 聚焦该标记时,会显示一个锚定到标记的浮动浮层,展示通过 `#item-0`、
31
+ * `#item-1`、… 具名插槽提供的注释内容。每个插槽对应注释标签的一个定义。
32
+ * 浮层被传送到 `body`,并使用 `@floating-ui/vue` 定位,应用 offset、flip 和
33
+ * shift 中间件以保证在视口边缘附近的稳定定位。
34
+ *
35
+ * The popover automatically closes when:
36
+ * - The user clicks outside the marker and popover.
37
+ * - The marker scrolls out of the viewport.
38
+ *
39
+ * 浮层在以下情况下自动关闭:
40
+ * - 用户点击标记和浮层之外的区域。
41
+ * - 标记滚动出视口。
42
+ */
43
+ const active = ref(false);
44
+ const group = computed(() => Array.from({ length: __props.total }, (_, i) => i));
45
+ const annotation = useTemplateRef("annotation");
46
+ const tooltip = useTemplateRef("tooltip");
47
+ onClickOutside(annotation, () => {
48
+ active.value = false;
49
+ }, { ignore: [tooltip] });
50
+ useIntersectionObserver(annotation, ([entry]) => {
51
+ if (!entry.isIntersecting && active.value) active.value = false;
52
+ }, { rootMargin: "-64px 0px 0px 0px" });
53
+ const { floatingStyles, placement } = useFloating(annotation, tooltip, {
54
+ whileElementsMounted: autoUpdate,
55
+ middleware: [flip(), shift({ padding: {
56
+ top: 80,
57
+ left: 16,
58
+ bottom: 16
59
+ } })]
60
+ });
61
+ const inset = computed(() => placement.value.split("-")[0]);
62
+ return (_ctx, _cache) => {
63
+ const _component_ClientOnly = resolveComponent("ClientOnly");
64
+ return openBlock(), createElementBlock(Fragment, null, [createElementVNode("button", mergeProps(_ctx.$attrs, {
65
+ ref_key: "annotation",
66
+ ref: annotation,
67
+ type: "button",
68
+ class: ["vp-annotation", {
69
+ [__props.label]: true,
70
+ [inset.value]: true,
71
+ active: active.value
72
+ }],
73
+ "aria-label": __props.label,
74
+ "aria-expanded": active.value,
75
+ onClick: _cache[0] || (_cache[0] = ($event) => active.value = !active.value)
76
+ }), [..._cache[1] || (_cache[1] = [createElementVNode("span", { class: "vpi-annotation" }, null, -1)])], 16, _hoisted_1), createVNode(_component_ClientOnly, null, {
77
+ default: withCtx(() => [(openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: "fade-in" }, {
78
+ default: withCtx(() => [active.value ? (openBlock(), createElementBlock("div", {
79
+ key: 0,
80
+ ref_key: "tooltip",
81
+ ref: tooltip,
82
+ class: normalizeClass(["vp-annotation-popover", { group: group.value.length > 1 }]),
83
+ style: normalizeStyle(unref(floatingStyles))
84
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.value, (i) => {
85
+ return openBlock(), createElementBlock("div", {
86
+ key: __props.label + i,
87
+ class: "annotation"
88
+ }, [renderSlot(_ctx.$slots, `item-${i}`)]);
89
+ }), 128))], 6)) : createCommentVNode("v-if", true)]),
90
+ _: 3
91
+ })]))]),
92
+ _: 3
93
+ })], 64);
94
+ };
95
+ }
96
+ });
97
+ //#endregion
98
+ //#region src/client/index.ts
99
+ /**
100
+ * Enhances the VitePress application by registering the `VPAnnotation`
101
+ * component globally under the name `VPAnnotation`, so it can be used
102
+ * directly in Vue templates or rendered markdown content.
103
+ *
104
+ * 通过全局注册 `VPAnnotation` 组件来增强 VitePress 应用,
105
+ * 使其可在 Vue 模板或渲染的 markdown 内容中直接使用。
106
+ *
107
+ * @example
108
+ * `.vitepress/theme/index.ts`
109
+ * ```ts
110
+ * import type { Theme } from 'vitepress'
111
+ * import { enhanceAppWithAnnotation } from 'vitepress-plugin-annotation/client'
112
+ * import DefaultTheme from 'vitepress/theme'
113
+ *
114
+ * export default {
115
+ * extends: DefaultTheme,
116
+ * enhanceApp(ctx) {
117
+ * enhanceAppWithAnnotation(ctx)
118
+ * },
119
+ * } satisfies Theme
120
+ * ```
121
+ */
122
+ function enhanceAppWithAnnotation({ app }) {
123
+ app.component("VPAnnotation", _sfc_main);
124
+ }
125
+ //#endregion
126
+ export { _sfc_main as VPAnnotation, enhanceAppWithAnnotation };
@@ -0,0 +1,47 @@
1
+ import { EnhanceAppContext } from "vitepress";
2
+
3
+ //#region src/client/VPAnnotation.vue.d.ts
4
+ type __VLS_Props = {
5
+ label: string;
6
+ total: number;
7
+ };
8
+ declare var __VLS_20: `item-${number}`, __VLS_21: {};
9
+ type __VLS_Slots = {} & { [K in NonNullable<typeof __VLS_20>]?: (props: typeof __VLS_21) => any };
10
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ type __VLS_WithSlots<T, S> = T & {
14
+ new (): {
15
+ $slots: S;
16
+ };
17
+ };
18
+ //#endregion
19
+ //#region src/client/index.d.ts
20
+ /**
21
+ * Enhances the VitePress application by registering the `VPAnnotation`
22
+ * component globally under the name `VPAnnotation`, so it can be used
23
+ * directly in Vue templates or rendered markdown content.
24
+ *
25
+ * 通过全局注册 `VPAnnotation` 组件来增强 VitePress 应用,
26
+ * 使其可在 Vue 模板或渲染的 markdown 内容中直接使用。
27
+ *
28
+ * @example
29
+ * `.vitepress/theme/index.ts`
30
+ * ```ts
31
+ * import type { Theme } from 'vitepress'
32
+ * import { enhanceAppWithAnnotation } from 'vitepress-plugin-annotation/client'
33
+ * import DefaultTheme from 'vitepress/theme'
34
+ *
35
+ * export default {
36
+ * extends: DefaultTheme,
37
+ * enhanceApp(ctx) {
38
+ * enhanceAppWithAnnotation(ctx)
39
+ * },
40
+ * } satisfies Theme
41
+ * ```
42
+ */
43
+ declare function enhanceAppWithAnnotation({
44
+ app
45
+ }: EnhanceAppContext): void;
46
+ //#endregion
47
+ export { _default as VPAnnotation, enhanceAppWithAnnotation };
@@ -0,0 +1,146 @@
1
+ import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createVNode, defineComponent, mergeProps, openBlock, ref, renderList, renderSlot, resolveComponent, unref, useSSRContext, useTemplateRef, withCtx } from "vue";
2
+ import { ssrRenderAttrs, ssrRenderClass, ssrRenderComponent, ssrRenderList, ssrRenderSlot, ssrRenderStyle, ssrRenderTeleport } from "vue/server-renderer";
3
+ import { autoUpdate, flip, shift, useFloating } from "@floating-ui/vue";
4
+ import { onClickOutside, useIntersectionObserver } from "@vueuse/core";
5
+ //#region src/client/VPAnnotation.vue
6
+ const _sfc_main = /*@__PURE__*/ defineComponent({
7
+ inheritAttrs: false,
8
+ __name: "VPAnnotation",
9
+ __ssrInlineRender: true,
10
+ props: {
11
+ label: {},
12
+ total: {}
13
+ },
14
+ setup(__props) {
15
+ /**
16
+ * VPAnnotation component for rendering annotation references with an
17
+ * interactive popover in VitePress.
18
+ *
19
+ * VPAnnotation 组件,用于在 VitePress 中渲染带有可交互浮层的注释引用。
20
+ *
21
+ * The annotation marker is rendered as a small inline span (styled via CSS as
22
+ * a superscript-like icon). When the user clicks or focuses the marker, a
23
+ * floating popover anchored to the marker is shown, displaying the annotation
24
+ * content provided via the `#item-0`, `#item-1`, … named slots. Each slot
25
+ * corresponds to one definition of the annotation label. The popover is
26
+ * teleported to `body` and positioned with `@floating-ui/vue`, applying
27
+ * offset, flip, and shift middleware for robust placement near viewport edges.
28
+ *
29
+ * 注释标记渲染为一个小型行内 span(通过 CSS 样式为类上标图标)。当用户点击或
30
+ * 聚焦该标记时,会显示一个锚定到标记的浮动浮层,展示通过 `#item-0`、
31
+ * `#item-1`、… 具名插槽提供的注释内容。每个插槽对应注释标签的一个定义。
32
+ * 浮层被传送到 `body`,并使用 `@floating-ui/vue` 定位,应用 offset、flip 和
33
+ * shift 中间件以保证在视口边缘附近的稳定定位。
34
+ *
35
+ * The popover automatically closes when:
36
+ * - The user clicks outside the marker and popover.
37
+ * - The marker scrolls out of the viewport.
38
+ *
39
+ * 浮层在以下情况下自动关闭:
40
+ * - 用户点击标记和浮层之外的区域。
41
+ * - 标记滚动出视口。
42
+ */
43
+ const active = ref(false);
44
+ const group = computed(() => Array.from({ length: __props.total }, (_, i) => i));
45
+ const annotation = useTemplateRef("annotation");
46
+ const tooltip = useTemplateRef("tooltip");
47
+ onClickOutside(annotation, () => {
48
+ active.value = false;
49
+ }, { ignore: [tooltip] });
50
+ useIntersectionObserver(annotation, ([entry]) => {
51
+ if (!entry.isIntersecting && active.value) active.value = false;
52
+ }, { rootMargin: "-64px 0px 0px 0px" });
53
+ const { floatingStyles, placement } = useFloating(annotation, tooltip, {
54
+ whileElementsMounted: autoUpdate,
55
+ middleware: [flip(), shift({ padding: {
56
+ top: 80,
57
+ left: 16,
58
+ bottom: 16
59
+ } })]
60
+ });
61
+ const inset = computed(() => placement.value.split("-")[0]);
62
+ return (_ctx, _push, _parent, _attrs) => {
63
+ const _component_ClientOnly = resolveComponent("ClientOnly");
64
+ _push(`<!--[--><button${ssrRenderAttrs(mergeProps(_ctx.$attrs, {
65
+ ref_key: "annotation",
66
+ ref: annotation,
67
+ type: "button",
68
+ class: ["vp-annotation", {
69
+ [__props.label]: true,
70
+ [inset.value]: true,
71
+ active: active.value
72
+ }],
73
+ "aria-label": __props.label,
74
+ "aria-expanded": active.value
75
+ }))}><span class="vpi-annotation"></span></button>`);
76
+ _push(ssrRenderComponent(_component_ClientOnly, null, {
77
+ default: withCtx((_, _push, _parent, _scopeId) => {
78
+ if (_push) ssrRenderTeleport(_push, (_push) => {
79
+ if (active.value) {
80
+ _push(`<div class="${ssrRenderClass([{ group: group.value.length > 1 }, "vp-annotation-popover"])}" style="${ssrRenderStyle(unref(floatingStyles))}"${_scopeId}><!--[-->`);
81
+ ssrRenderList(group.value, (i) => {
82
+ _push(`<div class="annotation"${_scopeId}>`);
83
+ ssrRenderSlot(_ctx.$slots, `item-${i}`, {}, null, _push, _parent, _scopeId);
84
+ _push(`</div>`);
85
+ });
86
+ _push(`<!--]--></div>`);
87
+ } else _push(`<!---->`);
88
+ }, "body", false, _parent);
89
+ else return [(openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: "fade-in" }, {
90
+ default: withCtx(() => [active.value ? (openBlock(), createBlock("div", {
91
+ key: 0,
92
+ ref_key: "tooltip",
93
+ ref: tooltip,
94
+ class: ["vp-annotation-popover", { group: group.value.length > 1 }],
95
+ style: unref(floatingStyles)
96
+ }, [(openBlock(true), createBlock(Fragment, null, renderList(group.value, (i) => {
97
+ return openBlock(), createBlock("div", {
98
+ key: __props.label + i,
99
+ class: "annotation"
100
+ }, [renderSlot(_ctx.$slots, `item-${i}`)]);
101
+ }), 128))], 6)) : createCommentVNode("v-if", true)]),
102
+ _: 3
103
+ })]))];
104
+ }),
105
+ _: 3
106
+ }, _parent));
107
+ _push(`<!--]-->`);
108
+ };
109
+ }
110
+ });
111
+ const _sfc_setup = _sfc_main.setup;
112
+ _sfc_main.setup = (props, ctx) => {
113
+ const ssrContext = useSSRContext();
114
+ (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/client/VPAnnotation.vue");
115
+ return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
116
+ };
117
+ //#endregion
118
+ //#region src/client/index.ts
119
+ /**
120
+ * Enhances the VitePress application by registering the `VPAnnotation`
121
+ * component globally under the name `VPAnnotation`, so it can be used
122
+ * directly in Vue templates or rendered markdown content.
123
+ *
124
+ * 通过全局注册 `VPAnnotation` 组件来增强 VitePress 应用,
125
+ * 使其可在 Vue 模板或渲染的 markdown 内容中直接使用。
126
+ *
127
+ * @example
128
+ * `.vitepress/theme/index.ts`
129
+ * ```ts
130
+ * import type { Theme } from 'vitepress'
131
+ * import { enhanceAppWithAnnotation } from 'vitepress-plugin-annotation/client'
132
+ * import DefaultTheme from 'vitepress/theme'
133
+ *
134
+ * export default {
135
+ * extends: DefaultTheme,
136
+ * enhanceApp(ctx) {
137
+ * enhanceAppWithAnnotation(ctx)
138
+ * },
139
+ * } satisfies Theme
140
+ * ```
141
+ */
142
+ function enhanceAppWithAnnotation({ app }) {
143
+ app.component("VPAnnotation", _sfc_main);
144
+ }
145
+ //#endregion
146
+ export { _sfc_main as VPAnnotation, enhanceAppWithAnnotation };
@@ -0,0 +1,110 @@
1
+ @import url("vitepress-plugin-toolkit/styles/transition/fade-in.css");
2
+
3
+ .vp-annotation {
4
+ position: relative;
5
+ top: -2px;
6
+ z-index: 10;
7
+ display: inline-block;
8
+ width: 1.5em;
9
+ height: 1.5em;
10
+ color: currentcolor;
11
+ vertical-align: middle;
12
+ cursor: pointer;
13
+ user-select: none;
14
+ opacity: 0.5;
15
+ transition: 0.25s ease-in-out;
16
+ transition-property: color, opacity, transform;
17
+ transform: rotate(0deg);
18
+ }
19
+
20
+ @media print {
21
+ .vp-annotation {
22
+ display: none;
23
+ }
24
+ }
25
+
26
+ .vp-annotation:where(:hover, .active) {
27
+ color: var(--vp-c-brand-2) !important;
28
+ opacity: 1;
29
+ }
30
+
31
+ .vp-annotation.active.top {
32
+ transform: rotate(135deg);
33
+ }
34
+
35
+ .vp-annotation.active.left {
36
+ transform: rotate(45deg);
37
+ }
38
+
39
+ .vp-annotation.active.bottom {
40
+ transform: rotate(-45deg);
41
+ }
42
+
43
+ .vp-annotation.active.right {
44
+ transform: rotate(-135deg);
45
+ }
46
+
47
+ .vp-annotation .vpi-annotation {
48
+ --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");
49
+
50
+ display: inline-block;
51
+ width: 100%;
52
+ height: 100%;
53
+ }
54
+
55
+ .vp-annotation-popover {
56
+ position: absolute;
57
+ top: 0;
58
+ left: 0;
59
+ z-index: 1;
60
+ width: max-content;
61
+ max-width: min(calc(100vw - 32px), 360px);
62
+ max-height: 360px;
63
+ padding-block: 8px;
64
+ padding-inline: 12px;
65
+ overflow: auto;
66
+ font-size: 14px;
67
+ font-weight: normal;
68
+ background-color: var(--vp-c-bg);
69
+ border: solid 1px var(--vp-c-divider);
70
+ border-radius: 8px;
71
+ box-shadow: var(--vp-shadow-2);
72
+ }
73
+
74
+ .vp-annotation-popover.group {
75
+ display: flex;
76
+ flex-direction: column;
77
+ gap: 12px;
78
+ padding: 12px;
79
+ background-color: var(--vp-c-bg-soft);
80
+ }
81
+
82
+ .vp-annotation-popover.group .annotation {
83
+ padding-block: 4px;
84
+ padding-inline: 12px;
85
+ background-color: var(--vp-c-bg);
86
+ border-radius: 4px;
87
+ box-shadow: var(--vp-shadow-1);
88
+ }
89
+
90
+ .vp-annotation-popover p {
91
+ margin-block: 12px;
92
+ margin-inline: 0;
93
+ line-height: 24px;
94
+ }
95
+
96
+ .vp-annotation-popover :first-child {
97
+ margin-block-start: 4px;
98
+ }
99
+
100
+ .vp-annotation-popover :last-child {
101
+ margin-block-end: 4px;
102
+ }
103
+
104
+ .vp-annotation-popover.group :first-child {
105
+ margin-block-start: 8px;
106
+ }
107
+
108
+ .vp-annotation-popover.group :last-child {
109
+ margin-block-end: 8px;
110
+ }
@@ -0,0 +1,104 @@
1
+ import { PluginWithOptions } from "markdown-it";
2
+
3
+ //#region src/node/plugin.d.ts
4
+ /**
5
+ * VitePress plugin for annotation support in markdown content.
6
+ *
7
+ * VitePress 插件,用于在 markdown 内容中支持注释功能。
8
+ *
9
+ * The plugin registers annotation definition and reference rules in markdown-it,
10
+ * and wires up the client-side `VPAnnotation` component via `componentResolver`
11
+ * so that annotation references render as interactive markers that, on click,
12
+ * reveal a popover with the annotation content.
13
+ *
14
+ * 该插件在 markdown-it 中注册注释定义与引用规则,并通过 `componentResolver`
15
+ * 接入客户端 `VPAnnotation` 组件,使注释引用渲染为可交互的标记,点击后弹出
16
+ * 包含注释内容的浮层。
17
+ *
18
+ * Annotations can be defined inline in markdown using the syntax
19
+ * `[+label]: annotation content`, or provided globally through the `annotations`
20
+ * option. A single label can be defined multiple times — all definitions are
21
+ * collected and displayed as separate items in the popover. Annotation content
22
+ * supports full block-level markdown.
23
+ *
24
+ * 注释可以在 markdown 中通过 `[+标签]: 注释内容` 语法内联定义,也可以通过
25
+ * `annotations` 选项全局提供。同一标签可多次定义 —— 所有定义会被收集并作为
26
+ * 独立条目展示在浮层中。注释内容支持完整的块级 markdown 语法。
27
+ *
28
+ * @param annotations - Global annotations preset, a map of label to annotation
29
+ * content (string or string array) / 全局注释预设,标签到注释内容
30
+ * (字符串或字符串数组)的映射
31
+ * @example
32
+ * `.vitepress/config.ts` without global annotations
33
+ * ```ts
34
+ * import { defineConfig } from 'vitepress-tuck'
35
+ * import annotation from 'vitepress-plugin-annotation'
36
+ *
37
+ * export default defineConfig({
38
+ * plugins: [annotation()],
39
+ * })
40
+ * ```
41
+ * @example
42
+ * `.vitepress/config.ts` with global annotations
43
+ * ```ts
44
+ * import { defineConfig } from 'vitepress-tuck'
45
+ * import annotation from 'vitepress-plugin-annotation'
46
+ *
47
+ * export default defineConfig({
48
+ * plugins: [
49
+ * annotation({
50
+ * HTML: 'HyperText Markup Language',
51
+ * }),
52
+ * ],
53
+ * })
54
+ * ```
55
+ * @example
56
+ * // Markdown usage
57
+ * ```md
58
+ * The **four great classical novels** [+novels] of Chinese literature.
59
+ *
60
+ * [+novels]:
61
+ * **Romance of the Three Kingdoms** — a historical novel.
62
+ *
63
+ * [+novels]:
64
+ * **Journey to the West** — a mythological adventure.
65
+ * ```
66
+ */
67
+ declare const annotation: (options?: Record<string, string | string[]> | undefined) => import("vitepress-tuck").VitepressPlugin;
68
+ //#endregion
69
+ //#region src/node/markdown.d.ts
70
+ /**
71
+ * Annotation plugin - Enable annotation syntax in markdown-it.
72
+ *
73
+ * 注释插件 - 在 markdown-it 中启用注释语法。
74
+ *
75
+ * Registers two rules:
76
+ * - A block rule (`annotationDef`) that recognizes annotation definitions of
77
+ * the form `[+label]: content` and stores them in `env.annotations`.
78
+ * Definitions support multi-line content via indented continuation lines,
79
+ * and multiple definitions for the same label are accumulated.
80
+ * - An inline rule (`annotationRef`) that recognizes annotation references of
81
+ * the form `[+label]` and pushes an `annotation_ref` token to be rendered
82
+ * as a `<VPAnnotation>` component.
83
+ *
84
+ * 注册两条规则:
85
+ * - 块规则(`annotationDef`)识别 `[+标签]: 内容` 形式的注释定义,并将其
86
+ * 存储到 `env.annotations` 中。定义通过缩进续行支持多行内容,同一标签的
87
+ * 多次定义会被累加。
88
+ * - 行内规则(`annotationRef`)识别 `[+标签]` 形式的注释引用,并推入
89
+ * `annotation_ref` 令牌,最终渲染为 `<VPAnnotation>` 组件。
90
+ *
91
+ * Definition syntax: `[+label]: annotation content`
92
+ * Reference syntax: `[+label]`
93
+ *
94
+ * 定义语法:`[+标签]: 注释内容`
95
+ * 引用语法:`[+标签]`
96
+ *
97
+ * @param md - Markdown-it instance / Markdown-it 实例
98
+ * @param globalAnnotations - Global annotations preset, a map of label to
99
+ * annotation content (string or string array) / 全局注释预设,标签到
100
+ * 注释内容(字符串或字符串数组)的映射
101
+ */
102
+ declare const annotationMarkdownPlugin: PluginWithOptions<Record<string, string | string[]>>;
103
+ //#endregion
104
+ export { annotation, annotation as default, annotationMarkdownPlugin };
@@ -0,0 +1,238 @@
1
+ import { definePlugin } from "vitepress-tuck";
2
+ import { objectMap, toArray } from "@pengzhanbo/utils";
3
+ import { cleanMarkdownEnv } from "vitepress-plugin-toolkit";
4
+ //#region src/node/markdown.ts
5
+ /**
6
+ * Annotation definition rule
7
+ *
8
+ * 注释定义规则
9
+ *
10
+ * @param state - State block / 状态块
11
+ * @param startLine - Start line number / 开始行号
12
+ * @param endLine - End line number / 结束行号
13
+ * @param silent - Silent mode / 静默模式
14
+ * @returns Whether matched / 是否匹配
15
+ */
16
+ const annotationDef = (state, startLine, endLine, silent) => {
17
+ const start = state.bMarks[startLine] + state.tShift[startLine];
18
+ const max = state.eMarks[startLine];
19
+ if (start + 4 > max || state.src.charAt(start) !== "[" || state.src.charAt(start + 1) !== "+") return false;
20
+ let pos = start + 2;
21
+ while (pos < max) {
22
+ if (state.src.charAt(pos) === " ") return false;
23
+ if (state.src.charAt(pos) === "]") break;
24
+ pos++;
25
+ }
26
+ if (pos === start + 2 || pos + 1 >= max || state.src.charAt(++pos) !== ":") return false;
27
+ /* istanbul ignore if -- @preserve */
28
+ if (silent) return true;
29
+ pos++;
30
+ const data = state.env.annotations ??= {};
31
+ const label = state.src.slice(start + 2, pos - 2);
32
+ let annotation = state.src.slice(pos, max).trim();
33
+ let nextLine = startLine + 1;
34
+ while (nextLine < endLine) {
35
+ const nextStart = state.bMarks[nextLine] + state.tShift[nextLine];
36
+ const nextMax = state.eMarks[nextLine];
37
+ const source = state.src.slice(nextStart, nextMax).slice(state.blkIndent).trimEnd();
38
+ if (state.sCount[nextLine] < state.blkIndent + 2 && source !== "") break;
39
+ annotation += `\n${source}`;
40
+ nextLine++;
41
+ }
42
+ (data[`:${label}`] ??= {
43
+ sources: [],
44
+ rendered: []
45
+ }).sources.push(annotation);
46
+ state.line = nextLine;
47
+ return true;
48
+ };
49
+ /**
50
+ * Annotation reference rule
51
+ *
52
+ * 注释引用规则
53
+ *
54
+ * @param state - State inline / 行内状态
55
+ * @param silent - Silent mode / 静默模式
56
+ * @returns Whether matched / 是否匹配
57
+ */
58
+ const annotationRef = (state, silent) => {
59
+ const start = state.pos;
60
+ const max = state.posMax;
61
+ if (start + 3 > max || typeof state.env.annotations === "undefined" || state.src.charAt(start) !== "[" || state.src.charAt(start + 1) !== "+") return false;
62
+ let pos = start + 2;
63
+ while (pos < max) {
64
+ if (state.src.charAt(pos) === " " || state.src.charAt(pos) === "\n") return false;
65
+ if (state.src.charAt(pos) === "]") break;
66
+ pos++;
67
+ }
68
+ if (pos === start + 2 || pos >= max) return false;
69
+ pos++;
70
+ const label = state.src.slice(start + 2, pos - 1);
71
+ if ((state.env.annotations?.[`:${label}`]?.sources ?? []).length === 0) return false;
72
+ /* istanbul ignore if -- @preserve */
73
+ if (!silent) {
74
+ const refToken = state.push("annotation_ref", "", 0);
75
+ refToken.meta = { label };
76
+ }
77
+ state.pos = pos;
78
+ state.posMax = max;
79
+ return true;
80
+ };
81
+ /**
82
+ * Annotation plugin - Enable annotation syntax in markdown-it.
83
+ *
84
+ * 注释插件 - 在 markdown-it 中启用注释语法。
85
+ *
86
+ * Registers two rules:
87
+ * - A block rule (`annotationDef`) that recognizes annotation definitions of
88
+ * the form `[+label]: content` and stores them in `env.annotations`.
89
+ * Definitions support multi-line content via indented continuation lines,
90
+ * and multiple definitions for the same label are accumulated.
91
+ * - An inline rule (`annotationRef`) that recognizes annotation references of
92
+ * the form `[+label]` and pushes an `annotation_ref` token to be rendered
93
+ * as a `<VPAnnotation>` component.
94
+ *
95
+ * 注册两条规则:
96
+ * - 块规则(`annotationDef`)识别 `[+标签]: 内容` 形式的注释定义,并将其
97
+ * 存储到 `env.annotations` 中。定义通过缩进续行支持多行内容,同一标签的
98
+ * 多次定义会被累加。
99
+ * - 行内规则(`annotationRef`)识别 `[+标签]` 形式的注释引用,并推入
100
+ * `annotation_ref` 令牌,最终渲染为 `<VPAnnotation>` 组件。
101
+ *
102
+ * Definition syntax: `[+label]: annotation content`
103
+ * Reference syntax: `[+label]`
104
+ *
105
+ * 定义语法:`[+标签]: 注释内容`
106
+ * 引用语法:`[+标签]`
107
+ *
108
+ * @param md - Markdown-it instance / Markdown-it 实例
109
+ * @param globalAnnotations - Global annotations preset, a map of label to
110
+ * annotation content (string or string array) / 全局注释预设,标签到
111
+ * 注释内容(字符串或字符串数组)的映射
112
+ */
113
+ const annotationMarkdownPlugin = (md, globalAnnotations = {}) => {
114
+ const annotations = objectMap(globalAnnotations, (key, value) => {
115
+ return [key.startsWith(":") ? key : `:${key}`, {
116
+ sources: toArray(value),
117
+ rendered: []
118
+ }];
119
+ });
120
+ /**
121
+ * Custom renderer for the `annotation_ref` token.
122
+ *
123
+ * `annotation_ref` 令牌的自定义渲染器。
124
+ *
125
+ * Renders the annotation reference as a `<VPAnnotation>` component tag. Each
126
+ * annotation source is rendered as block-level markdown and placed into a
127
+ * named slot (`#item-0`, `#item-1`, …). Rendered results are cached on the
128
+ * environment so that repeated references to the same label reuse the
129
+ * rendered output without re-rendering. The environment passed to the nested
130
+ * render is cleaned via `cleanMarkdownEnv` to strip `references` and
131
+ * `annotations`, preventing recursive annotation processing inside annotation
132
+ * content.
133
+ *
134
+ * 将注释引用渲染为 `<VPAnnotation>` 组件标签。每个注释源作为块级 markdown
135
+ * 渲染,并放入具名插槽(`#item-0`、`#item-1`、…)。渲染结果缓存在环境对象上,
136
+ * 使得对同一标签的重复引用可复用已渲染的结果而无需重复渲染。传递给嵌套渲染的
137
+ * 环境通过 `cleanMarkdownEnv` 清理,去除 `references` 和 `annotations`,
138
+ * 防止在注释内容中递归处理注释。
139
+ *
140
+ * When a label is not found in the inline (env) annotations, the renderer
141
+ * falls back to the global annotations preset.
142
+ *
143
+ * 当标签在内联(环境)注释中未找到时,渲染器回退到全局注释预设。
144
+ *
145
+ * @param tokens - Token array / token 数组
146
+ * @param idx - Current token index / 当前 token 索引
147
+ * @param _ - Render options (unused) / 渲染选项(未使用)
148
+ * @param env - Render environment containing annotations / 包含注释的渲染环境
149
+ * @returns Rendered HTML string / 渲染后的 HTML 字符串
150
+ */
151
+ md.renderer.rules.annotation_ref = (tokens, idx, _, env) => {
152
+ const label = tokens[idx].meta.label;
153
+ /* istanbul ignore next -- @preserve */
154
+ const data = env.annotations[`:${label}`] || annotations[`:${label}`];
155
+ return `<VPAnnotation label="${md.utils.escapeHtml(label)}" :total="${data.sources.length}">${data.sources.map((source, i) => {
156
+ return `<template #item-${i}>${data.rendered[i] ??= md.render(source, cleanMarkdownEnv(env, ["references", "annotations"]))}</template>`;
157
+ }).join("\n")}</VPAnnotation>`;
158
+ };
159
+ md.inline.ruler.before("image", "annotation_ref", annotationRef);
160
+ md.block.ruler.before("reference", "annotation", annotationDef, { alt: ["paragraph", "reference"] });
161
+ };
162
+ //#endregion
163
+ //#region src/node/plugin.ts
164
+ /**
165
+ * VitePress plugin for annotation support in markdown content.
166
+ *
167
+ * VitePress 插件,用于在 markdown 内容中支持注释功能。
168
+ *
169
+ * The plugin registers annotation definition and reference rules in markdown-it,
170
+ * and wires up the client-side `VPAnnotation` component via `componentResolver`
171
+ * so that annotation references render as interactive markers that, on click,
172
+ * reveal a popover with the annotation content.
173
+ *
174
+ * 该插件在 markdown-it 中注册注释定义与引用规则,并通过 `componentResolver`
175
+ * 接入客户端 `VPAnnotation` 组件,使注释引用渲染为可交互的标记,点击后弹出
176
+ * 包含注释内容的浮层。
177
+ *
178
+ * Annotations can be defined inline in markdown using the syntax
179
+ * `[+label]: annotation content`, or provided globally through the `annotations`
180
+ * option. A single label can be defined multiple times — all definitions are
181
+ * collected and displayed as separate items in the popover. Annotation content
182
+ * supports full block-level markdown.
183
+ *
184
+ * 注释可以在 markdown 中通过 `[+标签]: 注释内容` 语法内联定义,也可以通过
185
+ * `annotations` 选项全局提供。同一标签可多次定义 —— 所有定义会被收集并作为
186
+ * 独立条目展示在浮层中。注释内容支持完整的块级 markdown 语法。
187
+ *
188
+ * @param annotations - Global annotations preset, a map of label to annotation
189
+ * content (string or string array) / 全局注释预设,标签到注释内容
190
+ * (字符串或字符串数组)的映射
191
+ * @example
192
+ * `.vitepress/config.ts` without global annotations
193
+ * ```ts
194
+ * import { defineConfig } from 'vitepress-tuck'
195
+ * import annotation from 'vitepress-plugin-annotation'
196
+ *
197
+ * export default defineConfig({
198
+ * plugins: [annotation()],
199
+ * })
200
+ * ```
201
+ * @example
202
+ * `.vitepress/config.ts` with global annotations
203
+ * ```ts
204
+ * import { defineConfig } from 'vitepress-tuck'
205
+ * import annotation from 'vitepress-plugin-annotation'
206
+ *
207
+ * export default defineConfig({
208
+ * plugins: [
209
+ * annotation({
210
+ * HTML: 'HyperText Markup Language',
211
+ * }),
212
+ * ],
213
+ * })
214
+ * ```
215
+ * @example
216
+ * // Markdown usage
217
+ * ```md
218
+ * The **four great classical novels** [+novels] of Chinese literature.
219
+ *
220
+ * [+novels]:
221
+ * **Romance of the Three Kingdoms** — a historical novel.
222
+ *
223
+ * [+novels]:
224
+ * **Journey to the West** — a mythological adventure.
225
+ * ```
226
+ */
227
+ const annotation = definePlugin((annotations) => ({
228
+ name: "vitepress-plugin-annotation",
229
+ componentResolver: ["VPAnnotation"],
230
+ markdown: { config(md) {
231
+ md.use(annotationMarkdownPlugin, annotations);
232
+ } }
233
+ }));
234
+ //#endregion
235
+ //#region src/node/index.ts
236
+ var node_default = annotation;
237
+ //#endregion
238
+ export { annotation, annotationMarkdownPlugin, node_default as default };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "vitepress-plugin-annotation",
3
+ "type": "module",
4
+ "version": "0.7.0",
5
+ "description": "Add annotation support to VitePress",
6
+ "author": "pengzhanbo <q942450674@outlook.com> (https://github.com/pengzhanbo/)",
7
+ "license": "MIT",
8
+ "homepage": "https://tuck.pengzhanbo.cn/plugins/annotation",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/pengzhanbo/vitepress-tuck.git",
12
+ "directory": "packages/plugin-annotation"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/pengzhanbo/vitepress-tuck/issues"
16
+ },
17
+ "keywords": [
18
+ "vitepress",
19
+ "vitepress-plugin",
20
+ "annotation"
21
+ ],
22
+ "exports": {
23
+ ".": "./dist/node/index.js",
24
+ "./client": {
25
+ "browser": "./dist/client/browser/index.js",
26
+ "default": "./dist/client/ssr/index.js"
27
+ },
28
+ "./style.css": "./dist/client/style.css"
29
+ },
30
+ "module": "./dist/node/index.js",
31
+ "types": "./dist/node/index.d.ts",
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "peerDependencies": {
36
+ "vitepress": "^1.6.4 || ^2.0.0-alpha.17",
37
+ "vue": "^3.5.0"
38
+ },
39
+ "dependencies": {
40
+ "@floating-ui/vue": "^2.0.0",
41
+ "@pengzhanbo/utils": "^3.7.3",
42
+ "@vueuse/core": "^14.3.0",
43
+ "vitepress-tuck": "0.7.0",
44
+ "vitepress-plugin-toolkit": "0.7.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "scripts": {
50
+ "clean": "rimraf --glob ./dist",
51
+ "dev": "pnpm '/(tsdown|copy):watch/'",
52
+ "build": "pnpm tsdown && pnpm copy",
53
+ "copy": "cpx \"src/**/*.css\" dist",
54
+ "copy:watch": "pnpm copy -w",
55
+ "tsdown": "tsdown --config-loader unrun",
56
+ "tsdown:watch": "pnpm tsdown -w"
57
+ }
58
+ }