🎨 데본씽크 스타일 통합 미리보기 완성

📱 PDF 미리보기 (PDF.js):
- 실제 PDF 렌더링 (Canvas 기반)
- 줌 인/아웃 (50% ~ 300%)
- 페이지 네비게이션 (이전/다음/직접입력)
- 고해상도 디스플레이 지원
- 검색어 위치로 뷰어 연동

📄 HTML 문서 미리보기:
- iframe 렌더링 뷰 / 소스 코드 뷰 토글
- 검색어 자동 하이라이트 (iframe 내부)
- 문법 하이라이트된 소스 코드 표시
- 안전한 sandbox 모드

📝 노트 문서 미리보기:
- 제목, 생성일시 표시
- 검색어 하이라이트
- 편집기에서 열기 버튼
- 깔끔한 카드 스타일 UI

🌳 메모 트리 노드 미리보기:
- 메모 제목과 내용 표시
- 트리 정보 (소속 트리명)
- 검색어 하이라이트
- 구조화된 레이아웃

🎯 UX 개선:
- 타입별 아이콘과 색상 구분
- ESC 키 / 배경 클릭으로 닫기
- 로딩 상태 표시
- 에러 처리 및 fallback
- 반응형 디자인
This commit is contained in:
Hyungi Ahn
2025-09-02 17:14:09 +09:00
parent 4b65d45584
commit 960ee84356
2 changed files with 418 additions and 16 deletions

View File

