diff --git a/www/css/styles.css b/www/css/styles.css index edc4fd6..2c7a536 100644 --- a/www/css/styles.css +++ b/www/css/styles.css @@ -431,6 +431,33 @@ a:hover { text-decoration: underline; } } .copy-btn:hover, .download-btn:hover { background: var(--accent); color: white; } +.html-preview-block { margin: 8px 0; } +.html-preview-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 6px 12px; + background: var(--bg-tertiary); + border-radius: 8px 8px 0 0; + font-size: 12px; + color: var(--text-secondary); + border: 1px solid var(--border); + border-bottom: none; +} +.html-preview-bar + pre { border-top-left-radius: 0; border-top-right-radius: 0; } +.html-preview-btn { + background: linear-gradient(135deg, #6c63ff, #a855f7); + border: none; + color: white; + padding: 4px 14px; + border-radius: 4px; + font-size: 11px; + font-weight: 600; + cursor: pointer; + transition: opacity var(--transition); +} +.html-preview-btn:hover { opacity: 0.85; } + .msg-actions { display: flex; gap: 6px; diff --git a/www/index.html b/www/index.html index 0dfedd7..9538049 100644 --- a/www/index.html +++ b/www/index.html @@ -132,6 +132,19 @@ + +
diff --git a/www/js/app.js b/www/js/app.js index 4990893..520cf95 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -330,9 +330,20 @@ return code; }, breaks: true, - gfm: true + gfm: true, + sanitize: false }); - return marked.parse(text); + var html = marked.parse(text); + html = html.replace(/
([\s\S]*?)<\/code><\/pre>/gi, function(match, codeContent) {
+                var decoded = codeContent.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, "'");
+                var uid = 'hprev_' + Math.random().toString(36).substr(2, 9);
+                return '
' + + '
HTML
' + + '
' + codeContent + '
' + + '' + + '
'; + }); + return html; } return text.replace(//g, '>').replace(/\n/g, '
'); } @@ -405,6 +416,43 @@ }); } }); + + container.querySelectorAll('.html-preview-btn').forEach(function(btn) { + btn.addEventListener('click', function() { + var uid = this.getAttribute('data-uid'); + var wrapper = container.querySelector('.html-preview-block[data-uid="' + uid + '"]'); + if (!wrapper) return; + var srcEl = wrapper.querySelector('.html-preview-src'); + if (!srcEl) return; + var src = srcEl.textContent; + openHtmlPreview(src); + }); + }); + } + + function openHtmlPreview(htmlSource) { + var preview = $('#html-preview'); + var frame = $('#html-preview-frame'); + var title = $('#html-preview-title'); + if (!preview || !frame) return; + if (title) title.textContent = 'HTML Preview'; + preview.style.display = 'flex'; + var doc = frame.contentDocument || frame.contentWindow.document; + doc.open(); + doc.write(htmlSource); + doc.close(); + } + + function closeHtmlPreview() { + var preview = $('#html-preview'); + if (preview) preview.style.display = 'none'; + } + + function openHtmlInNewTab(htmlSource) { + var blob = new Blob([htmlSource], { type: 'text/html' }); + var url = URL.createObjectURL(blob); + window.open(url, '_blank'); + setTimeout(function() { URL.revokeObjectURL(url); }, 60000); } function highlightFilePaths(html) { @@ -3519,6 +3567,14 @@ if (approvalState && approvalState.onApprove) approvalState.onApprove(); }); $('#approval-deny').addEventListener('click', closeApproval); + $('#html-preview-close').addEventListener('click', closeHtmlPreview); + $('#html-preview-newtab').addEventListener('click', function() { + var frame = $('#html-preview-frame'); + if (!frame) return; + var doc = frame.contentDocument || frame.contentWindow.document; + var src = doc.documentElement.outerHTML; + openHtmlInNewTab('' + src); + }); $('#theme-toggle-header').addEventListener('click', toggleTheme);