diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ff740..c0a6c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog - project.linkedcorp.net +## [2.9.1] - 2026-10-07 +### Added +- Los bloques de código dentro de un .md visto en Documentos ahora tienen resaltado de sintaxis + a color (estilo Visual Studio/VSCode, claro y oscuro según el tema de la app) — js/ts, bash, + json, python, sql, yaml, html/xml, css, ini, dockerfile, markdown. + ## [2.9.0] - 2026-10-07 ### Added - Documentos (adjuntos de proyectos/actividades): los archivos de texto plano (.txt) y Markdown diff --git a/VERSION b/VERSION index c8e38b6..dedcc7d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.9.0 +2.9.1 diff --git a/backend/package.json b/backend/package.json index 5a52ca0..2eaf13e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "project-linkedcorp-backend", - "version": "2.9.0", + "version": "2.9.1", "private": true, "type": "module", "main": "src/server.js", diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8d7b0d5..dcc6a72 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,16 +1,18 @@ { "name": "project-linkedcorp-frontend", - "version": "2.8.13", + "version": "2.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "project-linkedcorp-frontend", - "version": "2.8.13", + "version": "2.9.0", "dependencies": { "dompurify": "^3.4.16", + "highlight.js": "^11.12.0", "lucide-react": "^0.462.0", "marked": "^18.1.0", + "marked-highlight": "^2.2.4", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.18.3", @@ -4392,6 +4394,15 @@ "node": ">= 0.4" } }, + "node_modules/highlight.js": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.12.0.tgz", + "integrity": "sha512-nbfWpyRMcMrPMmDwJB+dhX/eiaPKtc2RB+0QZskqJ3WjRA/FDS0e9hZrx8EC/lbEv8gXy98FcDbNa/dspAaJMg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5069,6 +5080,15 @@ "node": ">= 20" } }, + "node_modules/marked-highlight": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/marked-highlight/-/marked-highlight-2.2.4.tgz", + "integrity": "sha512-PZxisNMJDduSjc0q6uvjsnqqHCXc9s0eyzxDO9sB1eNGJnd/H1/Fu+z6g/liC1dfJdFW4SftMwMlLvsBhUPrqQ==", + "license": "MIT", + "peerDependencies": { + "marked": ">=4 <19" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index e698506..178d38f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "project-linkedcorp-frontend", "private": true, - "version": "2.9.0", + "version": "2.9.1", "type": "module", "scripts": { "dev": "vite", @@ -10,8 +10,10 @@ }, "dependencies": { "dompurify": "^3.4.16", + "highlight.js": "^11.12.0", "lucide-react": "^0.462.0", "marked": "^18.1.0", + "marked-highlight": "^2.2.4", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.18.3", diff --git a/frontend/src/components/AttachmentsPanel.jsx b/frontend/src/components/AttachmentsPanel.jsx index 1efd7e9..99f6b6c 100644 --- a/frontend/src/components/AttachmentsPanel.jsx +++ b/frontend/src/components/AttachmentsPanel.jsx @@ -6,11 +6,15 @@ import { listAttachments, uploadAttachment, deleteAttachment, downloadAttachment import { renderMarkdown } from '../utils/renderMarkdown.js'; import { Button } from './Button.jsx'; import { DetailPopup } from './DetailPopup.jsx'; +// Tema de colores de bloques de codigo al estilo Visual Studio/VSCode (claro y oscuro), +// inyectado solo mientras se ve un .md -- ?inline evita que Vite lo aplique global siempre. +import hljsLight from 'highlight.js/styles/vs.css?inline'; +import hljsDark from 'highlight.js/styles/vs2015.css?inline'; const VIEWABLE_MIME = new Set(['text/plain', 'text/markdown']); export function AttachmentsPanel({ entityType, entityId }) { - const { t, openDialog } = useUi(); + const { t, openDialog, theme } = useUi(); const runAction = useAction(); const { data: files, reload } = useAsync(() => listAttachments(entityType, entityId), [entityType, entityId]); const inputRef = useRef(null); @@ -83,8 +87,11 @@ export function AttachmentsPanel({ entityType, entityId }) { {viewLoading ? (
{t('common_loading')}
) : viewing?.mime_type === 'text/markdown' ? ( - // eslint-disable-next-line react/no-danger -- sanitizado con DOMPurify en renderMarkdown() -
+ <> + + {/* eslint-disable-next-line react/no-danger -- sanitizado con DOMPurify en renderMarkdown() */} +
+ ) : (
{viewContent}
)} diff --git a/frontend/src/utils/renderMarkdown.js b/frontend/src/utils/renderMarkdown.js index f5e1d9c..8372831 100644 --- a/frontend/src/utils/renderMarkdown.js +++ b/frontend/src/utils/renderMarkdown.js @@ -1,5 +1,51 @@ import { marked } from 'marked'; +import { markedHighlight } from 'marked-highlight'; +import hljs from 'highlight.js/lib/core'; import DOMPurify from 'dompurify'; +import javascript from 'highlight.js/lib/languages/javascript'; +import typescript from 'highlight.js/lib/languages/typescript'; +import xml from 'highlight.js/lib/languages/xml'; +import css from 'highlight.js/lib/languages/css'; +import json from 'highlight.js/lib/languages/json'; +import bash from 'highlight.js/lib/languages/bash'; +import python from 'highlight.js/lib/languages/python'; +import sql from 'highlight.js/lib/languages/sql'; +import yaml from 'highlight.js/lib/languages/yaml'; +import markdown from 'highlight.js/lib/languages/markdown'; +import ini from 'highlight.js/lib/languages/ini'; +import dockerfile from 'highlight.js/lib/languages/dockerfile'; + +// Solo los lenguajes que realmente se esperan en documentos de este proyecto -- se usa +// highlight.js/lib/core (sin lenguajes) en vez del paquete completo (~1MB) para no inflar el +// bundle con lenguajes que nunca se van a usar aqui. +hljs.registerLanguage('javascript', javascript); +hljs.registerLanguage('js', javascript); +hljs.registerLanguage('typescript', typescript); +hljs.registerLanguage('ts', typescript); +hljs.registerLanguage('xml', xml); +hljs.registerLanguage('html', xml); +hljs.registerLanguage('css', css); +hljs.registerLanguage('json', json); +hljs.registerLanguage('bash', bash); +hljs.registerLanguage('sh', bash); +hljs.registerLanguage('shell', bash); +hljs.registerLanguage('python', python); +hljs.registerLanguage('py', python); +hljs.registerLanguage('sql', sql); +hljs.registerLanguage('yaml', yaml); +hljs.registerLanguage('yml', yaml); +hljs.registerLanguage('markdown', markdown); +hljs.registerLanguage('md', markdown); +hljs.registerLanguage('ini', ini); +hljs.registerLanguage('dockerfile', dockerfile); + +marked.use(markedHighlight({ + langPrefix: 'hljs language-', + highlight(code, lang) { + const language = hljs.getLanguage(lang) ? lang : 'plaintext'; + return hljs.highlight(code, { language }).value; + }, +})); // Un documento .md subido por cualquier miembro del proyecto puede ser visto por otros // miembros -- sin sanitizar, HTML/JS embebido en el markdown se ejecutaria al renderizarlo