@@ -8,6 +8,9 @@
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- PDF.js 라이브러리 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<style>
[x-cloak] { display: none !important; }
@@ -456,7 +459,7 @@
<!-- 모달 내용 -->
<div class="p-6 overflow-y-auto max-h-[60vh]">
<!-- PDF 미리보기 -->
<!-- PDF 미리보기 (데본씽크 스타일) -->
<div x-show="previewResult?.type === 'document_content' && previewResult?.highlight_info?.has_pdf"
class="mb-4">
<div class="flex items-center justify-between mb-3">
@@ -464,26 +467,172 @@
<i class="fas fa-file-pdf mr-2 text-red-600"></i>PDF 미리보기
</div>
<div class="flex items-center space-x-2">
<button @click="zoomOut()"
class="px-2 py-1 bg-gray-600 text-white rounded text-xs hover:bg-gray-700">
<i class="fas fa-search-minus"></i>
</button>
<span class="text-xs text-gray-600" x-text="`${Math.round(pdfZoom * 100)}%`"></span>
<button @click="zoomIn()"
class="px-2 py-1 bg-gray-600 text-white rounded text-xs hover:bg-gray-700">
<i class="fas fa-search-plus"></i>
</button>
<button @click="searchInPdf()"
class="px-3 py-1 bg-blue-600 text-white rounded text-xs hover:bg-blue-700">
<i class="fas fa-search mr-1"></i>PDF에서 검색
</button>
</div>
</div>
<div class="border rounded-lg overflow-hidden bg-gray-100" style="height: 400px;">
<iframe :src="`/api/documents/${previewResult?.document_id}/pdf`"
class="w-full h-full"
x-show="!pdfError"
@error="pdfError = true">
<!-- PDF 뷰어 컨테이너 -->
<div class="border rounded-lg overflow-hidden bg-gray-100 relative" style="height: 500px;">
<!-- PDF.js 뷰어 -->
<div id="pdfViewerContainer" class="w-full h-full overflow-auto bg-gray-200">
<div x-show="pdfLoading" class="flex items-center justify-center h-full">
<div class="text-center">
<i class="fas fa-spinner fa-spin text-2xl text-gray-500 mb-2"></i>
<p class="text-gray-600">PDF를 로드하는 중...</p>
</div>
</div>
<canvas id="pdfCanvas"
x-show="!pdfLoading && !pdfError"
class="mx-auto shadow-lg"
style="display: block; margin: 20px auto;"></canvas>
<div x-show="pdfError" class="flex items-center justify-center h-full text-gray-500">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-2xl mb-2"></i>
<p>PDF를 로드할 수 없습니다</p>
<button @click="openResult(previewResult)"
class="mt-2 px-3 py-1 bg-blue-600 text-white rounded text-sm">
뷰어에서 열기
</button>
</div>
</div>
</div>
<!-- 페이지 네비게이션 -->
<div x-show="!pdfLoading && !pdfError && pdfTotalPages > 1"
class="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-75 text-white px-4 py-2 rounded-lg flex items-center space-x-3">
<button @click="prevPage()"
:disabled="pdfCurrentPage <= 1"
class="px-2 py-1 bg-gray-600 rounded text-xs hover:bg-gray-500 disabled:opacity-50 disabled:cursor-not-allowed">
<i class="fas fa-chevron-left"></i>
</button>
<span class="text-sm">
<input type="number"
x-model="pdfCurrentPage"
@change="goToPage(pdfCurrentPage)"
:min="1"
:max="pdfTotalPages"
class="w-12 text-center bg-transparent border-b border-gray-400 text-white text-xs">
/ <span x-text="pdfTotalPages"></span>
</span>
<button @click="nextPage()"
:disabled="pdfCurrentPage >= pdfTotalPages"
class="px-2 py-1 bg-gray-600 rounded text-xs hover:bg-gray-500 disabled:opacity-50 disabled:cursor-not-allowed">
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
</div>
<!-- HTML 문서 미리보기 -->
<div x-show="(previewResult?.type === 'document' || previewResult?.type === 'document_content') && !previewResult?.highlight_info?.has_pdf"
class="mb-4">
<div class="flex items-center justify-between mb-3">
<div class="text-sm font-medium text-gray-800">
<i class="fas fa-code mr-2 text-green-600"></i>HTML 문서 미리보기
</div>
<div class="flex items-center space-x-2">
<button @click="toggleHtmlRaw()"
class="px-3 py-1 bg-gray-600 text-white rounded text-xs hover:bg-gray-700">
<i class="fas fa-code mr-1"></i><span x-text="htmlRawMode ? '렌더링' : '소스'"></span>
</button>
</div>
</div>
<div class="border rounded-lg overflow-hidden bg-white relative" style="height: 500px;">
<!-- HTML 렌더링 뷰 -->
<iframe id="htmlPreviewFrame"
x-show="!htmlRawMode && !htmlLoading"
class="w-full h-full border-0"
sandbox="allow-same-origin">
</iframe>
<div x-show="pdfError" class="flex items-center justify-center h-full text-gray-500">
<!-- HTML 소스 뷰 -->
<div x-show="htmlRawMode && !htmlLoading"
class="w-full h-full overflow-auto p-4 bg-gray-900 text-green-400 font-mono text-sm">
<pre x-html="htmlSourceCode"></pre>
</div>
<!-- 로딩 상태 -->
<div x-show="htmlLoading" class="flex items-center justify-center h-full">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-2xl mb-2"></i>
<p>PDF를 로드할 수 없습니다</p>
<button @click="openResult(previewResult)"
class="mt-2 px-3 py-1 bg-blue-600 text-white rounded text-sm">
뷰어에서 열기
</button>
<i class="fas fa-spinner fa-spin text-2xl text-gray-500 mb-2"></i>
<p class="text-gray-600">HTML을 로드하는 중...</p>
</div>
</div>
</div>
</div>
<!-- 메모 트리 노드 미리보기 -->
<div x-show="previewResult?.type === 'memo'"
class="mb-4">
<div class="flex items-center justify-between mb-3">
<div class="text-sm font-medium text-gray-800">
<i class="fas fa-tree mr-2 text-purple-600"></i>메모 노드 미리보기
</div>
<div class="flex items-center space-x-2">
<span class="text-xs text-gray-600" x-text="previewResult?.document_title"></span>
</div>
</div>
<div class="border rounded-lg overflow-hidden bg-white" style="height: 400px;">
<div class="h-full overflow-auto p-6">
<!-- 메모 제목 -->
<h3 class="text-xl font-bold text-gray-900 mb-4" x-text="previewResult?.title"></h3>
<!-- 메모 내용 -->
<div class="prose max-w-none">
<div class="text-gray-700 leading-relaxed whitespace-pre-wrap"
x-html="highlightText(previewResult?.content || '', searchQuery)"></div>
</div>
</div>
</div>
</div>
<!-- 노트 문서 미리보기 -->
<div x-show="previewResult?.type === 'note'"
class="mb-4">
<div class="flex items-center justify-between mb-3">
<div class="text-sm font-medium text-gray-800">
<i class="fas fa-sticky-note mr-2 text-blue-600"></i>노트 미리보기
</div>
<div class="flex items-center space-x-2">
<button @click="toggleNoteEdit()"
class="px-3 py-1 bg-blue-600 text-white rounded text-xs hover:bg-blue-700">
<i class="fas fa-edit mr-1"></i>편집기에서 열기
</button>
</div>
</div>
<div class="border rounded-lg overflow-hidden bg-white" style="height: 450px;">
<div class="h-full overflow-auto">
<!-- 노트 헤더 -->
<div class="p-4 border-b bg-gray-50">
<h3 class="text-lg font-semibold text-gray-900" x-text="previewResult?.title"></h3>
<div class="text-sm text-gray-600 mt-1">
<span x-text="formatDate(previewResult?.created_at)"></span>
</div>
</div>
<!-- 노트 내용 -->
<div class="p-6">
<div class="prose max-w-none">
<div class="text-gray-700 leading-relaxed"
x-html="highlightText(previewResult?.content || '', searchQuery)"></div>
</div>
</div>
</div>
</div>