From a32944b809de33a767c77c329947f3c7f611936e Mon Sep 17 00:00:00 2001 From: PrzZiomek2 Date: Sun, 8 Feb 2026 09:41:30 +0100 Subject: [PATCH] Create code snippet jdd component Summary: Ref T2994 Reviewers: kuba-orlik Reviewed By: kuba-orlik Maniphest Tasks: T2994 Differential Revision: https://hub.sealcode.org/D1667 --- package-lock.json | 28 +++++++--- package.json | 1 + .../code-snippet/code-snippet.css | 22 ++++++++ .../code-snippet/code-snippet.jdd.tsx | 54 +++++++++++++++++++ 4 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/back/jdd-components/code-snippet/code-snippet.css create mode 100644 src/back/jdd-components/code-snippet/code-snippet.jdd.tsx diff --git a/package-lock.json b/package-lock.json index d4ee1e4..6da6b55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "escape-goat": "^4.0.0", "get-port": "^7.0.0", "glob": "^11.0.3", + "highlight.js": "^11.11.1", "js-convert-case": "^4.2.0", "koa-mount": "^4.2.0", "koa-qs": "^3.0.0", @@ -6887,11 +6888,11 @@ } }, "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", "engines": { - "node": "*" + "node": ">=12.0.0" } }, "node_modules/hookable": { @@ -14214,6 +14215,14 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/typedoc/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, "node_modules/typedoc/node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -20126,9 +20135,9 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==" }, "hookable": { "version": "5.5.3", @@ -25539,6 +25548,11 @@ "universalify": "^0.1.0" } }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", diff --git a/package.json b/package.json index 25b8e2b..c294756 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "escape-goat": "^4.0.0", "get-port": "^7.0.0", "glob": "^11.0.3", + "highlight.js": "^11.11.1", "js-convert-case": "^4.2.0", "koa-mount": "^4.2.0", "koa-qs": "^3.0.0", diff --git a/src/back/jdd-components/code-snippet/code-snippet.css b/src/back/jdd-components/code-snippet/code-snippet.css new file mode 100644 index 0000000..e1e0628 --- /dev/null +++ b/src/back/jdd-components/code-snippet/code-snippet.css @@ -0,0 +1,22 @@ +.code-snippet { + display: flex; + flex-direction: column; + padding: 0 16px 16px 16px; +} + +.code-snippet pre { + margin: 0; +} + +.code-snippet__language-error { + color: red; + font-size: 16px; +} + +.code-snippet__language { + display: flex; + justify-content: flex-start; + margin: 0; + margin-top: 20px; + gap: 8px; +} \ No newline at end of file diff --git a/src/back/jdd-components/code-snippet/code-snippet.jdd.tsx b/src/back/jdd-components/code-snippet/code-snippet.jdd.tsx new file mode 100644 index 0000000..734226c --- /dev/null +++ b/src/back/jdd-components/code-snippet/code-snippet.jdd.tsx @@ -0,0 +1,54 @@ +import { TempstreamJSX } from "tempstream"; +import type { ComponentToHTMLArgs } from "@sealcode/jdd"; +import { Component, ComponentArguments } from "@sealcode/jdd"; +import hljs from "highlight.js"; + +const component_arguments = { + codeWithLanguage: new ComponentArguments.CodeWithCustomLanguage(), +} as const; + +export class CodeSnippet extends Component { + getArguments() { + return component_arguments; + } + + async toHTML({ + args: { codeWithLanguage }, + classes, + }: ComponentToHTMLArgs): Promise { + let highlightedCode: string; + let languageNotFoundMessage: string = ""; + + const language = codeWithLanguage.language?.toLowerCase() || "plaintext"; + + if (hljs.getLanguage(language)) { + highlightedCode = hljs.highlight(codeWithLanguage.code, { + language, + }).value; + } else { + highlightedCode = hljs.highlight(codeWithLanguage.code, { + language: "plaintext", + }).value; + languageNotFoundMessage = `Language "${language}" not found`; + } + + return ( +
+

CodeSnippet

+ {languageNotFoundMessage ? ( +

{languageNotFoundMessage}

+ ) : ( + <> +
+							{highlightedCode}
+						
+
+ {codeWithLanguage.language} + +
+ + )} +
+ ); + } +}