@wonderwhy-er/desktop-commander
Version:
MCP server for terminal operations and file editing
48 lines (47 loc) • 2.35 kB
JavaScript
/**
* HTML preview renderer with display mode control. It handles rendered HTML versus
* source text display and ensures fallback behavior is predictable.
*
* The rendered preview runs inside a nested sandboxed iframe, which is itself inside
* the MCP app's sandboxed iframe chain. Scripts and external resources (CDNs) are
* allowed since the sandbox isolation prevents any escape.
*/
import { renderCodeViewer } from './code-viewer.js';
import { escapeHtml } from './highlighting.js';
function resolveThemeFrameStyles() {
if (typeof window === 'undefined' || typeof document === 'undefined') {
return {
background: 'Canvas',
text: 'CanvasText',
fontFamily: 'system-ui, sans-serif',
};
}
const rootStyles = window.getComputedStyle(document.documentElement);
const background = rootStyles.getPropertyValue('--panel').trim() || 'Canvas';
const text = rootStyles.getPropertyValue('--text').trim() || 'CanvasText';
const fontFamily = rootStyles.getPropertyValue('--font-sans').trim() || 'system-ui, sans-serif';
return { background, text, fontFamily };
}
function renderSandboxedHtmlFrame(content) {
const palette = resolveThemeFrameStyles();
const frameDocument = `<!doctype html><html><head><meta charset="utf-8" /><style>html,body{margin:0;padding:0;background:${palette.background};color:${palette.text};}body{font-family:${palette.fontFamily};padding:16px;line-height:1.5;}img{max-width:100%;height:auto;}</style></head><body>${content}</body></html>`;
return `<iframe class="html-rendered-frame" title="Rendered HTML preview" sandbox="allow-scripts allow-forms allow-popups" referrerpolicy="no-referrer" srcdoc="${escapeHtml(frameDocument)}"></iframe>`;
}
export function renderHtmlPreview(content, mode) {
if (mode === 'source') {
return {
html: `<div class="panel-content source-content">${renderCodeViewer(content, 'html')}</div>`
};
}
try {
return {
html: `<div class="panel-content html-content">${renderSandboxedHtmlFrame(content)}</div>`
};
}
catch {
return {
html: `<div class="panel-content source-content">${renderCodeViewer(content, 'html')}</div>`,
notice: 'HTML renderer failed. Showing source instead.'
};
}
}