@liujitcn/kratos-admin-core 0.0.1 → 0.0.16

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,19 @@
1
+ import "md-editor-v3/lib/preview.css";
2
+ /** Markdown 预览组件属性。 */
3
+ interface MarkdownPreviewProps {
4
+ /** Markdown 原文。 */
5
+ modelValue: string;
6
+ /** 是否使用暗色主题。 */
7
+ isDark?: boolean;
8
+ /** 预览根节点 ID。 */
9
+ id?: string;
10
+ /** 代码块最大高度。 */
11
+ maxCodeHeight?: string;
12
+ }
13
+ declare const __VLS_export: import("vue").DefineComponent<MarkdownPreviewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<MarkdownPreviewProps> & Readonly<{}>, {
14
+ id: string;
15
+ isDark: boolean;
16
+ maxCodeHeight: string;
17
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -0,0 +1,292 @@
1
+ <template>
2
+ <MdPreview
3
+ v-bind="$attrs"
4
+ :id="resolvedId"
5
+ class="core-markdown-preview"
6
+ :model-value="props.modelValue"
7
+ :theme="props.isDark ? 'dark' : 'light'"
8
+ preview-theme="github"
9
+ code-theme="github"
10
+ language="zh-CN"
11
+ :show-code-row-number="false"
12
+ :code-foldable="false"
13
+ :no-mermaid="true"
14
+ :no-katex="true"
15
+ :no-echarts="true"
16
+ :no-img-zoom-in="true"
17
+ :sanitize="sanitizeMarkdownHtml"
18
+ :md-heading-id="createMarkdownHeadingId"
19
+ :style="{ '--core-markdown-code-max-height': props.maxCodeHeight }"
20
+ />
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ import { computed, useId } from "vue";
25
+ import DOMPurify from "dompurify";
26
+ import hljs from "highlight.js";
27
+ import { config as configureMarkdownPreview, MdPreview } from "md-editor-v3";
28
+ import type { MdHeadingId } from "md-editor-v3";
29
+ import "md-editor-v3/lib/preview.css";
30
+
31
+ defineOptions({
32
+ name: "CoreMarkdownPreview",
33
+ inheritAttrs: false
34
+ });
35
+
36
+ /** Markdown 预览组件属性。 */
37
+ interface MarkdownPreviewProps {
38
+ /** Markdown 原文。 */
39
+ modelValue: string;
40
+ /** 是否使用暗色主题。 */
41
+ isDark?: boolean;
42
+ /** 预览根节点 ID。 */
43
+ id?: string;
44
+ /** 代码块最大高度。 */
45
+ maxCodeHeight?: string;
46
+ }
47
+
48
+ const props = withDefaults(defineProps<MarkdownPreviewProps>(), {
49
+ isDark: false,
50
+ id: "",
51
+ maxCodeHeight: "480px"
52
+ });
53
+ const generatedId = useId();
54
+ const resolvedId = computed(() => props.id || `core-markdown-preview-${generatedId.replaceAll(":", "")}`);
55
+ const markdownHeadingIdCounts = new Map<string, number>();
56
+
57
+ configureMarkdownPreview({
58
+ editorExtensions: {
59
+ highlight: {
60
+ instance: hljs
61
+ }
62
+ }
63
+ });
64
+
65
+ /** 清洗 Markdown 中允许渲染的原生 HTML。 */
66
+ function sanitizeMarkdownHtml(html: string) {
67
+ return DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
68
+ }
69
+
70
+ /** 生成兼容中文和重复标题的稳定 Markdown 锚点。 */
71
+ function createMarkdownHeadingId({ text, index }: Parameters<MdHeadingId>[0]) {
72
+ if (index === 1) markdownHeadingIdCounts.clear();
73
+ const slug =
74
+ text
75
+ .trim()
76
+ .toLocaleLowerCase()
77
+ .replace(/\s+/g, "-")
78
+ .replace(/[^\p{Letter}\p{Number}_-]/gu, "") || `heading-${index}`;
79
+ const duplicateIndex = markdownHeadingIdCounts.get(slug) ?? 0;
80
+ markdownHeadingIdCounts.set(slug, duplicateIndex + 1);
81
+ return duplicateIndex ? `${slug}-${duplicateIndex}` : slug;
82
+ }
83
+ </script>
84
+
85
+ <style scoped lang="scss">
86
+ .core-markdown-preview {
87
+ color: var(--admin-page-text-primary);
88
+ background: transparent;
89
+
90
+ --md-color: var(--admin-page-text-primary);
91
+ --md-hover-color: var(--admin-page-text-primary);
92
+ --md-bk-color: transparent;
93
+ --md-bk-color-outstand: var(--admin-page-card-bg-muted);
94
+ --md-bk-hover-color: var(--admin-page-card-bg-soft);
95
+ --md-border-color: var(--admin-page-card-border-soft);
96
+ --md-border-hover-color: var(--admin-page-divider-strong);
97
+ --md-border-active-color: var(--admin-page-text-secondary);
98
+ }
99
+ .core-markdown-preview :deep(.md-editor-preview) {
100
+ font-size: 15px;
101
+ line-height: 1.75;
102
+ color: var(--admin-page-text-primary);
103
+ word-break: normal;
104
+
105
+ --md-theme-color: var(--admin-page-text-primary);
106
+ --md-theme-heading-color: var(--admin-page-text-primary);
107
+ --md-theme-heading-6-color: var(--admin-page-text-secondary);
108
+ --md-theme-heading-bg-color: transparent;
109
+ --md-theme-heading-1-border: 1px solid var(--admin-page-divider-strong);
110
+ --md-theme-heading-2-border: 1px solid var(--admin-page-divider);
111
+ --md-theme-link-color: var(--el-color-primary);
112
+ --md-theme-link-hover-color: var(--el-color-primary-light-3);
113
+ --md-theme-border-color: var(--admin-page-card-border-soft);
114
+ --md-theme-quote-color: var(--admin-page-text-secondary);
115
+ --md-theme-quote-border: 4px solid var(--el-color-primary-light-5);
116
+ --md-theme-table-stripe-color: var(--el-fill-color-lighter);
117
+ --md-theme-table-tr-bg-color: transparent;
118
+ --md-theme-table-td-border-color: var(--admin-page-card-border-soft);
119
+ --md-theme-code-inline-color: var(--admin-page-accent-soft-text);
120
+ --md-theme-code-inline-bg-color: var(--admin-page-card-bg-muted);
121
+ --md-theme-code-inline-radius: 4px;
122
+ --md-theme-code-block-color: var(--admin-page-text-primary);
123
+ --md-theme-code-block-bg-color: var(--admin-page-card-bg-muted);
124
+ --md-theme-code-before-bg-color: var(--admin-page-card-bg-muted);
125
+ --md-theme-code-block-radius: var(--admin-page-radius);
126
+ }
127
+ .core-markdown-preview :deep(.md-editor-preview > :first-child) {
128
+ margin-top: 0;
129
+ }
130
+ .core-markdown-preview :deep(.md-editor-preview > :last-child) {
131
+ margin-bottom: 0;
132
+ }
133
+ .core-markdown-preview :deep(h1),
134
+ .core-markdown-preview :deep(h2),
135
+ .core-markdown-preview :deep(h3),
136
+ .core-markdown-preview :deep(h4),
137
+ .core-markdown-preview :deep(h5),
138
+ .core-markdown-preview :deep(h6) {
139
+ line-height: 1.35;
140
+ color: var(--admin-page-text-primary);
141
+ letter-spacing: 0;
142
+ scroll-margin-top: 16px;
143
+ }
144
+ .core-markdown-preview :deep(a:hover) {
145
+ text-underline-offset: 3px;
146
+ }
147
+ .core-markdown-preview :deep(blockquote) {
148
+ padding: 10px 16px;
149
+ margin: 20px 0;
150
+ background: var(--admin-page-card-bg-soft);
151
+ }
152
+ .core-markdown-preview :deep(blockquote > :last-child) {
153
+ margin-bottom: 0;
154
+ }
155
+ .core-markdown-preview :deep(table) {
156
+ display: block;
157
+ width: max-content;
158
+ min-width: 100%;
159
+ max-width: 100%;
160
+ margin: 18px 0 24px;
161
+ overflow-x: auto;
162
+ border-spacing: 0;
163
+ border-collapse: collapse;
164
+ }
165
+ .core-markdown-preview :deep(th),
166
+ .core-markdown-preview :deep(td) {
167
+ min-width: 120px;
168
+ padding: 9px 12px;
169
+ line-height: 1.55;
170
+ vertical-align: top;
171
+ text-align: left;
172
+ border: 1px solid var(--admin-page-card-border-soft);
173
+ }
174
+ .core-markdown-preview :deep(th) {
175
+ font-weight: 600;
176
+ background: var(--admin-page-card-bg-soft);
177
+ }
178
+ .core-markdown-preview :deep(tbody tr:nth-child(even)) {
179
+ background: var(--el-fill-color-lighter);
180
+ }
181
+ .core-markdown-preview :deep(.md-editor-code) {
182
+ margin: 16px 0 20px;
183
+ overflow: hidden;
184
+ background: var(--admin-page-card-bg-muted);
185
+ border: 1px solid var(--admin-page-card-border-soft);
186
+ border-radius: var(--admin-page-radius);
187
+ }
188
+ .core-markdown-preview :deep(.md-editor-preview .md-editor-code .md-editor-code-head) {
189
+ position: absolute;
190
+ inset: 6px 6px auto auto;
191
+ z-index: 2;
192
+ display: block;
193
+ width: auto;
194
+ height: auto;
195
+ margin: 0;
196
+ pointer-events: none;
197
+ background: transparent;
198
+ opacity: 0;
199
+ transition: opacity 0.15s ease;
200
+ }
201
+ .core-markdown-preview :deep(.md-editor-code:hover .md-editor-code-head) {
202
+ pointer-events: auto;
203
+ opacity: 1;
204
+ }
205
+ .core-markdown-preview :deep(.md-editor-code-flag),
206
+ .core-markdown-preview :deep(.md-editor-code-lang),
207
+ .core-markdown-preview :deep(.md-editor-collapse-tips) {
208
+ display: none;
209
+ }
210
+ .core-markdown-preview :deep(.md-editor-code .md-editor-code-action > *) {
211
+ margin: 0;
212
+ }
213
+ .core-markdown-preview :deep(.md-editor-copy-button) {
214
+ display: inline-flex;
215
+ align-items: center;
216
+ min-height: 28px;
217
+ padding: 0 8px;
218
+ font-size: 12px;
219
+ line-height: 1;
220
+ color: var(--admin-page-text-secondary);
221
+ cursor: pointer;
222
+ background: var(--admin-page-card-bg);
223
+ border: 1px solid var(--admin-page-card-border-soft);
224
+ border-radius: 4px;
225
+ box-shadow: var(--admin-page-shadow);
226
+ }
227
+ .core-markdown-preview :deep(.md-editor-code pre) {
228
+ max-height: var(--core-markdown-code-max-height);
229
+ margin: 0;
230
+ overflow: auto;
231
+ }
232
+ .core-markdown-preview :deep(.md-editor-code pre code) {
233
+ min-height: 0;
234
+ padding: 10px 12px;
235
+ margin: 0;
236
+ font-size: 14px;
237
+ line-height: 1.55;
238
+ color: var(--admin-page-text-primary);
239
+ letter-spacing: 0;
240
+ white-space: pre;
241
+ background: transparent;
242
+ border-radius: 0;
243
+ }
244
+ .core-markdown-preview :deep(.hljs-comment),
245
+ .core-markdown-preview :deep(.hljs-quote) {
246
+ font-style: italic;
247
+ color: var(--admin-page-text-secondary);
248
+ }
249
+ .core-markdown-preview :deep(.hljs-keyword),
250
+ .core-markdown-preview :deep(.hljs-selector-tag),
251
+ .core-markdown-preview :deep(.hljs-built_in),
252
+ .core-markdown-preview :deep(.hljs-name) {
253
+ color: var(--el-color-primary);
254
+ }
255
+ .core-markdown-preview :deep(.hljs-string),
256
+ .core-markdown-preview :deep(.hljs-attr),
257
+ .core-markdown-preview :deep(.hljs-symbol),
258
+ .core-markdown-preview :deep(.hljs-bullet) {
259
+ color: var(--el-color-success);
260
+ }
261
+ .core-markdown-preview :deep(.hljs-number),
262
+ .core-markdown-preview :deep(.hljs-literal),
263
+ .core-markdown-preview :deep(.hljs-variable),
264
+ .core-markdown-preview :deep(.hljs-template-variable) {
265
+ color: var(--el-color-warning);
266
+ }
267
+ .core-markdown-preview :deep(.hljs-title),
268
+ .core-markdown-preview :deep(.hljs-section),
269
+ .core-markdown-preview :deep(.hljs-type) {
270
+ color: var(--el-color-danger);
271
+ }
272
+ .core-markdown-preview :deep(hr) {
273
+ height: 1px;
274
+ margin: 28px 0;
275
+ background: var(--admin-page-divider-strong);
276
+ border: 0;
277
+ }
278
+ .core-markdown-preview :deep(img) {
279
+ max-width: 100%;
280
+ height: auto;
281
+ border-radius: var(--admin-page-radius);
282
+ }
283
+
284
+ @media (width <= 720px) {
285
+ .core-markdown-preview :deep(h1) {
286
+ font-size: 26px;
287
+ }
288
+ .core-markdown-preview :deep(h2) {
289
+ font-size: 21px;
290
+ }
291
+ }
292
+ </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@liujitcn/kratos-admin-core",
3
3
  "private": false,
4
- "version": "0.0.1",
4
+ "version": "0.0.16",
5
5
  "type": "module",
6
6
  "description": "kratos-admin frontend runtime and base modules",
7
7
  "author": {
@@ -28,11 +28,14 @@
28
28
  "axios": "^1.7.2",
29
29
  "code-inspector-plugin": "^1.5.1",
30
30
  "dayjs": "^1.11.21",
31
+ "dompurify": "^3.4.5",
31
32
  "driver.js": "^1.3.1",
32
33
  "echarts": "^5.5.1",
33
34
  "echarts-liquidfill": "^3.1.0",
34
35
  "element-plus": "^2.7.6",
35
36
  "go-captcha-vue": "2.0.6",
37
+ "highlight.js": "^11.11.1",
38
+ "md-editor-v3": "^6.5.5",
36
39
  "md5": "^2.3.0",
37
40
  "mitt": "^3.0.1",
38
41
  "nprogress": "^0.2.0",
@@ -102,6 +105,10 @@
102
105
  "types": "./dist/package/declarations/src/components/Dict/DictLabel.vue.d.ts",
103
106
  "default": "./dist/package/src/components/Dict/DictLabel.vue"
104
107
  },
108
+ "./components/MarkdownPreview/index.vue": {
109
+ "types": "./dist/package/declarations/src/components/MarkdownPreview/index.vue.d.ts",
110
+ "default": "./dist/package/src/components/MarkdownPreview/index.vue"
111
+ },
105
112
  "./components/PasswordStrength/index.vue": {
106
113
  "types": "./dist/package/declarations/src/components/PasswordStrength/index.vue.d.ts",
107
114
  "default": "./dist/package/src/components/PasswordStrength/index.vue"
package/vite.config.ts CHANGED
@@ -87,12 +87,15 @@ export function defineAdminViteConfig(options: AdminViteConfigOptions = {}) {
87
87
  "@liujitcn/kratos-admin-core > dayjs/plugin/localeData.js",
88
88
  "@liujitcn/kratos-admin-core > dayjs/plugin/weekOfYear.js",
89
89
  "@liujitcn/kratos-admin-core > dayjs/plugin/weekYear.js",
90
+ "@liujitcn/kratos-admin-core > dompurify",
91
+ "@liujitcn/kratos-admin-core > highlight.js",
92
+ "@liujitcn/kratos-admin-core > md-editor-v3",
90
93
  "@liujitcn/kratos-admin-core > nprogress",
91
94
  "@liujitcn/kratos-admin-core > qs",
92
95
  ...(options.optimizeDependencies ?? [])
93
96
  ],
94
97
  noDiscovery: true,
95
- exclude: ["@liujitcn/kratos-admin-core", ...(options.modulePackages ?? [])]
98
+ exclude: ["vue", "@liujitcn/kratos-admin-core", ...(options.modulePackages ?? [])]
96
99
  },
97
100
  server: {
98
101
  host: "0.0.0.0",