diff --git a/frontend/src/components/MailDetail.jsx b/frontend/src/components/MailDetail.jsx
index 59e5c10..562ce7f 100644
--- a/frontend/src/components/MailDetail.jsx
+++ b/frontend/src/components/MailDetail.jsx
@@ -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(`
+
+
+
+
+
+
+
+ ${htmlContent}
+
+ `);
+ 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 (
+
+ );
+};
+
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 (
-
- );
+ return ;
} else if (textHasHtml) {
- return (
-
- );
+ return ;
} else {
return (
@@ -646,26 +733,24 @@ const MailDetail = ({ onContinueDraft, onReply, onForward }) => {
const isHtml = /<[a-z][\s\S]*>/i.test(translatedContent);
return (
-
+
번역됨
- {isHtml ? (
-
- ) : (
-
-
- {translatedContent}
-
-
- )}
+
+ {isHtml ? (
+
+ ) : (
+
+
+ {translatedContent}
+
+
+ )}
+
);
}