이메일 내용 iframe으로 변경
This commit is contained in:
parent
730ea717bf
commit
54f6dce97d
1 changed files with 115 additions and 30 deletions
|
|
@ -2,7 +2,7 @@
|
|||
* 메일 상세 보기 컴포넌트
|
||||
* 선택된 메일의 내용, 첨부파일, 액션 버튼 표시
|
||||
*/
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useMail } from '../context/MailContext';
|
||||
import { Trash2, Printer, Star, Reply, Forward, Mail as MailIcon, MailOpen, Archive, Paperclip, Download, FileText, Image, File, Edit, AlertOctagon, Languages, Sparkles } from 'lucide-react';
|
||||
|
|
@ -15,6 +15,103 @@ import { encodeEmailId } from '../utils/emailIdEncoder';
|
|||
import { HighlightText } from '../utils/highlightText';
|
||||
import ConfirmDialog from './ConfirmDialog';
|
||||
|
||||
/**
|
||||
* 이메일 HTML을 iframe 안에서 렌더링하는 컴포넌트 (CSS 격리)
|
||||
*/
|
||||
const EmailIframe = ({ htmlContent }) => {
|
||||
const iframeRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (iframeRef.current && htmlContent) {
|
||||
const doc = iframeRef.current.contentDocument;
|
||||
if (doc) {
|
||||
doc.open();
|
||||
doc.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<base target="_blank">
|
||||
<style>
|
||||
html { height: auto !important; overflow: visible !important; }
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
height: auto !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
img { max-width: 100%; height: auto; }
|
||||
a { color: #2563eb; }
|
||||
* { max-width: 100%; box-sizing: border-box; }
|
||||
table { height: auto !important; }
|
||||
div, td, tr { height: auto !important; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${htmlContent}</body>
|
||||
</html>
|
||||
`);
|
||||
doc.close();
|
||||
|
||||
// iframe 높이 자동 조절 - 실제 콘텐츠 높이 측정
|
||||
const resizeIframe = () => {
|
||||
if (iframeRef.current && doc.body) {
|
||||
// 모든 자식 요소의 실제 위치를 기반으로 높이 계산
|
||||
const children = doc.body.children;
|
||||
let maxBottom = 0;
|
||||
|
||||
for (let child of children) {
|
||||
const rect = child.getBoundingClientRect();
|
||||
const bottom = rect.top + rect.height;
|
||||
if (bottom > maxBottom) {
|
||||
maxBottom = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
// 최소 100px, 최대 계산된 높이 + 여유 20px
|
||||
const height = Math.max(maxBottom + 20, 100);
|
||||
iframeRef.current.style.height = height + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
// 이미지 로드 후 재조정
|
||||
const images = doc.images;
|
||||
let loadedCount = 0;
|
||||
const totalImages = images.length;
|
||||
|
||||
if (totalImages === 0) {
|
||||
resizeIframe();
|
||||
} else {
|
||||
for (let img of images) {
|
||||
img.onload = img.onerror = () => {
|
||||
loadedCount++;
|
||||
resizeIframe();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 초기 크기 설정 + 지연 재조정
|
||||
setTimeout(resizeIframe, 50);
|
||||
setTimeout(resizeIframe, 200);
|
||||
setTimeout(resizeIframe, 500);
|
||||
}
|
||||
}
|
||||
}, [htmlContent]);
|
||||
|
||||
return (
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
title="email-content"
|
||||
className="w-full border-0 mb-8"
|
||||
style={{ minHeight: '100px', overflow: 'hidden' }}
|
||||
sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"
|
||||
scrolling="no"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const MailDetail = ({ onContinueDraft, onReply, onForward }) => {
|
||||
const navigate = useNavigate();
|
||||
const { selectedEmail, setSelectedEmail, toggleStar, moveToTrash, markAsUnread, markAsRead, restoreEmail, deleteEmail, selectedBox, moveToSpam, moveEmail, userNames, isSearchMode, searchQuery } = useMail();
|
||||
|
|
@ -590,19 +687,9 @@ const MailDetail = ({ onContinueDraft, onReply, onForward }) => {
|
|||
const textHasHtml = textContent && /<[a-z][\s\S]*>/i.test(textContent);
|
||||
|
||||
if (htmlContent) {
|
||||
return (
|
||||
<div
|
||||
className="email-html-content mb-8 overflow-x-auto"
|
||||
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
||||
/>
|
||||
);
|
||||
return <EmailIframe htmlContent={htmlContent} />;
|
||||
} else if (textHasHtml) {
|
||||
return (
|
||||
<div
|
||||
className="email-html-content mb-8 overflow-x-auto"
|
||||
dangerouslySetInnerHTML={{ __html: textContent }}
|
||||
/>
|
||||
);
|
||||
return <EmailIframe htmlContent={textContent} />;
|
||||
} else {
|
||||
return (
|
||||
<div className="mb-8 p-6 bg-gray-50 rounded-xl border border-gray-100">
|
||||
|
|
@ -646,27 +733,25 @@ const MailDetail = ({ onContinueDraft, onReply, onForward }) => {
|
|||
const isHtml = /<[a-z][\s\S]*>/i.test(translatedContent);
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="absolute -top-2 left-4 px-3 py-1 rounded-full text-xs font-semibold text-white shadow-md flex items-center gap-1.5" style={{ background: 'linear-gradient(90deg, #4285f4, #ea4335, #fbbc05, #34a853)' }}>
|
||||
<div className="absolute -top-2 left-4 px-3 py-1 rounded-full text-xs font-semibold text-white shadow-md flex items-center gap-1.5 z-10" style={{ background: 'linear-gradient(90deg, #4285f4, #ea4335, #fbbc05, #34a853)' }}>
|
||||
<Sparkles className="w-3 h-3" />
|
||||
번역됨
|
||||
</div>
|
||||
{isHtml ? (
|
||||
<div
|
||||
className="email-html-content mb-8 overflow-x-auto rounded-xl p-4 mt-2"
|
||||
className="rounded-xl mt-2 overflow-hidden"
|
||||
style={{ border: '2px solid transparent', background: 'linear-gradient(white, white) padding-box, linear-gradient(90deg, #4285f4, #ea4335, #fbbc05, #34a853) border-box' }}
|
||||
dangerouslySetInnerHTML={{ __html: translatedContent }}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className="mb-8 p-6 rounded-xl mt-2"
|
||||
style={{ border: '2px solid transparent', background: 'linear-gradient(#f0f9ff, #f0f9ff) padding-box, linear-gradient(90deg, #4285f4, #ea4335, #fbbc05, #34a853) border-box' }}
|
||||
>
|
||||
{isHtml ? (
|
||||
<EmailIframe htmlContent={translatedContent} />
|
||||
) : (
|
||||
<div className="p-6">
|
||||
<pre className="whitespace-pre-wrap font-sans text-sm text-gray-700 leading-relaxed">
|
||||
{translatedContent}
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue