From d5ea2aa824eee4b7e2d169d21da0107d057e7bc6 Mon Sep 17 00:00:00 2001 From: Bobby <30593201+luciferreeves@users.noreply.github.com> Date: Wed, 24 Dec 2025 17:17:15 +0530 Subject: feat: Implement API endpoints for email details and actions, and refactor email preview for client-side rendering with Shadow DOM. --- static/js/shadow.js | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 static/js/shadow.js (limited to 'static/js/shadow.js') diff --git a/static/js/shadow.js b/static/js/shadow.js new file mode 100644 index 0000000..8439639 --- /dev/null +++ b/static/js/shadow.js @@ -0,0 +1,63 @@ +/* ShadowRenderer.js - A tiny library to render safely encapsulated HTML */ +const ShadowRenderer = { + render: function (hostElement, htmlContent, options = {}) { + // 1. Attach Shadow Root (if not exists) + let shadow = hostElement.shadowRoot; + if (!shadow) { + shadow = hostElement.attachShadow({ mode: 'open' }); + } + + // 2. Parse HTML + const parser = new DOMParser(); + const doc = parser.parseFromString(htmlContent, 'text/html'); + + // 3. Rewrite Styles (Body -> Wrapper) + const styles = doc.querySelectorAll('style'); + styles.forEach(style => { + // Replace 'body' selector with '.mail-body-content' + style.textContent = style.textContent.replace(/(^|[\}\s,;])body(?=[\s,\.\{])/gi, '$1.mail-body-content'); + }); + + // 4. Create Wrapper + const wrapper = document.createElement('div'); + wrapper.className = 'mail-body-content'; + + // Copy attributes & move children + if (doc.body) { + Array.from(doc.body.attributes).forEach(attr => { + if (attr.name === 'class') { + if (attr.value) wrapper.classList.add(...attr.value.split(' ')); + } else { + wrapper.setAttribute(attr.name, attr.value); + } + }); + // Handle legacy bgcolor if present + if (doc.body.bgColor) wrapper.style.backgroundColor = doc.body.bgColor; + + while (doc.body.firstChild) wrapper.appendChild(doc.body.firstChild); + } + + // 5. Build Shadow Content + shadow.innerHTML = ''; // Clear previous + + // Append Head Content (Styles) + if (doc.head) { + while (doc.head.firstChild) shadow.appendChild(doc.head.firstChild); + } + + // Append Body Wrapper + shadow.appendChild(wrapper); + + // 6. Apply Default Styles + const defaultStyle = document.createElement('style'); + defaultStyle.textContent = ` + :host { display: block; overflow: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + .mail-body-content { margin: 0; padding: 16px; min-height: 100%; } + img { max-width: 100%; height: auto; } + a { color: #1a73e8; } + `; + shadow.prepend(defaultStyle); + + return shadow; + } +}; -- cgit v1.2.3