Merge pull request #674 from getmaxun/perfect-ui

feat: enhance snapshot rendering
This commit is contained in:
Rohit
2025-07-07 01:24:54 +05:30
committed by GitHub
2 changed files with 73 additions and 125 deletions

View File

@@ -734,7 +734,7 @@ export const IntegrationSettingsModal = ({
<Button
variant="outlined"
onClick={() => {
window.open("https://docs.maxun.dev/mcp/setup", "_blank" "noopener,noreferrer");
window.open("https://docs.maxun.dev/mcp/setup", "_blank", "noopener,noreferrer");
}}
style={{ display: "flex", flexDirection: "column", alignItems: "center", background: 'white', color: '#ff00c3' }}
>

View File

@@ -756,20 +756,86 @@ export const DOMBrowserRenderer: React.FC<RRWebDOMBrowserRendererProps> = ({
return;
}
const iframe = iframeRef.current;
if (isInCaptureMode) {
return; // Skip rendering in capture mode
}
try {
setRenderError(null);
setIsRendered(false);
const tempDoc =
document.implementation.createHTMLDocument("RRWeb Snapshot");
const iframe = iframeRef.current!;
const iframeDoc = iframe.contentDocument!;
const styleTags = Array.from(
document.querySelectorAll('link[rel="stylesheet"], style')
)
.map((tag) => tag.outerHTML)
.join("\n");
const enhancedCSS = `
/* rrweb rebuilt content styles */
html, body {
margin: 0 !important;
padding: 8px !important;
overflow-x: hidden !important;
}
html::-webkit-scrollbar,
body::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
background: transparent !important;
}
/* Hide scrollbars for all elements */
*::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
background: transparent !important;
}
* {
scrollbar-width: none !important; /* Firefox */
-ms-overflow-style: none !important; /* Internet Explorer 10+ */
}
/* Make everything interactive */
* {
cursor: "pointer" !important;
}
`;
const skeleton = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="${snapshotData.baseUrl}">
${styleTags}
<style>${enhancedCSS}</style>
</head>
<body></body>
</html>
`;
if (!iframeDoc) {
throw new Error("Cannot access iframe document");
}
// Write the skeleton into the iframe
iframeDoc.open();
iframeDoc.write(skeleton);
iframeDoc.close();
const mirror = createMirror();
try {
rebuild(snapshotData.snapshot, {
doc: tempDoc,
doc: iframeDoc,
mirror: mirror,
cache: { stylesWithHoverClass: new Map() },
afterAppend: (node) => {
@@ -793,126 +859,8 @@ export const DOMBrowserRenderer: React.FC<RRWebDOMBrowserRendererProps> = ({
throw new Error(`rrweb rebuild failed: ${rebuildError}`);
}
let rebuiltHTML = tempDoc.documentElement.outerHTML;
rebuiltHTML = "<!DOCTYPE html>\n" + rebuiltHTML;
const additionalCSS = [];
if (snapshotData.resources.fonts?.length > 0) {
const fontCSS = snapshotData.resources.fonts
.map((font) => {
const format = font.format || "woff2";
return `
@font-face {
font-family: 'ProxiedFont-${
font.url.split("/").pop()?.split(".")[0] || "unknown"
}';
src: url("${font.dataUrl}") format("${format}");
font-display: swap;
}
`;
})
.join("\n");
additionalCSS.push(fontCSS);
}
if (snapshotData.resources.stylesheets?.length > 0) {
const externalCSS = snapshotData.resources.stylesheets
.map((stylesheet) => stylesheet.content)
.join("\n\n");
additionalCSS.push(externalCSS);
}
const enhancedCSS = `
/* rrweb rebuilt content styles */
html, body {
margin: 0 !important;
padding: 8px !important;
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif !important;
background: white !important;
overflow-x: hidden !important;
}
html::-webkit-scrollbar,
body::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
background: transparent !important;
}
/* Hide scrollbars for all elements */
*::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
background: transparent !important;
}
* {
scrollbar-width: none !important; /* Firefox */
-ms-overflow-style: none !important; /* Internet Explorer 10+ */
}
img {
max-width: 100% !important;
height: auto !important;
}
/* Make everything interactive */
* {
cursor: "pointer" !important;
}
/* Additional CSS from resources */
${additionalCSS.join("\n\n")}
`;
const headTagRegex = /<head[^>]*>/i;
const cssInjection = `
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="${snapshotData.baseUrl}">
<style>${enhancedCSS}</style>
`;
if (headTagRegex.test(rebuiltHTML)) {
rebuiltHTML = rebuiltHTML.replace(
"<head>",
`<head><base href="${snapshotData.baseUrl}">${minimalCSS}`
);
} else if (rebuiltHTML.includes("<html>")) {
rebuiltHTML = rebuiltHTML.replace(
"<html>",
`<html><head><base href="${snapshotData.baseUrl}">${minimalCSS}</head>`
);
}
rebuiltHTML = rebuiltHTML
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")
.replace(/\s*on\w+\s*=\s*"[^"]*"/gi, "")
.replace(/\s*on\w+\s*=\s*'[^']*'/gi, "")
.replace(/javascript:/gi, "void:")
.replace(/<form\b/gi, '<form onsubmit="return false;"');
const iframeDoc =
iframe.contentDocument || iframe.contentWindow?.document;
if (!iframeDoc) {
throw new Error("Cannot access iframe document");
}
iframeDoc.open();
iframeDoc.write(rebuiltHTML);
iframeDoc.close();
iframe.onload = () => {
setIsRendered(true);
setupIframeInteractions(iframeDoc);
};
setIsRendered(true);
setupIframeInteractions(iframeDoc);
} catch (error) {
console.error("Error rendering rrweb snapshot:", error);
setRenderError(error instanceof Error ? error.message : String(error));