@huyooo/ai-chat-shared 0.2.3

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,505 @@
1
+ /**
2
+ * Markdown 渲染样式
3
+ * 参考 VitePress 和 GitHub 风格,优化显示效果
4
+ * 统一的样式,供 React 和 Vue 版本使用
5
+ */
6
+
7
+ /* Markdown 容器 - VitePress 风格 */
8
+ .markdown-content {
9
+ font-size: 15px;
10
+ line-height: 1.75;
11
+ color: var(--chat-text, #e4e4e7);
12
+ word-break: break-word;
13
+ overflow-wrap: break-word;
14
+ letter-spacing: 0.01em;
15
+ }
16
+
17
+ /* 段落 - 优化间距 */
18
+ .markdown-content p {
19
+ margin: 1em 0;
20
+ line-height: 1.75;
21
+ }
22
+
23
+ .markdown-content p:first-child {
24
+ margin-top: 0;
25
+ }
26
+
27
+ .markdown-content p:last-child {
28
+ margin-bottom: 0;
29
+ }
30
+
31
+ /* 标题 - 统一的间距规则 */
32
+ .markdown-content h1,
33
+ .markdown-content h2,
34
+ .markdown-content h3,
35
+ .markdown-content h4,
36
+ .markdown-content h5,
37
+ .markdown-content h6 {
38
+ margin-top: 1em;
39
+ margin-bottom: 0.5em;
40
+ font-weight: 600;
41
+ line-height: 1.4;
42
+ color: var(--chat-text, #e4e4e7);
43
+ letter-spacing: -0.01em;
44
+ }
45
+
46
+ /* 第一个标题不需要上边距 */
47
+ .markdown-content h1:first-child,
48
+ .markdown-content h2:first-child,
49
+ .markdown-content h3:first-child,
50
+ .markdown-content h4:first-child,
51
+ .markdown-content h5:first-child,
52
+ .markdown-content h6:first-child {
53
+ margin-top: 0;
54
+ }
55
+
56
+ /* 标题字体大小 */
57
+ .markdown-content h1 {
58
+ font-size: 2em;
59
+ font-weight: 700;
60
+ }
61
+
62
+ .markdown-content h2 {
63
+ font-size: 1.5em;
64
+ }
65
+
66
+ .markdown-content h3 {
67
+ font-size: 1.25em;
68
+ }
69
+
70
+ .markdown-content h4 {
71
+ font-size: 1.1em;
72
+ }
73
+
74
+ .markdown-content h5 {
75
+ font-size: 1em;
76
+ }
77
+
78
+ .markdown-content h6 {
79
+ font-size: 0.9em;
80
+ color: var(--chat-text-muted, #a1a1aa);
81
+ }
82
+
83
+ /* 列表 - GitHub 风格,更好的缩进 */
84
+ .markdown-content ul,
85
+ .markdown-content ol {
86
+ margin: 1em 0;
87
+ padding-left: 2em;
88
+ line-height: 1.75;
89
+ }
90
+
91
+ .markdown-content li {
92
+ margin: 0.4em 0;
93
+ line-height: 1.75;
94
+ }
95
+
96
+ .markdown-content li > p {
97
+ margin: 0.4em 0;
98
+ }
99
+
100
+ .markdown-content ul {
101
+ list-style-type: disc;
102
+ }
103
+
104
+ .markdown-content ol {
105
+ list-style-type: decimal;
106
+ }
107
+
108
+ .markdown-content ul ul,
109
+ .markdown-content ol ol,
110
+ .markdown-content ul ol,
111
+ .markdown-content ol ul {
112
+ margin: 0.3em 0;
113
+ }
114
+
115
+ /* 嵌套列表样式 */
116
+ .markdown-content ul ul {
117
+ list-style-type: circle;
118
+ }
119
+
120
+ .markdown-content ul ul ul {
121
+ list-style-type: square;
122
+ }
123
+
124
+ /* 代码 - 更现代的样式 */
125
+ .markdown-content code {
126
+ background: var(--chat-muted, #2a2a2a);
127
+ padding: 0.2em 0.4em;
128
+ border-radius: 4px;
129
+ font-family: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace;
130
+ font-size: 0.9em;
131
+ color: var(--chat-code-text, #f4f4f5);
132
+ font-weight: 500;
133
+ }
134
+
135
+ .markdown-content pre {
136
+ background: transparent;
137
+ border: 1px solid var(--chat-border, rgba(255, 255, 255, 0.1));
138
+ border-radius: 8px;
139
+ padding: 16px;
140
+ overflow-x: auto;
141
+ margin: 1em 0;
142
+ font-family: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace;
143
+ font-size: 14px;
144
+ line-height: 1.6;
145
+ position: relative;
146
+ }
147
+
148
+ /* 统一滚动条样式 */
149
+ .markdown-content pre::-webkit-scrollbar {
150
+ width: 6px;
151
+ height: 6px;
152
+ }
153
+
154
+ .markdown-content pre::-webkit-scrollbar-track {
155
+ background: transparent;
156
+ }
157
+
158
+ .markdown-content pre::-webkit-scrollbar-thumb {
159
+ background: var(--chat-scrollbar, rgba(255, 255, 255, 0.2));
160
+ border-radius: 3px;
161
+ }
162
+
163
+ .markdown-content pre::-webkit-scrollbar-thumb:hover {
164
+ background: var(--chat-scrollbar-hover, rgba(255, 255, 255, 0.3));
165
+ }
166
+
167
+ .markdown-content pre code {
168
+ background: transparent;
169
+ padding: 0;
170
+ border-radius: 0;
171
+ font-size: inherit;
172
+ color: inherit;
173
+ border: none;
174
+ font-weight: normal;
175
+ }
176
+
177
+ .markdown-code-block {
178
+ background: transparent;
179
+ border: 1px solid var(--chat-border, rgba(255, 255, 255, 0.1));
180
+ border-radius: 8px;
181
+ padding: 16px;
182
+ overflow-x: auto;
183
+ margin: 1em 0;
184
+ font-family: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace;
185
+ font-size: 14px;
186
+ line-height: 1.6;
187
+ position: relative;
188
+ }
189
+
190
+ /* 统一滚动条样式 */
191
+ .markdown-code-block::-webkit-scrollbar {
192
+ width: 6px;
193
+ height: 6px;
194
+ }
195
+
196
+ .markdown-code-block::-webkit-scrollbar-track {
197
+ background: transparent;
198
+ }
199
+
200
+ .markdown-code-block::-webkit-scrollbar-thumb {
201
+ background: var(--chat-scrollbar, rgba(255, 255, 255, 0.2));
202
+ border-radius: 3px;
203
+ }
204
+
205
+ .markdown-code-block::-webkit-scrollbar-thumb:hover {
206
+ background: var(--chat-scrollbar-hover, rgba(255, 255, 255, 0.3));
207
+ }
208
+
209
+ .markdown-code-block code {
210
+ background: transparent;
211
+ padding: 0;
212
+ border-radius: 0;
213
+ font-size: inherit;
214
+ color: var(--chat-code-text, #f4f4f5);
215
+ border: none;
216
+ font-weight: normal;
217
+ }
218
+
219
+ /* 代码高亮样式 - One Dark Pro 主题 */
220
+ .markdown-code-block .hljs-keyword {
221
+ color: #c678dd;
222
+ }
223
+ .markdown-code-block .hljs-string {
224
+ color: #98c379;
225
+ }
226
+ .markdown-code-block .hljs-number {
227
+ color: #d19a66;
228
+ }
229
+ .markdown-code-block .hljs-comment {
230
+ color: #5c6370;
231
+ font-style: italic;
232
+ }
233
+ .markdown-code-block .hljs-function {
234
+ color: #61afef;
235
+ }
236
+ .markdown-code-block .hljs-class {
237
+ color: #e5c07b;
238
+ }
239
+ .markdown-code-block .hljs-variable {
240
+ color: #e06c75;
241
+ }
242
+ .markdown-code-block .hljs-operator {
243
+ color: #56b6c2;
244
+ }
245
+ .markdown-code-block .hljs-punctuation {
246
+ color: #abb2bf;
247
+ }
248
+ .markdown-code-block .hljs-property {
249
+ color: #e06c75;
250
+ }
251
+ .markdown-code-block .hljs-attr {
252
+ color: #d19a66;
253
+ }
254
+ .markdown-code-block .hljs-built_in {
255
+ color: #e5c07b;
256
+ }
257
+ .markdown-code-block .hljs-title {
258
+ color: #61afef;
259
+ }
260
+ .markdown-code-block .hljs-params {
261
+ color: #abb2bf;
262
+ }
263
+ .markdown-code-block .hljs-literal {
264
+ color: #56b6c2;
265
+ }
266
+ .markdown-code-block .hljs-type {
267
+ color: #e5c07b;
268
+ }
269
+
270
+ /* 引用 - VitePress 风格,更明显的视觉区分 */
271
+ .markdown-content blockquote {
272
+ margin: 1em 0;
273
+ padding: 0.5em 1em;
274
+ border-left: 4px solid var(--chat-primary, #3b82f6);
275
+ background: var(--chat-muted, #2a2a2a);
276
+ border-radius: 0 4px 4px 0;
277
+ color: var(--chat-text, #e4e4e7);
278
+ }
279
+
280
+ .markdown-content blockquote p {
281
+ margin: 0.5em 0;
282
+ }
283
+
284
+ .markdown-content blockquote p:first-child {
285
+ margin-top: 0;
286
+ }
287
+
288
+ .markdown-content blockquote p:last-child {
289
+ margin-bottom: 0;
290
+ }
291
+
292
+ /* 表格容器 - 支持横向滚动 */
293
+ .markdown-content .markdown-table-wrapper {
294
+ width: 100%;
295
+ overflow-x: auto;
296
+ margin: 1em 0;
297
+ border-radius: 8px;
298
+ }
299
+
300
+ /* 统一滚动条样式 */
301
+ .markdown-content .markdown-table-wrapper::-webkit-scrollbar {
302
+ width: 6px;
303
+ height: 6px;
304
+ }
305
+
306
+ .markdown-content .markdown-table-wrapper::-webkit-scrollbar-track {
307
+ background: transparent;
308
+ }
309
+
310
+ .markdown-content .markdown-table-wrapper::-webkit-scrollbar-thumb {
311
+ background: var(--chat-scrollbar, rgba(255, 255, 255, 0.2));
312
+ border-radius: 3px;
313
+ }
314
+
315
+ .markdown-content .markdown-table-wrapper::-webkit-scrollbar-thumb:hover {
316
+ background: var(--chat-scrollbar-hover, rgba(255, 255, 255, 0.3));
317
+ }
318
+
319
+ /* 表格 */
320
+ .markdown-table {
321
+ width: 100%;
322
+ border-collapse: separate;
323
+ border-spacing: 0;
324
+ margin: 0;
325
+ font-size: 0.95em;
326
+ border: 1px solid var(--chat-border, #333);
327
+ border-radius: 8px;
328
+ overflow: hidden;
329
+ }
330
+
331
+ /* 表头样式 */
332
+ .markdown-table thead {
333
+ display: table-header-group;
334
+ }
335
+
336
+ .markdown-table th {
337
+ padding: 0.875em 1em;
338
+ text-align: left;
339
+ font-weight: 600;
340
+ color: var(--chat-text, #ccc);
341
+ border-bottom: 1px solid var(--chat-border, #333);
342
+ border-right: 1px solid var(--chat-border, #333);
343
+ border-top: none;
344
+ background: transparent;
345
+ }
346
+
347
+ .markdown-table th:last-child {
348
+ border-right: none;
349
+ }
350
+
351
+ /* 表格内容样式 */
352
+ .markdown-table tbody {
353
+ display: table-row-group;
354
+ }
355
+
356
+ .markdown-table td {
357
+ padding: 0.875em 1em;
358
+ text-align: left;
359
+ color: var(--chat-text, #ccc);
360
+ border-bottom: 1px solid var(--chat-border, #333);
361
+ border-right: 1px solid var(--chat-border, #333);
362
+ border-top: none;
363
+ vertical-align: top;
364
+ }
365
+
366
+ .markdown-table td:last-child {
367
+ border-right: none;
368
+ }
369
+
370
+ .markdown-table tbody tr:last-child td {
371
+ border-bottom: none;
372
+ }
373
+
374
+ /* 表格行悬停效果(可选,保持简洁) */
375
+ .markdown-table tbody tr {
376
+ transition: opacity 0.15s ease;
377
+ }
378
+
379
+ /* 表格中的图标和特殊内容 */
380
+ .markdown-table td img,
381
+ .markdown-table td svg,
382
+ .markdown-table th img,
383
+ .markdown-table th svg {
384
+ vertical-align: middle;
385
+ margin-right: 0.5em;
386
+ display: inline-block;
387
+ }
388
+
389
+ /* 表格中的进度条、星级等 */
390
+ .markdown-table td .progress,
391
+ .markdown-table td .stars {
392
+ display: inline-flex;
393
+ align-items: center;
394
+ gap: 0.25em;
395
+ }
396
+
397
+ /* 表格中的代码块 */
398
+ .markdown-table td code,
399
+ .markdown-table th code {
400
+ font-size: 0.85em;
401
+ padding: 0.15em 0.35em;
402
+ }
403
+
404
+ /* 表格响应式 */
405
+ @media (max-width: 768px) {
406
+ .markdown-table {
407
+ font-size: 13px;
408
+ border-radius: 6px;
409
+ }
410
+
411
+ .markdown-table th,
412
+ .markdown-table td {
413
+ padding: 0.6em 0.8em;
414
+ }
415
+ }
416
+
417
+ /* 链接 - VitePress 风格 */
418
+ .markdown-link {
419
+ color: var(--chat-link, #60a5fa);
420
+ text-decoration: none;
421
+ border-bottom: 1px solid transparent;
422
+ transition: all 0.2s ease;
423
+ font-weight: 500;
424
+ }
425
+
426
+ .markdown-link:hover {
427
+ color: var(--chat-link, #3b82f6);
428
+ border-bottom-color: var(--chat-link, #3b82f6);
429
+ }
430
+
431
+ /* 图片 - 优化显示 */
432
+ .markdown-content img {
433
+ max-width: 100%;
434
+ height: auto;
435
+ border-radius: 6px;
436
+ margin: 1em 0;
437
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
438
+ }
439
+
440
+ /* 水平线 - 更优雅 */
441
+ .markdown-content hr {
442
+ border: none;
443
+ border-top: 1px solid var(--chat-border, rgba(255, 255, 255, 0.1));
444
+ margin: 1em 0;
445
+ height: 0;
446
+ }
447
+
448
+ /* 强调 */
449
+ .markdown-content strong {
450
+ font-weight: 600;
451
+ color: var(--chat-text, #e4e4e7);
452
+ }
453
+
454
+ .markdown-content em {
455
+ font-style: italic;
456
+ color: var(--chat-text, #e4e4e7);
457
+ }
458
+
459
+ .markdown-content u {
460
+ text-decoration: underline;
461
+ text-decoration-color: var(--chat-text-muted, #a1a1aa);
462
+ text-underline-offset: 0.15em;
463
+ }
464
+
465
+ .markdown-content s {
466
+ text-decoration: line-through;
467
+ opacity: 0.7;
468
+ color: var(--chat-text-muted, #a1a1aa);
469
+ }
470
+
471
+ /* 任务列表 - checkbox 显示为文本 */
472
+ .markdown-content .markdown-task-item {
473
+ list-style-type: disc;
474
+ }
475
+
476
+ .markdown-content .markdown-task-checkbox {
477
+ font-size: 1em;
478
+ color: var(--chat-text, #e4e4e7);
479
+ user-select: none;
480
+ }
481
+
482
+ /* 定义列表 */
483
+ .markdown-content dl {
484
+ margin: 1em 0;
485
+ }
486
+
487
+ .markdown-content dt {
488
+ font-weight: 600;
489
+ margin-top: 0.8em;
490
+ color: var(--chat-text, #e4e4e7);
491
+ }
492
+
493
+ .markdown-content dd {
494
+ margin: 0.4em 0 0.8em 2em;
495
+ color: var(--chat-text-muted, #a1a1aa);
496
+ }
497
+
498
+ /* 代码块中的行号(如果使用) */
499
+ .markdown-code-block .line-numbers {
500
+ padding-right: 1em;
501
+ border-right: 1px solid var(--chat-border, rgba(255, 255, 255, 0.1));
502
+ margin-right: 1em;
503
+ user-select: none;
504
+ opacity: 0.5;
505
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@huyooo/ai-chat-shared",
3
+ "version": "0.2.3",
4
+ "description": "AI Chat 共享模块 - 内容解析器、类型定义",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "development": "./src/index.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./styles": "./dist/styles.css"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "dev": "tsup --watch"
25
+ },
26
+ "dependencies": {
27
+ "highlight.js": "^11.11.1",
28
+ "marked": "^12.0.0",
29
+ "dompurify": "^3.2.0"
30
+ },
31
+ "devDependencies": {
32
+ "tsup": "^8.0.1",
33
+ "typescript": "^5.3.3",
34
+ "@types/dompurify": "^3.0.5"
35
+ },
36
+ "peerDependencies": {},
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * 代码高亮工具
3
+ * 使用 highlight.js 提供代码语法高亮
4
+ */
5
+
6
+ import hljs from 'highlight.js'
7
+
8
+ /** 支持的语言别名映射 */
9
+ const LANGUAGE_ALIASES: Record<string, string> = {
10
+ js: 'javascript',
11
+ ts: 'typescript',
12
+ tsx: 'typescript',
13
+ jsx: 'javascript',
14
+ py: 'python',
15
+ rb: 'ruby',
16
+ sh: 'bash',
17
+ shell: 'bash',
18
+ yml: 'yaml',
19
+ md: 'markdown',
20
+ }
21
+
22
+ /**
23
+ * 高亮代码
24
+ * @param code 代码内容
25
+ * @param language 语言标识
26
+ * @returns 高亮后的 HTML
27
+ */
28
+ export function highlightCode(code: string, language?: string): string {
29
+ if (!language) {
30
+ // 无语言指定,尝试自动检测
31
+ try {
32
+ const result = hljs.highlightAuto(code)
33
+ return result.value
34
+ } catch {
35
+ return escapeHtml(code)
36
+ }
37
+ }
38
+
39
+ // 处理语言别名
40
+ const normalizedLang = LANGUAGE_ALIASES[language.toLowerCase()] || language.toLowerCase()
41
+
42
+ try {
43
+ if (hljs.getLanguage(normalizedLang)) {
44
+ return hljs.highlight(code, { language: normalizedLang }).value
45
+ }
46
+ // 语言不支持,返回转义后的原文
47
+ return escapeHtml(code)
48
+ } catch {
49
+ return escapeHtml(code)
50
+ }
51
+ }
52
+
53
+ /** HTML 转义 */
54
+ function escapeHtml(text: string): string {
55
+ return text
56
+ .replace(/&/g, '&amp;')
57
+ .replace(/</g, '&lt;')
58
+ .replace(/>/g, '&gt;')
59
+ .replace(/"/g, '&quot;')
60
+ .replace(/'/g, '&#039;')
61
+ }
62
+
63
+ /**
64
+ * 获取语言显示名称
65
+ * @param language 语言标识
66
+ * @returns 显示名称
67
+ */
68
+ export function getLanguageDisplayName(language?: string): string {
69
+ if (!language) return 'Plain Text'
70
+
71
+ const normalizedLang = LANGUAGE_ALIASES[language.toLowerCase()] || language.toLowerCase()
72
+ const langDef = hljs.getLanguage(normalizedLang)
73
+
74
+ if (langDef) {
75
+ // 首字母大写
76
+ return normalizedLang.charAt(0).toUpperCase() + normalizedLang.slice(1)
77
+ }
78
+
79
+ return language
80
+ }
package/src/index.ts ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @huyooo/ai-chat-shared
3
+ *
4
+ * AI Chat 共享模块
5
+ * - 内容解析器
6
+ * - 代码高亮
7
+ * - 共享类型定义
8
+ */
9
+
10
+ // 类型导出
11
+ export type {
12
+ // 内容块类型
13
+ ContentBlockType,
14
+ ContentBlockBase,
15
+ TextBlock,
16
+ CodeBlock,
17
+ ContentBlock,
18
+ // 工具渲染器类型
19
+ ToolRendererProps,
20
+ // 内置数据类型
21
+ WeatherData,
22
+ WeatherForecastItem,
23
+ SearchResultItem,
24
+ CodeExecutionResult,
25
+ FileOperationResult,
26
+ } from './types'
27
+
28
+ // 解析器导出
29
+ export {
30
+ parseContent,
31
+ createStreamParseState,
32
+ parseContentStream,
33
+ finishStreamParse,
34
+ } from './parser'
35
+ export type { StreamParseState } from './parser'
36
+
37
+ // 高亮工具导出
38
+ export {
39
+ highlightCode,
40
+ getLanguageDisplayName,
41
+ } from './highlighter'
42
+
43
+ // Markdown 渲染工具导出
44
+ export {
45
+ renderMarkdown,
46
+ } from './markdown'