diff --git a/01_content/package-lock.json b/01_content/package-lock.json index 440d28e..82d4e23 100644 --- a/01_content/package-lock.json +++ b/01_content/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "devDependencies": { "esbuild": "^0.25.0", + "highlight.js": "^11.12.0", "markdown-it": "^15.0.0", "xterm": "^5.3.0" }, @@ -544,6 +545,16 @@ "@esbuild/win32-x64": "0.25.12" } }, + "node_modules/highlight.js": { + "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.12.0.tgz", + "integrity": "sha512-nbfWpyRMcMrPMmDwJB+dhX/eiaPKtc2RB+0QZskqJ3WjRA/FDS0e9hZrx8EC/lbEv8gXy98FcDbNa/dspAaJMg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/linkify-it": { "version": "6.1.0", "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-6.1.0.tgz", diff --git a/01_content/package.json b/01_content/package.json index 17a177d..3032b6f 100644 --- a/01_content/package.json +++ b/01_content/package.json @@ -52,6 +52,7 @@ }, "devDependencies": { "esbuild": "^0.25.0", + "highlight.js": "^11.12.0", "markdown-it": "^15.0.0", "xterm": "^5.3.0" } diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index 4be6edd..8fc2864 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -2,6 +2,16 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { Terminal } from 'xterm' import 'xterm/css/xterm.css' import MarkdownIt from 'markdown-it' +import hljs from 'highlight.js/lib/core' +import hljsTypescript from 'highlight.js/lib/languages/typescript' +import hljsJavascript from 'highlight.js/lib/languages/javascript' +import hljsCss from 'highlight.js/lib/languages/css' +import hljsJson from 'highlight.js/lib/languages/json' + +hljs.registerLanguage('typescript', hljsTypescript) +hljs.registerLanguage('javascript', hljsJavascript) +hljs.registerLanguage('css', hljsCss) +hljs.registerLanguage('json', hljsJson) /** * dsh-worktable 乐高式工作区 M1:通用分栏引擎(PRD §13)。 @@ -1121,7 +1131,23 @@ function FileViewer(props: { path: string }) { return } -/** MD/TXT 文本预览(fetch 原文 → MD 渲染或
 等宽展示);MD 支持编辑/预览自由切换并可保存回磁盘 */
+/** 代码文件语言映射(预览语法着色) */
+const CODE_LANGS: Record = { ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript', css: 'css', json: 'json' }
+const CODE_EXTS = /[.](tsx|ts|jsx|js|css|json)$/i
+
+function escapeHtml(s: string): string {
+  return s.replace(/&/g, '&').replace(//g, '>')
+}
+
+function codeHtml(text: string, ext: string): string {
+  const lang = CODE_LANGS[ext] ?? ''
+  if (lang) {
+    try { return hljs.highlight(text, { language: lang }).value } catch { return escapeHtml(text) }
+  }
+  return escapeHtml(text)
+}
+
+/** 文本预览(fetch 原文 → MD 渲染 / 代码高亮 / 
 等宽展示);全部文本类型支持编辑/预览切换并可保存回磁盘 */
 function TextViewer(props: { path: string; fileUrl: string; isMd: boolean }) {
   const [text, setText] = useState(null)
   const [error, setError] = useState('')
@@ -1167,20 +1193,22 @@ function TextViewer(props: { path: string; fileUrl: string; isMd: boolean }) {
   if (text == null) {
     return 
{T('file.loading')}
} - if (props.isMd) { - return ( - <> -
- - - {mode === 'edit' && ( - - )} - {saveFail && {T('file.saveFail')}} -
- {mode === 'edit' - ?