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
This commit is contained in:
PrzZiomek2 2026-02-08 09:41:30 +01:00
parent 7dfaf103b8
commit a32944b809
4 changed files with 98 additions and 7 deletions

28
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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;
}

View File

@ -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<typeof component_arguments> {
getArguments() {
return component_arguments;
}
async toHTML({
args: { codeWithLanguage },
classes,
}: ComponentToHTMLArgs<typeof component_arguments>): Promise<string> {
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 (
<div class={["code-snippet", ...classes]} data-controller="code-snippet">
<h2>CodeSnippet</h2>
{languageNotFoundMessage ? (
<p class="code-snippet__language-error">{languageNotFoundMessage}</p>
) : (
<>
<pre>
<code data-code-snippet-target="code">{highlightedCode}</code>
</pre>
<div class="code-snippet__language">
<span>{codeWithLanguage.language}</span>
<button data-action="code-snippet#copyCode">Copy</button>
</div>
</>
)}
</div>
);
}
}