diff --git a/index.css b/index.css index 343a873..25143cc 100644 --- a/index.css +++ b/index.css @@ -1915,6 +1915,7 @@ @media (min-width: 768px) { .brand-identity-card { padding: 32px; + max-height: 500px; } } diff --git a/src/App.tsx b/src/App.tsx index 66b4863..bcb2395 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,11 +15,34 @@ type ViewMode = 'landing' | 'loading' | 'analysis' | 'login' | 'generation_flow' const VIEW_MODE_KEY = 'castad_view_mode'; const ANALYSIS_DATA_KEY = 'castad_analysis_data'; +const SESSION_KEY = 'castad_session_active'; + +// 새 탭/새 창에서 접근 시 localStorage 초기화 (sessionStorage로 현재 세션 확인) +const initializeOnNewSession = () => { + const isExistingSession = sessionStorage.getItem(SESSION_KEY); + + if (!isExistingSession) { + // 새 세션이면 localStorage 정리하고 세션 표시 + localStorage.removeItem(VIEW_MODE_KEY); + localStorage.removeItem(ANALYSIS_DATA_KEY); + localStorage.removeItem('castad_wizard_step'); + localStorage.removeItem('castad_active_item'); + localStorage.removeItem('castad_song_task_id'); + localStorage.removeItem('castad_image_task_id'); + localStorage.removeItem('castad_song_generation'); + localStorage.removeItem('castad_video_generation'); + localStorage.removeItem('castad_video_ratio'); + sessionStorage.setItem(SESSION_KEY, 'true'); + } +}; + +// 앱 시작 시 세션 체크 +initializeOnNewSession(); const App: React.FC = () => { const containerRef = useRef(null); - // localStorage에서 저장된 상태 복원 + // localStorage에서 저장된 상태 복원 (새 세션이면 이미 초기화됨) const savedViewMode = localStorage.getItem(VIEW_MODE_KEY) as ViewMode | null; const savedAnalysisData = localStorage.getItem(ANALYSIS_DATA_KEY); diff --git a/src/pages/Analysis/AnalysisResultSection.tsx b/src/pages/Analysis/AnalysisResultSection.tsx index 60cb5eb..f413a32 100755 --- a/src/pages/Analysis/AnalysisResultSection.tsx +++ b/src/pages/Analysis/AnalysisResultSection.tsx @@ -8,31 +8,33 @@ interface AnalysisResultSectionProps { data: CrawlingResponse; } -// 텍스트를 포맷팅 ([] 기준 줄바꿈, 해시태그 스타일링) +// 텍스트를 포맷팅 (개행 처리, 제목 스타일링, 해시태그 스타일링) const formatReportText = (text: string): React.ReactNode[] => { if (!text) return []; - // [제목] 패턴을 기준으로 분리 - const parts = text.split(/(\[[^\]]+\])/g).filter(Boolean); + // 먼저 \n으로 단락 분리 + const paragraphs = text.split('\n'); - return parts.map((part, idx) => { - // [제목] 패턴인 경우 - if (part.match(/^\[[^\]]+\]$/)) { - const title = part.slice(1, -1); // [] 제거 + return paragraphs.map((paragraph, pIdx) => { + // 빈 줄은 줄바꿈으로 처리 + if (paragraph.trim() === '') { + return
; + } + + // 제목 패턴 (한글로 된 짧은 텍스트로 시작하는 경우) + const titleMatch = paragraph.match(/^(타겟 고객|핵심 차별점|지역 특성|시즌별 포인트)$/); + if (titleMatch) { return ( - - {idx > 0 &&
} -
- [{title}] -
-
+
0 ? '16px' : '0' }}> + {paragraph} +
); } // 해시태그 처리 - const hashtagParts = part.split(/(#[^\s#]+)/g); + const hashtagParts = paragraph.split(/(#[^\s#]+)/g); return ( - +
{hashtagParts.map((segment, segIdx) => { if (segment.startsWith('#')) { return ( @@ -43,7 +45,7 @@ const formatReportText = (text: string): React.ReactNode[] => { } return segment; })} - +
); }); };