feat: version 2.9.1 -- resaltado de sintaxis en bloques de codigo de documentos .md
Los bloques de codigo dentro de un .md visto en Documentos ahora tienen colores de token (highlight.js + marked-highlight), con el tema "Visual Studio" claro/oscuro para que se vea parecido a VSCode y se adapte solo al tema de la app. Se usa highlight.js/lib/core y solo se registran los lenguajes esperados en este proyecto (js/ts, bash, json, python, sql, yaml, html/xml, css, ini, dockerfile, markdown) para no inflar el bundle con el paquete completo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
# Changelog - project.linkedcorp.net
|
# 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
|
## [2.9.0] - 2026-10-07
|
||||||
### Added
|
### Added
|
||||||
- Documentos (adjuntos de proyectos/actividades): los archivos de texto plano (.txt) y Markdown
|
- Documentos (adjuntos de proyectos/actividades): los archivos de texto plano (.txt) y Markdown
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-backend",
|
"name": "project-linkedcorp-backend",
|
||||||
"version": "2.9.0",
|
"version": "2.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/server.js",
|
"main": "src/server.js",
|
||||||
|
|||||||
Generated
+22
-2
@@ -1,16 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-frontend",
|
"name": "project-linkedcorp-frontend",
|
||||||
"version": "2.8.13",
|
"version": "2.9.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "project-linkedcorp-frontend",
|
"name": "project-linkedcorp-frontend",
|
||||||
"version": "2.8.13",
|
"version": "2.9.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dompurify": "^3.4.16",
|
"dompurify": "^3.4.16",
|
||||||
|
"highlight.js": "^11.12.0",
|
||||||
"lucide-react": "^0.462.0",
|
"lucide-react": "^0.462.0",
|
||||||
"marked": "^18.1.0",
|
"marked": "^18.1.0",
|
||||||
|
"marked-highlight": "^2.2.4",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router-dom": "^7.18.3",
|
"react-router-dom": "^7.18.3",
|
||||||
@@ -4392,6 +4394,15 @@
|
|||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/human-signals": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
@@ -5069,6 +5080,15 @@
|
|||||||
"node": ">= 20"
|
"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": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-frontend",
|
"name": "project-linkedcorp-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.9.0",
|
"version": "2.9.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -10,8 +10,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dompurify": "^3.4.16",
|
"dompurify": "^3.4.16",
|
||||||
|
"highlight.js": "^11.12.0",
|
||||||
"lucide-react": "^0.462.0",
|
"lucide-react": "^0.462.0",
|
||||||
"marked": "^18.1.0",
|
"marked": "^18.1.0",
|
||||||
|
"marked-highlight": "^2.2.4",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router-dom": "^7.18.3",
|
"react-router-dom": "^7.18.3",
|
||||||
|
|||||||
@@ -6,11 +6,15 @@ import { listAttachments, uploadAttachment, deleteAttachment, downloadAttachment
|
|||||||
import { renderMarkdown } from '../utils/renderMarkdown.js';
|
import { renderMarkdown } from '../utils/renderMarkdown.js';
|
||||||
import { Button } from './Button.jsx';
|
import { Button } from './Button.jsx';
|
||||||
import { DetailPopup } from './DetailPopup.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']);
|
const VIEWABLE_MIME = new Set(['text/plain', 'text/markdown']);
|
||||||
|
|
||||||
export function AttachmentsPanel({ entityType, entityId }) {
|
export function AttachmentsPanel({ entityType, entityId }) {
|
||||||
const { t, openDialog } = useUi();
|
const { t, openDialog, theme } = useUi();
|
||||||
const runAction = useAction();
|
const runAction = useAction();
|
||||||
const { data: files, reload } = useAsync(() => listAttachments(entityType, entityId), [entityType, entityId]);
|
const { data: files, reload } = useAsync(() => listAttachments(entityType, entityId), [entityType, entityId]);
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
@@ -83,8 +87,11 @@ export function AttachmentsPanel({ entityType, entityId }) {
|
|||||||
{viewLoading ? (
|
{viewLoading ? (
|
||||||
<div className="text-muted">{t('common_loading')}</div>
|
<div className="text-muted">{t('common_loading')}</div>
|
||||||
) : viewing?.mime_type === 'text/markdown' ? (
|
) : viewing?.mime_type === 'text/markdown' ? (
|
||||||
// eslint-disable-next-line react/no-danger -- sanitizado con DOMPurify en renderMarkdown()
|
<>
|
||||||
|
<style>{theme === 'light' ? hljsLight : hljsDark}</style>
|
||||||
|
{/* eslint-disable-next-line react/no-danger -- sanitizado con DOMPurify en renderMarkdown() */}
|
||||||
<div className="markdown-view" dangerouslySetInnerHTML={{ __html: renderMarkdown(viewContent) }} />
|
<div className="markdown-view" dangerouslySetInnerHTML={{ __html: renderMarkdown(viewContent) }} />
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<pre className="text-view">{viewContent}</pre>
|
<pre className="text-view">{viewContent}</pre>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,51 @@
|
|||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
|
import { markedHighlight } from 'marked-highlight';
|
||||||
|
import hljs from 'highlight.js/lib/core';
|
||||||
import DOMPurify from 'dompurify';
|
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
|
// 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
|
// miembros -- sin sanitizar, HTML/JS embebido en el markdown se ejecutaria al renderizarlo
|
||||||
|
|||||||
Reference in New Issue
Block a user