|
|
@@ -0,0 +1,82 @@
|
|
|
+import { marked, Renderer } from "marked";
|
|
|
+import DOMPurify from "dompurify";
|
|
|
+import hljs from "highlight.js/lib/core";
|
|
|
+import javascript from "highlight.js/lib/languages/javascript";
|
|
|
+import typescript from "highlight.js/lib/languages/typescript";
|
|
|
+import python from "highlight.js/lib/languages/python";
|
|
|
+import bash from "highlight.js/lib/languages/bash";
|
|
|
+import json from "highlight.js/lib/languages/json";
|
|
|
+import sql from "highlight.js/lib/languages/sql";
|
|
|
+import xml from "highlight.js/lib/languages/xml";
|
|
|
+import css from "highlight.js/lib/languages/css";
|
|
|
+import yaml from "highlight.js/lib/languages/yaml";
|
|
|
+import markdown from "highlight.js/lib/languages/markdown";
|
|
|
+import java from "highlight.js/lib/languages/java";
|
|
|
+import csharp from "highlight.js/lib/languages/csharp";
|
|
|
+import php from "highlight.js/lib/languages/php";
|
|
|
+import plaintext from "highlight.js/lib/languages/plaintext";
|
|
|
+
|
|
|
+hljs.registerLanguage("javascript", javascript);
|
|
|
+hljs.registerLanguage("typescript", typescript);
|
|
|
+hljs.registerLanguage("python", python);
|
|
|
+hljs.registerLanguage("bash", bash);
|
|
|
+hljs.registerLanguage("json", json);
|
|
|
+hljs.registerLanguage("sql", sql);
|
|
|
+hljs.registerLanguage("xml", xml);
|
|
|
+hljs.registerLanguage("css", css);
|
|
|
+hljs.registerLanguage("yaml", yaml);
|
|
|
+hljs.registerLanguage("markdown", markdown);
|
|
|
+hljs.registerLanguage("java", java);
|
|
|
+hljs.registerLanguage("csharp", csharp);
|
|
|
+hljs.registerLanguage("php", php);
|
|
|
+hljs.registerLanguage("plaintext", plaintext);
|
|
|
+
|
|
|
+const renderer = new Renderer();
|
|
|
+
|
|
|
+const CODE_BLOCK_STORE_MAX = 500;
|
|
|
+let codeBlockCounter = 0;
|
|
|
+const codeBlockStore = new Map();
|
|
|
+
|
|
|
+function storeCodeBlock(text) {
|
|
|
+ const id = String(codeBlockCounter++);
|
|
|
+ codeBlockStore.set(id, text);
|
|
|
+ if (codeBlockStore.size > CODE_BLOCK_STORE_MAX) {
|
|
|
+ codeBlockStore.delete(codeBlockStore.keys().next().value);
|
|
|
+ }
|
|
|
+ return id;
|
|
|
+}
|
|
|
+
|
|
|
+export function getStoredCode(id) {
|
|
|
+ return codeBlockStore.get(id) ?? "";
|
|
|
+}
|
|
|
+
|
|
|
+renderer.code = ({ text, lang }) => {
|
|
|
+ const language = lang && hljs.getLanguage(lang) ? lang : "plaintext";
|
|
|
+ const highlighted = hljs.highlight(text, { language }).value;
|
|
|
+ const id = storeCodeBlock(text);
|
|
|
+ return `<div class="code-block-wrapper">
|
|
|
+ <div class="code-block-header">
|
|
|
+ <span class="code-lang">${language}</span>
|
|
|
+ <button class="code-copy-btn" data-code-id="${id}" aria-label="Copiar código">
|
|
|
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
|
+ Copiar
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <pre><code class="hljs language-${language}">${highlighted}</code></pre>
|
|
|
+ </div>`;
|
|
|
+};
|
|
|
+
|
|
|
+marked.use({
|
|
|
+ renderer,
|
|
|
+ breaks: true,
|
|
|
+ gfm: true,
|
|
|
+});
|
|
|
+
|
|
|
+export function renderMarkdown(content) {
|
|
|
+ if (!content) return "";
|
|
|
+ const html = marked.parse(content);
|
|
|
+ return DOMPurify.sanitize(html, {
|
|
|
+ ADD_ATTR: ["data-code-id"],
|
|
|
+ ADD_TAGS: ["button"],
|
|
|
+ });
|
|
|
+}
|