New:Socket for Asana Is Now Available.Learn more
Get Started

@thiennq/docs-viewer

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thiennq/docs-viewer - npm Package Compare versions

Comparing version
1.5.1
to
1.6.0
+14
public/components/Badge.jsx
function Badge({ type = 'default', children }) {
const variant = String(children || '').toLowerCase().trim();
let customStyle = {};
if (variant === 'easy') customStyle = { background: 'rgba(16, 185, 129, 0.15)', color: '#10b981', border: '1px solid rgba(16, 185, 129, 0.3)', padding: '2px 8px', borderRadius: '10px', fontWeight: 700, fontSize: '0.75rem' };
else if (variant === 'medium') customStyle = { background: 'rgba(59, 130, 246, 0.15)', color: '#3b82f6', border: '1px solid rgba(59, 130, 246, 0.3)', padding: '2px 8px', borderRadius: '10px', fontWeight: 700, fontSize: '0.75rem' };
else if (variant === 'hard') customStyle = { background: 'rgba(245, 158, 11, 0.15)', color: '#f59e0b', border: '1px solid rgba(245, 158, 11, 0.3)', padding: '2px 8px', borderRadius: '10px', fontWeight: 700, fontSize: '0.75rem' };
else if (variant === 'nightmare') customStyle = { background: 'rgba(239, 68, 68, 0.15)', color: '#ef4444', border: '1px solid rgba(239, 68, 68, 0.3)', padding: '2px 8px', borderRadius: '10px', fontWeight: 700, fontSize: '0.75rem' };
return (
<span className={`mdx-badge mdx-badge-${type}`} style={customStyle}>
{children}
</span>
);
}
function Button({ variant = 'primary', onClick, children }) {
return (
<button className={`mdx-button mdx-button-${variant}`} onClick={onClick || (() => {})}>
{children}
</button>
);
}
function Callout({ type = 'info', title, children }) {
const icons = { info: '💡', warning: '⚠️', success: '✅', error: '🛑' };
return (
<div className={`mdx-callout mdx-callout-${type}`}>
<div className="mdx-callout-header">
<span className="mdx-callout-icon">{icons[type] || '💡'}</span>
{title && <strong className="mdx-callout-title">{title}</strong>}
</div>
<div className="mdx-callout-content">{children}</div>
</div>
);
}
function Card({ title, icon = '📁', children }) {
return (
<div className="mdx-card">
{title && (
<div className="mdx-card-header">
<span className="mdx-card-icon">{icon}</span>
<span className="mdx-card-title">{title}</span>
</div>
)}
<div className="mdx-card-body">{children}</div>
</div>
);
}
function StatCard({ label, value, sub, color = '#6366f1' }) {
return (
<div style={{
background: 'rgba(22, 30, 49, 0.8)',
border: '1px solid rgba(255, 255, 255, 0.08)',
borderRadius: '16px',
padding: '20px',
position: 'relative',
overflow: 'hidden'
}}>
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '3px', background: color }} />
<div style={{ fontSize: '0.78rem', fontWeight: 700, color: '#94a3b8', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
{label}
</div>
<div style={{ fontSize: '2rem', fontWeight: 800, color: '#f8fafc', margin: '6px 0 2px 0' }}>
{value}
</div>
{sub && <div style={{ fontSize: '0.82rem', color: '#64748b' }}>{sub}</div>}
</div>
);
}
function StatGrid({ children }) {
return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '16px', margin: '20px 0' }}>
{children}
</div>
);
}
import React from 'react';
import styled from 'styled-components';
const CardWrapper = styled.div`
background: linear-gradient(135deg, rgba(99, 102, 241, 0.15), rgba(139, 92, 246, 0.15));
border: 1px solid rgba(99, 102, 241, 0.4);
border-radius: 16px;
padding: 24px;
margin: 20px 0;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(12px);
`;
const CardTitle = styled.h4`
font-size: 1.1rem;
font-weight: 700;
color: #818cf8;
margin: 0 0 8px 0;
display: flex;
align-items: center;
gap: 8px;
`;
const CardBody = styled.div`
color: #cbd5e1;
font-size: 0.92rem;
line-height: 1.6;
`;
export default function StyledCard({ title = 'CSS-in-JS Styled Component', children }) {
return (
<CardWrapper>
<CardTitle>✨ {title}</CardTitle>
<CardBody>{children}</CardBody>
</CardWrapper>
);
}
function ThresholdViewer() {
const [threshold, setThreshold] = React.useState('50');
const barCanvasRef = React.useRef(null);
const pieCanvasRef = React.useRef(null);
const barChartRef = React.useRef(null);
const pieChartRef = React.useRef(null);
const data = {
"50": {
total: 31406119,
pctTotal: "62.81%",
easy: 12500000,
medium: 9581731,
hard: 8970875,
nightmare: 353513,
avgEng: { easy: 63.8, medium: 57.2, hard: 56.4, nightmare: 51.2 }
},
"60": {
total: 17987423,
pctTotal: "35.97%",
easy: 12500000,
medium: 2567818,
hard: 2903366,
nightmare: 16239,
avgEng: { easy: 63.8, medium: 63.1, hard: 63.4, nightmare: 61.5 }
},
"70": {
total: 354572,
pctTotal: "0.71%",
easy: 0,
medium: 237870,
hard: 115996,
nightmare: 706,
avgEng: { easy: 0, medium: 72.8, hard: 73.1, nightmare: 70.8 }
},
"80": {
total: 67,
pctTotal: "< 0.001%",
easy: 0,
medium: 32,
hard: 35,
nightmare: 0,
avgEng: { easy: 0, medium: 86.4, hard: 87.2, nightmare: 0 }
},
"90": {
total: 5,
pctTotal: "< 0.0001%",
easy: 0,
medium: 3,
hard: 2,
nightmare: 0,
avgEng: { easy: 0, medium: 93.3, hard: 96.4, nightmare: 0 }
}
};
const curr = data[threshold];
const diffs = [
{ key: 'easy', label: 'EASY', color: '#10b981', count: curr.easy },
{ key: 'medium', label: 'MEDIUM', color: '#3b82f6', count: curr.medium },
{ key: 'hard', label: 'HARD', color: '#f59e0b', count: curr.hard },
{ key: 'nightmare', label: 'NIGHTMARE', color: '#ef4444', count: curr.nightmare }
];
const maxCount = Math.max(...diffs.map(d => d.count), 1);
React.useEffect(() => {
if (typeof Chart === 'undefined') return;
if (barCanvasRef.current) {
if (barChartRef.current) barChartRef.current.destroy();
const ctxBar = barCanvasRef.current.getContext('2d');
barChartRef.current = new Chart(ctxBar, {
type: 'bar',
data: {
labels: ['Easy', 'Medium', 'Hard', 'Nightmare'],
datasets: [{
label: 'Map Count',
data: [curr.easy, curr.medium, curr.hard, curr.nightmare],
backgroundColor: ['#10b981', '#3b82f6', '#f59e0b', '#ef4444'],
borderRadius: 8
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: {
callbacks: { label: (ctx) => ` ${ctx.raw.toLocaleString()} maps` }
}
},
scales: {
x: { grid: { display: false }, ticks: { color: '#94a3b8', font: { weight: '600' } } },
y: { grid: { color: 'rgba(255, 255, 255, 0.06)' }, ticks: { color: '#94a3b8' } }
}
}
});
}
if (pieCanvasRef.current) {
if (pieChartRef.current) pieChartRef.current.destroy();
const ctxPie = pieCanvasRef.current.getContext('2d');
pieChartRef.current = new Chart(ctxPie, {
type: 'doughnut',
data: {
labels: ['Easy', 'Medium', 'Hard', 'Nightmare'],
datasets: [{
data: [curr.easy, curr.medium, curr.hard, curr.nightmare],
backgroundColor: ['#10b981', '#3b82f6', '#f59e0b', '#ef4444'],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'bottom', labels: { color: '#94a3b8', font: { size: 12, weight: '600' } } }
},
cutout: '70%'
}
});
}
return () => {
if (barChartRef.current) barChartRef.current.destroy();
if (pieChartRef.current) pieChartRef.current.destroy();
};
}, [threshold]);
return (
<div style={{
background: 'rgba(22, 30, 49, 0.85)',
border: '1px solid rgba(255, 255, 255, 0.1)',
borderRadius: '16px',
padding: '24px',
margin: '24px 0'
}}>
{/* Header & Tabs */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px', flexWrap: 'wrap', gap: '12px' }}>
<h3 style={{ fontSize: '1.15rem', fontWeight: 700, margin: 0, color: '#f8fafc', display: 'flex', alignItems: 'center', gap: '8px' }}>
<span style={{ width: '8px', height: '18px', background: '#6366f1', borderRadius: '4px' }} />
Engagement Threshold Distribution
</h3>
<div style={{ display: 'flex', gap: '6px', background: 'rgba(15, 23, 42, 0.7)', padding: '4px', borderRadius: '10px', border: '1px solid rgba(255,255,255,0.08)' }}>
{['50', '60', '70', '80', '90'].map(t => (
<button
key={t}
onClick={() => setThreshold(t)}
style={{
padding: '6px 14px',
borderRadius: '6px',
border: 'none',
background: threshold === t ? '#6366f1' : 'transparent',
color: threshold === t ? '#fff' : '#94a3b8',
fontWeight: 600,
fontSize: '0.85rem',
cursor: 'pointer',
transition: 'all 0.2s'
}}
>
E ≥ {t}
</button>
))}
</div>
</div>
{/* Chart.js Canvas Row */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: '20px', marginBottom: '24px', height: '300px' }}>
<div style={{ position: 'relative', height: '100%', width: '100%', background: 'rgba(15, 23, 42, 0.5)', padding: '12px', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.05)' }}>
<canvas ref={barCanvasRef} />
</div>
<div style={{ position: 'relative', height: '100%', width: '100%', background: 'rgba(15, 23, 42, 0.5)', padding: '12px', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.05)' }}>
<canvas ref={pieCanvasRef} />
</div>
</div>
{/* Visual Progress Bars */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: '16px', marginBottom: '24px' }}>
{diffs.map(d => {
const pctHeight = Math.max(4, Math.round((d.count / maxCount) * 100));
const pctGroup = curr.total > 0 ? ((d.count / curr.total) * 100).toFixed(2) : '0.00';
return (
<div key={d.key} style={{ background: 'rgba(15, 23, 42, 0.6)', padding: '16px', borderRadius: '12px', border: '1px solid rgba(255, 255, 255, 0.05)' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '8px', fontSize: '0.8rem', fontWeight: 700, color: d.color }}>
<span>{d.label}</span>
<span>{pctGroup}%</span>
</div>
<div style={{ fontSize: '1.25rem', fontWeight: 800, color: '#f8fafc', marginBottom: '12px' }}>
{d.count.toLocaleString()}
</div>
<div style={{ height: '8px', background: 'rgba(255,255,255,0.06)', borderRadius: '4px', overflow: 'hidden' }}>
<div style={{ width: `${pctHeight}%`, height: '100%', background: d.color, borderRadius: '4px', transition: 'width 0.4s ease' }} />
</div>
</div>
);
})}
</div>
{/* Data Table */}
<div style={{ overflowX: 'auto', borderRadius: '10px', border: '1px solid rgba(255, 255, 255, 0.08)' }}>
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.88rem', textAlign: 'left' }}>
<thead>
<tr style={{ background: 'rgba(15, 23, 42, 0.9)', color: '#94a3b8', fontSize: '0.78rem', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
<th style={{ padding: '12px 16px' }}>Difficulty</th>
<th style={{ padding: '12px 16px' }}>Map Count</th>
<th style={{ padding: '12px 16px' }}>Share in Threshold</th>
<th style={{ padding: '12px 16px' }}>Share of Total 50M</th>
<th style={{ padding: '12px 16px' }}>Avg Engagement</th>
</tr>
</thead>
<tbody>
{diffs.map(d => {
const pctGroup = curr.total > 0 ? ((d.count / curr.total) * 100).toFixed(2) + '%' : '0.00%';
const pct50M = ((d.count / 50000000) * 100).toFixed(2) + '%';
const avg = curr.avgEng[d.key] ? curr.avgEng[d.key] : '-';
return (
<tr key={d.key} style={{ borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
<td style={{ padding: '12px 16px', fontWeight: 700, color: d.color }}>{d.label}</td>
<td style={{ padding: '12px 16px', fontWeight: 700, color: '#f8fafc' }}>{d.count.toLocaleString()}</td>
<td style={{ padding: '12px 16px', color: '#cbd5e1' }}>{pctGroup}</td>
<td style={{ padding: '12px 16px', color: '#94a3b8' }}>{pct50M}</td>
<td style={{ padding: '12px 16px', color: '#cbd5e1' }}>{avg}</td>
</tr>
);
})}
<tr style={{ background: 'rgba(99, 102, 241, 0.12)', fontWeight: 700 }}>
<td style={{ padding: '12px 16px', color: '#818cf8' }}>TỔNG (E ≥ {threshold})</td>
<td style={{ padding: '12px 16px', color: '#fff' }}>{curr.total.toLocaleString()}</td>
<td style={{ padding: '12px 16px', color: '#fff' }}>100.00%</td>
<td style={{ padding: '12px 16px', color: '#818cf8' }}>{curr.pctTotal}</td>
<td style={{ padding: '12px 16px', color: '#fff' }}>-</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
/* ───────────────────────────────────────────────────────────
DYNAMIC NO-BUILD JSX COMPONENT LOADER (UNIVERSAL ENGINE)
Supports all 5 JSX Patterns + ES6 Imports/Exports + CSS-in-JS (styled)
─────────────────────────────────────────────────────────────*/
window.MDXBuiltInComponents = window.MDXBuiltInComponents || {};
async function loadJSXComponent(componentName, fileUrl) {
try {
const res = await fetch(fileUrl);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const rawJsx = await res.text();
// 1. Strip top-level import statements and export keywords
const cleanJsx = rawJsx
.replace(/^import\s+[\s\S]*?;?\s*$/gm, '')
.replace(/^export\s+default\s+/gm, '')
.replace(/^export\s+/gm, '');
// 2. Transpile JSX string on-the-fly via Babel Standalone
const compiled = Babel.transform(cleanJsx, {
presets: ['react']
}).code;
// 3. Resolve styled-components UMD global
const styledEngine = window.styled || (window.styledComponents ? (window.styledComponents.default || window.styledComponents) : null);
// 4. Create function in browser scope and evaluate component
const createComp = new Function('React', 'Chart', 'styled', compiled + `; return (typeof ${componentName} !== "undefined" ? ${componentName} : null);`);
const Component = createComp(React, window.Chart, styledEngine);
if (Component) {
window.MDXBuiltInComponents[componentName] = Component;
return Component;
} else {
console.warn(`Could not resolve component [${componentName}] from ${fileUrl}`);
}
} catch (err) {
console.error(`Failed to load JSX component [${componentName}] from ${fileUrl}:`, err);
}
}
async function loadAllJSXComponents() {
if (typeof Babel === 'undefined' || typeof React === 'undefined') return;
const componentList = [
{ name: 'Callout', url: '/components/Callout.jsx' },
{ name: 'Card', url: '/components/Card.jsx' },
{ name: 'Badge', url: '/components/Badge.jsx' },
{ name: 'Button', url: '/components/Button.jsx' },
{ name: 'StatCard', url: '/components/StatCard.jsx' },
{ name: 'StatGrid', url: '/components/StatGrid.jsx' },
{ name: 'ThresholdViewer', url: '/components/ThresholdViewer.jsx' },
{ name: 'StyledCard', url: '/components/StyledCard.jsx' }
];
await Promise.all(componentList.map(c => loadJSXComponent(c.name, c.url)));
}
// Auto-trigger universal component loader
window._jsxComponentsLoaded = loadAllJSXComponents();
/* ───────────────────────────────────────────────────────────
DOCS VIEWER — MDX PARSING & TRANSPILATION ENGINE
─────────────────────────────────────────────────────────────*/
async function renderMDXContent(mdxText, container) {
if (window._jsxComponentsLoaded) {
await window._jsxComponentsLoaded;
}
if (typeof Babel === 'undefined' || typeof React === 'undefined' || typeof ReactDOM === 'undefined') {
container.innerHTML = `
<div class="mdx-error-boundary">
<div class="mdx-error-header">⚠️ Missing Client Transpiler Libraries</div>
<div class="mdx-error-message">Babel Standalone or React/ReactDOM library is not loaded. Please check your network connection or CDN script tags.</div>
</div>
`;
return;
}
try {
// 1. Strip top-level import and export statements
let cleanText = mdxText
.replace(/^import\s+[\s\S]*?;?\s*$/gm, '')
.replace(/^export\s+[\s\S]*?;?\s*$/gm, '');
// 2. Parse Markdown portion to HTML while retaining JSX tags
let htmlFromMarkdown = marked.parse(cleanText);
// 2b. Remove HTML comments which break JSX
htmlFromMarkdown = htmlFromMarkdown.replace(/<!--[\s\S]*?-->/g, '');
// 2c. Convert HTML void tags (hr, br, img, input, etc.) to self-closing JSX tags (<hr />)
const voidTags = ['hr', 'br', 'img', 'input', 'meta', 'link', 'source', 'param', 'embed'];
voidTags.forEach(tag => {
const reg = new RegExp(`<${tag}\\b([^>]*)(?<!\\/)>`, 'gi');
htmlFromMarkdown = htmlFromMarkdown.replace(reg, `<${tag}$1 />`);
});
// 2d. Sanitize HTML for JSX to escape < in codeblocks and raw text nodes
htmlFromMarkdown = htmlFromMarkdown.replace(/(<code[^>]*>)([\s\S]*?)(<\/code>)/gi, (match, openTag, codeContent, closeTag) => {
const safeCode = codeContent.replace(/</g, '&lt;').replace(/>/g, '&gt;');
return openTag + safeCode + closeTag;
}).replace(/<(?![a-zA-Z_\/!?])/g, '&lt;');
// 3. Construct React Component code string
const jsxCode = `
function MDXDocument({ components }) {
const { Callout, Card, Badge, Button, StatGrid, StatCard, ThresholdViewer, StyledCard } = components;
return (
<React.Fragment>
${htmlFromMarkdown}
</React.Fragment>
);
}
`;
// 4. Transpile JSX using Babel Standalone
const compiled = Babel.transform(jsxCode, {
presets: ['react']
}).code;
// 5. Evaluate compiled JS code to obtain React Component
const createComponent = new Function('React', compiled + '; return MDXDocument;');
const MDXDocument = createComponent(React);
// 6. Render with ReactDOM Root
const builtInComponents = window.MDXBuiltInComponents || (typeof getMDXBuiltInComponents === 'function' ? getMDXBuiltInComponents() : {});
container.innerHTML = '';
const root = ReactDOM.createRoot(container);
root.render(React.createElement(MDXDocument, { components: builtInComponents }));
// Allow React DOM flush before post-processing
await new Promise(r => setTimeout(r, 60));
} catch (err) {
container.innerHTML = `
<div class="mdx-error-boundary">
<div class="mdx-error-header">⚠️ MDX Compilation / Runtime Error</div>
<pre class="mdx-error-message">${typeof escapeHtml === 'function' ? escapeHtml(err.stack || err.message) : (err.stack || err.message)}</pre>
</div>
`;
}
}
window.renderMDXContent = renderMDXContent;
+18
-0

@@ -5,2 +5,20 @@ # Docs Viewer CHANGELOG

## [1.6.0] - 2026-07-26
### Added
* **Modular No-Build React/JSX Component Architecture**:
* `public/loader.js`: Implemented lightweight client-side dynamic loader to import and transpile `.jsx` components on the fly without bundlers or build steps.
* `public/mdx.js`: Extracted MDX parsing and Babel Standalone transpilation pipeline from `app.js` into a dedicated modular engine.
* **Chart.js Integration & Data Visualization**:
* `public/index.html`: Loaded Chart.js v4 library via CDN.
* `ThresholdViewer.jsx`: Added interactive component powered by Chart.js for visualizing statistical metrics, difficulty distribution, and threshold analysis directly in MDX documentation.
* **CSS-in-JS & Styled Components Support**:
* `public/index.html`: Added CDN dependencies for `styled-components` v5.3.11 and `react-is` v18.2.0.
* `StyledCard.jsx`: Added styled-components based card component for custom CSS-in-JS document styling.
* **Expanded Built-in Component Library (`public/components/`)**:
* Added `StatCard.jsx` and `StatGrid.jsx` for dashboard metric cards.
* Modularized `Callout.jsx`, `Card.jsx`, `Badge.jsx`, and `Button.jsx` as standalone `.jsx` component files.
---
## [1.5.0] - 2026-07-22

@@ -7,0 +25,0 @@

+1
-1
{
"name": "@thiennq/docs-viewer",
"version": "1.5.1",
"version": "1.6.0",
"description": "Standalone Docs Viewer CLI — static HTTP server & browser reader for Markdown, MDX, HTML and Mermaid diagrams",

@@ -5,0 +5,0 @@ "main": "server.js",

@@ -33,2 +33,5 @@ <!DOCTYPE html>

<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- React & ReactDOM -->

@@ -38,2 +41,8 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>

<!-- React-Is dependency for Styled Components -->
<script src="https://cdn.jsdelivr.net/npm/react-is@18.2.0/umd/react-is.production.min.js"></script>
<!-- Styled Components for CSS-in-JS (depends on React & React-Is) -->
<script src="https://cdn.jsdelivr.net/npm/styled-components@5.3.11/dist/styled-components.min.js"></script>
<!-- Babel Standalone for MDX Transpilation -->

@@ -196,2 +205,5 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.6/babel.min.js"></script>

<!-- Modular No-Build JSX Components & MDX Engine -->
<script src="loader.js"></script>
<script src="mdx.js"></script>
<!-- App logic -->

@@ -198,0 +210,0 @@ <script src="app.js"></script>

@@ -15,5 +15,9 @@ # 📚 Docs Viewer (`@thiennq/docs-viewer`)

* **Markdown (`.md`)**: Full GFM support, task lists, tables, auto-generated Table of Contents (TOC).
* **MDX (`.mdx`)**: Client-side transpilation via Babel & React with built-in UI components (`<Callout>`, `<Card>`, `<Badge>`, `<Button>`).
* **MDX (`.mdx`)**: Client-side transpilation via Babel & React with dynamic no-build `.jsx` component loader (`loader.js`, `mdx.js`).
* **HTML (`.html`, `.htm`)**: Sanitized inline HTML rendering via DOMPurify.
* 📊 **Rich Visuals & Formulas**:
* ⚛️ **Modular No-Build Component Suite**:
* Built-in & custom JSX components (`<Callout>`, `<Card>`, `<StyledCard>`, `<Badge>`, `<Button>`, `<StatCard>`, `<StatGrid>`, `<ThresholdViewer>`).
* **Styled Components (CSS-in-JS)**: First-class support for styled-components without build tooling.
* 📊 **Rich Visuals, Charts & Formulas**:
* **Chart.js Visualizations**: Render interactive data charts and threshold analytics directly in MDX (`<ThresholdViewer>`).
* **Mermaid Diagrams**: Interactive rendering with dark/light theme switching and lightbox zoom modal.

@@ -20,0 +24,0 @@ * **KaTeX**: Fast math formula rendering ($\LaTeX$).

Sorry, the diff of this file is too big to display