From f711998ce93cd847a3a15c34e6a82f35d46e9f73 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Tue, 2 Sep 2025 15:11:36 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B2=B9=EC=B9=A8=20=EB=A9=94=EB=89=B4?= =?UTF-8?q?=EC=97=90=20=EA=B0=81=20=EA=B8=B0=EB=8A=A5=EB=B3=84=20=EC=95=A1?= =?UTF-8?q?=EC=85=98=20=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 하이라이트: '메모 보기' 버튼으로 하이라이트 툴팁 표시 - 링크: '문서로 이동' 버튼으로 바로 연결된 문서로 이동 - 백링크: '원본으로 이동' 버튼으로 바로 원본 문서로 이동 - 각 항목에 '상세보기' 버튼으로 상세 정보 툴팁 표시 - 메뉴 UI 개선: 크기 확대, 아이콘 추가, 레이아웃 개선 - 링크/백링크 툴팁을 메모처럼 상세하게 개선 (날짜, 아이콘, 그라데이션) - 겹침 감지 로직 디버깅 및 안정화 --- .../static/js/viewer/features/link-manager.js | 266 ++++++++++++++---- 1 file changed, 219 insertions(+), 47 deletions(-) diff --git a/frontend/static/js/viewer/features/link-manager.js b/frontend/static/js/viewer/features/link-manager.js index b6c2036..67ea192 100644 --- a/frontend/static/js/viewer/features/link-manager.js +++ b/frontend/static/js/viewer/features/link-manager.js @@ -494,39 +494,77 @@ class LinkManager { const tooltip = document.createElement('div'); tooltip.id = 'link-tooltip'; - tooltip.className = 'absolute bg-white border border-gray-300 rounded-lg shadow-lg p-4 z-50 max-w-lg'; - tooltip.style.minWidth = '350px'; + tooltip.className = 'absolute bg-white border border-gray-300 rounded-lg shadow-lg p-5 z-50 max-w-2xl'; + tooltip.style.minWidth = '450px'; + tooltip.style.maxHeight = '80vh'; + tooltip.style.overflowY = 'auto'; + + // 생성 날짜 포맷팅 + const createdDate = link.created_at ? this.formatDate(link.created_at) : '알 수 없음'; const tooltipHTML = `
-
링크 정보
-
- "${link.selected_text}" +
+
+ + + + 링크 정보 +
+
${createdDate}
+
+ +
+
선택된 텍스트
+
"${link.selected_text}"
-
-
연결된 문서
-
-
${link.target_document_title}
- ${link.target_text ? `
대상 텍스트: "${link.target_text}"
` : ''} +
+
+ + + + 연결된 문서 +
+
+
${link.target_document_title}
+ ${link.target_text ? ` +
+
대상 텍스트
+
"${link.target_text}"
+
+ ` : ''} + ${link.description ? ` +
+
설명
+
${link.description}
+
+ ` : ''}
-
+
-
+
@@ -544,35 +582,67 @@ class LinkManager { const tooltip = document.createElement('div'); tooltip.id = 'backlink-tooltip'; - tooltip.className = 'absolute bg-white border border-gray-300 rounded-lg shadow-lg p-4 z-50 max-w-lg'; - tooltip.style.minWidth = '350px'; + tooltip.className = 'absolute bg-white border border-gray-300 rounded-lg shadow-lg p-5 z-50 max-w-2xl'; + tooltip.style.minWidth = '450px'; + tooltip.style.maxHeight = '80vh'; + tooltip.style.overflowY = 'auto'; + + // 생성 날짜 포맷팅 + const createdDate = backlink.created_at ? this.formatDate(backlink.created_at) : '알 수 없음'; const tooltipHTML = `
-
백링크 정보
-
- "${backlink.target_text || backlink.selected_text}" +
+
+ + + + 백링크 정보 +
+
${createdDate}
+
+ +
+
현재 문서의 텍스트
+
"${backlink.target_text || backlink.selected_text}"
-
-
참조 문서
-
-
${backlink.source_document_title}
-
원본 텍스트: "${backlink.selected_text}"
+
+
+ + + + 참조하는 문서 +
+
+
${backlink.source_document_title}
+
+
원본 텍스트
+
"${backlink.selected_text}"
+
+ ${backlink.description ? ` +
+
설명
+
${backlink.description}
+
+ ` : ''}
-
+
-
+
@@ -582,6 +652,32 @@ class LinkManager { this.positionTooltip(tooltip, element); } + /** + * 날짜 포맷팅 + */ + formatDate(dateString) { + if (!dateString) return '알 수 없음'; + + const date = new Date(dateString); + const now = new Date(); + const diffTime = Math.abs(now - date); + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); + + if (diffDays === 1) { + return '오늘'; + } else if (diffDays <= 7) { + return `${diffDays}일 전`; + } else if (diffDays <= 30) { + return `${Math.ceil(diffDays / 7)}주 전`; + } else { + return date.toLocaleDateString('ko-KR', { + year: 'numeric', + month: 'short', + day: 'numeric' + }); + } + } + /** * 툴팁 위치 설정 */ @@ -803,12 +899,18 @@ class LinkManager { const menu = document.createElement('div'); menu.id = 'overlap-menu'; - menu.className = 'absolute bg-white border border-gray-300 rounded-lg shadow-lg p-2 z-50'; - menu.style.minWidth = '200px'; + menu.className = 'absolute bg-white border border-gray-300 rounded-lg shadow-lg p-4 z-50'; + menu.style.minWidth = '320px'; + menu.style.maxWidth = '400px'; let menuHTML = ` -
여러 요소가 겹쳐있습니다
-
+
+ + + + 겹치는 요소들 +
+
`; // 클릭된 요소 추가 @@ -884,25 +986,95 @@ class LinkManager { const clickedClass = isClicked ? 'ring-2 ring-blue-300' : ''; const elementId = element.dataset.highlightId || element.dataset.linkId || element.dataset.backlinkId || ''; + + + // 각 타입별 액션 버튼들 + let actionButtons = ''; + if (type === 'highlight') { + actionButtons = ` +
+ +
+ `; + } else if (type === 'link') { + actionButtons = ` +
+ + +
+ `; + } else if (type === 'backlink') { + actionButtons = ` +
+ + +
+ `; + } + return ` - + ${actionButtons} +
`; } + /** + * 메뉴에서 바로 링크된 문서로 이동 + */ + navigateToLinkedDocumentFromMenu(elementId) { + this.hideTooltip(); + + const link = this.documentLinks.find(l => l.id === elementId); + if (link) { + this.navigateToLinkedDocument(link.target_document_id, link); + } else { + console.warn('링크 데이터를 찾을 수 없음:', elementId); + } + } + + /** + * 메뉴에서 바로 소스 문서로 이동 + */ + navigateToSourceDocumentFromMenu(elementId) { + this.hideTooltip(); + + const backlink = this.backlinks.find(b => b.id === elementId); + if (backlink) { + this.navigateToSourceDocument(backlink.source_document_id, backlink); + } else { + console.warn('백링크 데이터를 찾을 수 없음:', elementId); + } + } + /** * 겹침 메뉴 클릭 처리 */ handleOverlapMenuClick(type, elementId) { + this.hideTooltip(); // 해당 요소 찾기 @@ -913,20 +1085,19 @@ class LinkManager { // 하이라이트 클릭 처리 (HighlightManager에 위임) const highlightId = elementId; - // 해당 하이라이트 그룹 찾기 - const highlightGroups = window.documentViewerInstance.highlightManager.highlightGroups || []; - const targetGroup = highlightGroups.find(group => - group.some(h => h.id === highlightId) - ); + // 해당 하이라이트 찾기 + const highlight = window.documentViewerInstance.highlightManager.highlights.find(h => h.id === highlightId); - if (targetGroup) { - window.documentViewerInstance.highlightManager.showHighlightModal(targetGroup); + if (highlight) { + // 하이라이트 툴팁 표시 (메모 작성/편집 기능 포함) + window.documentViewerInstance.highlightManager.showHighlightTooltip(highlight, element); } else { - console.warn('하이라이트 그룹을 찾을 수 없음:', highlightId); + console.warn('하이라이트를 찾을 수 없음:', highlightId); } } } else if (type === 'link') { element = document.querySelector(`[data-link-id="${elementId}"]`); + if (element) { // 링크 데이터 찾기 const link = this.documentLinks.find(l => l.id === elementId); @@ -936,6 +1107,7 @@ class LinkManager { } } else if (type === 'backlink') { element = document.querySelector(`[data-backlink-id="${elementId}"]`); + if (element) { // 백링크 데이터 찾기 const backlink = this.backlinks.find(b => b.id === elementId);