Files
document-server/frontend/viewer.html
Hyungi Ahn 43e7466195 스토리 뷰 페이지 헤더 z-index 충돌 문제 해결
- 메인 컨테이너 padding-top을 pt-4에서 pt-20으로 증가
- 드롭다운 z-index를 z-[60]으로 설정하여 헤더보다 높은 우선순위 부여
- 스토리 선택 드롭다운이 정상적으로 작동하도록 수정
- 디버깅용 코드 정리
2025-09-04 10:22:43 +09:00

1131 lines
69 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>문서 뷰어 - Document Server</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📄</text></svg>">
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script>
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/viewer.css">
</head>
<body class="bg-gray-50 min-h-screen">
<!-- 인증 확인 및 리다이렉트 -->
<script>
// 페이지 로드 시 인증 상태 확인
(function() {
const token = localStorage.getItem('access_token');
if (!token) {
console.log('🔐 인증 토큰이 없습니다. 메인 페이지로 리다이렉트합니다.');
window.location.href = '/';
return;
}
console.log('✅ 인증 토큰 확인됨:', token.substring(0, 20) + '...');
})();
</script>
<div x-data="documentViewer" x-init="init(); $store.documentViewer.init()">
<!-- 헤더 - 투명하고 세련된 3줄 디자인 -->
<header class="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-50 w-full">
<div class="w-full px-6 py-4">
<!-- 첫 번째 줄: 네비게이션 + 제목 -->
<div class="flex items-center justify-between mb-2">
<!-- 왼쪽: 네비게이션 -->
<div class="flex items-center space-x-3">
<!-- 뒤로가기 -->
<button @click="goBack" class="w-9 h-9 bg-white/60 hover:bg-white/80 rounded-xl flex items-center justify-center transition-all duration-200 text-gray-700 hover:text-gray-900 shadow-sm">
<i class="fas fa-arrow-left text-sm"></i>
</button>
<!-- 서적 네비게이션 -->
<div x-show="navigation" class="flex items-center space-x-2">
<button @click="navigateToDocument(navigation?.previous?.id)"
x-show="navigation?.previous"
:title="navigation?.previous ? `이전: ${navigation.previous.title}` : ''"
class="w-8 h-8 bg-blue-500/20 hover:bg-blue-500/30 rounded-lg flex items-center justify-center transition-all duration-200 text-blue-700">
<i class="fas fa-chevron-left text-xs"></i>
</button>
<button @click="goToBookContents()"
x-show="navigation?.book_info"
:title="navigation?.book_info ? `목차: ${navigation.book_info.title}` : ''"
class="w-8 h-8 bg-green-500/20 hover:bg-green-500/30 rounded-lg flex items-center justify-center transition-all duration-200 text-green-700">
<i class="fas fa-list text-xs"></i>
</button>
<button @click="navigateToDocument(navigation?.next?.id)"
x-show="navigation?.next"
:title="navigation?.next ? `다음: ${navigation.next.title}` : ''"
class="w-8 h-8 bg-blue-500/20 hover:bg-blue-500/30 rounded-lg flex items-center justify-center transition-all duration-200 text-blue-700">
<i class="fas fa-chevron-right text-xs"></i>
</button>
</div>
</div>
<!-- 중앙: 문서 제목 -->
<div class="flex-1 text-center">
<h1 class="text-xl font-bold text-gray-800" x-text="document?.title || '로딩 중...'"></h1>
</div>
<!-- 오른쪽: 검색 -->
<div class="flex items-center">
<div class="relative">
<input type="text" x-model="searchQuery" @input="searchInDocument"
placeholder="검색..."
class="w-60 pl-9 pr-3 py-2 bg-white/50 border border-white/30 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-400/50 focus:bg-white/70 shadow-sm transition-all duration-200 text-sm">
<i class="fas fa-search absolute left-3 top-2.5 text-gray-500 text-xs"></i>
</div>
</div>
</div>
<!-- 두 번째 줄: 문서 정보 -->
<div x-show="document" class="flex items-center justify-between text-sm text-gray-600 mb-3 px-2">
<!-- 왼쪽: 업로더 정보 -->
<div class="flex items-center space-x-4">
<span class="flex items-center space-x-1">
<i class="fas fa-user text-xs"></i>
<span x-text="document?.uploader_name"></span>
</span>
<span x-show="navigation?.book_info" class="flex items-center space-x-1">
<i class="fas fa-book text-xs"></i>
<span x-text="navigation?.book_info?.title"></span>
</span>
</div>
<!-- 오른쪽: 문서 통계 -->
<div class="flex items-center space-x-4">
<span x-show="notes.length > 0" class="flex items-center space-x-1">
<i class="fas fa-sticky-note text-xs text-blue-500"></i>
<span x-text="`메모 ${notes.length}개`"></span>
</span>
<span x-show="bookmarks.length > 0" class="flex items-center space-x-1">
<i class="fas fa-bookmark text-xs text-amber-500"></i>
<span x-text="`책갈피 ${bookmarks.length}개`"></span>
</span>
<span x-show="documentLinks.length > 0" class="flex items-center space-x-1">
<i class="fas fa-link text-xs text-purple-500"></i>
<span x-text="`링크 ${documentLinks.length}개`"></span>
</span>
</div>
</div>
<!-- 세 번째 줄: 도구 모음 -->
<div class="flex items-center justify-between">
<!-- 왼쪽: 하이라이트 색상 -->
<div class="flex items-center space-x-1 bg-white/50 rounded-xl shadow-sm border border-white/30 px-3 py-2">
<span class="text-xs font-medium text-gray-600 mr-2">하이라이트</span>
<button @click="createHighlightWithColor('#FFFF00')"
:class="selectedHighlightColor === '#FFFF00' ? 'ring-2 ring-yellow-400 scale-110' : 'hover:scale-110'"
class="w-6 h-6 bg-gradient-to-br from-yellow-300 to-yellow-400 rounded-full border border-white shadow-sm transition-all duration-200"
title="노란색"></button>
<button @click="createHighlightWithColor('#90EE90')"
:class="selectedHighlightColor === '#90EE90' ? 'ring-2 ring-green-400 scale-110' : 'hover:scale-110'"
class="w-6 h-6 bg-gradient-to-br from-green-300 to-green-400 rounded-full border border-white shadow-sm transition-all duration-200"
title="초록색"></button>
<button @click="createHighlightWithColor('#FFCCCB')"
:class="selectedHighlightColor === '#FFCCCB' ? 'ring-2 ring-pink-400 scale-110' : 'hover:scale-110'"
class="w-6 h-6 bg-gradient-to-br from-pink-200 to-pink-300 rounded-full border border-white shadow-sm transition-all duration-200"
title="분홍색"></button>
<button @click="createHighlightWithColor('#87CEEB')"
:class="selectedHighlightColor === '#87CEEB' ? 'ring-2 ring-blue-400 scale-110' : 'hover:scale-110'"
class="w-6 h-6 bg-gradient-to-br from-blue-300 to-blue-400 rounded-full border border-white shadow-sm transition-all duration-200"
title="파란색"></button>
</div>
<!-- 중앙: 기능 버튼들 -->
<div class="flex items-center space-x-3">
<!-- 링크 버튼 - 드래그 후 클릭으로 링크 생성 -->
<button @click="activateLinkMode()"
:class="activeMode === 'link' ? 'bg-purple-600' : 'bg-purple-500/80 hover:bg-purple-500'"
class="px-4 py-2 text-white rounded-xl transition-all duration-200 flex items-center space-x-2 shadow-sm"
title="텍스트를 드래그한 후 이 버튼을 클릭하여 링크를 생성하세요">
<i class="fas fa-link text-sm"></i>
<span class="text-sm font-medium">링크</span>
<span x-show="documentLinks.length > 0"
class="bg-white text-purple-600 text-xs rounded-full w-5 h-5 flex items-center justify-center font-bold"
x-text="documentLinks.length"></span>
</button>
<!-- 백링크 표시 (읽기 전용) -->
<div class="px-4 py-2 bg-orange-500/80 text-white rounded-xl flex items-center space-x-2 shadow-sm"
title="이 문서를 참조하는 다른 문서들">
<i class="fas fa-arrow-left text-sm"></i>
<span class="text-sm font-medium">백링크</span>
<span x-show="backlinks.length > 0"
class="bg-white text-orange-600 text-xs rounded-full w-5 h-5 flex items-center justify-center font-bold"
x-text="backlinks.length"></span>
</div>
<!-- 메모 버튼 그룹 -->
<div class="relative">
<button @click="toggleFeatureMenu('memo')"
:class="activeFeatureMenu === 'memo' ? 'bg-blue-600' : 'bg-blue-500/80 hover:bg-blue-500'"
class="px-4 py-2 text-white rounded-xl transition-all duration-200 flex items-center space-x-2 shadow-sm">
<i class="fas fa-sticky-note text-sm"></i>
<span class="text-sm font-medium">메모</span>
<span x-show="notes.length > 0"
class="bg-white text-blue-600 text-xs rounded-full w-5 h-5 flex items-center justify-center font-bold"
x-text="notes.length"></span>
<i class="fas fa-chevron-down text-xs ml-1" :class="activeFeatureMenu === 'memo' ? 'rotate-180' : ''"></i>
</button>
<!-- 메모 서브메뉴 -->
<div x-show="activeFeatureMenu === 'memo'"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute top-full left-0 mt-2 bg-white/90 backdrop-blur-md rounded-xl shadow-lg border border-white/30 p-2 z-10 min-w-max">
<button @click="showNotesModal = true; activeFeatureMenu = null"
class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-blue-100 rounded-lg flex items-center space-x-2 transition-colors">
<i class="fas fa-eye text-blue-500"></i>
<span>메모 보기</span>
</button>
<button @click="activateNoteMode(); activeFeatureMenu = null"
class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-green-100 rounded-lg flex items-center space-x-2 transition-colors">
<i class="fas fa-plus text-green-500"></i>
<span>메모 만들기</span>
</button>
</div>
</div>
<!-- 책갈피 버튼 그룹 -->
<div class="relative">
<button @click="toggleFeatureMenu('bookmark')"
:class="activeFeatureMenu === 'bookmark' ? 'bg-amber-600' : 'bg-amber-500/80 hover:bg-amber-500'"
class="px-4 py-2 text-white rounded-xl transition-all duration-200 flex items-center space-x-2 shadow-sm">
<i class="fas fa-bookmark text-sm"></i>
<span class="text-sm font-medium">책갈피</span>
<span x-show="bookmarks.length > 0"
class="bg-white text-amber-600 text-xs rounded-full w-5 h-5 flex items-center justify-center font-bold"
x-text="bookmarks.length"></span>
<i class="fas fa-chevron-down text-xs ml-1" :class="activeFeatureMenu === 'bookmark' ? 'rotate-180' : ''"></i>
</button>
<!-- 책갈피 서브메뉴 -->
<div x-show="activeFeatureMenu === 'bookmark'"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute top-full left-0 mt-2 bg-white/90 backdrop-blur-md rounded-xl shadow-lg border border-white/30 p-2 z-10 min-w-max">
<button @click="showBookmarksModal = true; activeFeatureMenu = null"
class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-amber-100 rounded-lg flex items-center space-x-2 transition-colors">
<i class="fas fa-eye text-amber-500"></i>
<span>책갈피 보기</span>
</button>
<button @click="console.log('책갈피 만들기 클릭됨'); activateBookmarkMode(); activeFeatureMenu = null"
class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-amber-100 rounded-lg flex items-center space-x-2 transition-colors">
<i class="fas fa-plus text-amber-500"></i>
<span>책갈피 만들기</span>
</button>
</div>
</div>
</div>
<!-- 오른쪽: 액션 버튼들 -->
<div class="flex items-center space-x-3">
<button @click="$store.documentViewer.downloadOriginalFile()"
class="bg-red-500/80 hover:bg-red-500 text-white px-4 py-2 rounded-xl transition-all duration-200 flex items-center space-x-2 shadow-sm"
title="원본 PDF 다운로드">
<i class="fas fa-file-pdf text-sm"></i>
<span class="text-sm font-medium">PDF</span>
</button>
<button @click="$store.documentViewer.toggleLanguage()"
class="bg-blue-500/80 hover:bg-blue-500 text-white px-4 py-2 rounded-xl transition-all duration-200 flex items-center space-x-2 shadow-sm"
id="language-toggle-btn">
<i class="fas fa-globe text-sm"></i>
<span class="text-sm font-medium">언어전환</span>
</button>
</div>
</div>
</div>
</header>
<!-- 메인 컨텐츠 -->
<div class="flex w-full min-h-screen">
<!-- 문서 뷰어 -->
<main class="flex-1 bg-white">
<div class="px-12 py-8 max-w-5xl mx-auto">
<!-- 로딩 상태 -->
<div x-show="loading" class="text-center py-16">
<i class="fas fa-spinner fa-spin text-4xl text-gray-400 mb-4"></i>
<p class="text-gray-600">문서를 불러오는 중...</p>
</div>
<!-- 에러 상태 -->
<div x-show="error" class="text-center py-16">
<i class="fas fa-exclamation-triangle text-4xl text-red-400 mb-4"></i>
<p class="text-red-600" x-text="error"></p>
<button @click="goBack" class="mt-4 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700">
돌아가기
</button>
</div>
<!-- 문서 내용 -->
<div x-show="!loading && !error">
<!-- HTML 문서 내용 -->
<div x-show="contentType === 'document' && document && !document.pdf_path"
id="document-content" class="prose max-w-none">
<!-- 문서 HTML이 여기에 로드됩니다 -->
</div>
<!-- PDF 뷰어 -->
<div x-show="contentType === 'document' && document && document.pdf_path"
class="pdf-viewer-container">
<div class="mb-4 flex items-center justify-between">
<div class="flex items-center space-x-3">
<i class="fas fa-file-pdf text-red-600 text-xl"></i>
<h1 class="text-2xl font-bold text-gray-900" x-text="document?.title"></h1>
</div>
<div class="flex items-center space-x-2">
<button @click="openPdfSearchModal()"
class="px-3 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors flex items-center space-x-2">
<i class="fas fa-search"></i>
<span>PDF에서 검색</span>
</button>
<button @click="downloadOriginalFile()"
class="px-3 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center space-x-2">
<i class="fas fa-download"></i>
<span>다운로드</span>
</button>
</div>
</div>
<!-- PDF 뷰어 컨테이너 -->
<div class="border rounded-lg overflow-hidden bg-white relative" style="min-height: 800px;">
<!-- PDF.js 뷰어 -->
<div x-show="!pdfError && !pdfLoading && pdfSrc" class="w-full h-full">
<!-- PDF 뷰어 툴바 -->
<div class="bg-gray-100 border-b px-4 py-2 flex items-center justify-between">
<div class="flex items-center space-x-4">
<button @click="previousPage()" :disabled="currentPage <= 1"
class="px-3 py-1 bg-blue-600 text-white rounded disabled:bg-gray-300">
<i class="fas fa-chevron-left"></i>
</button>
<span class="text-sm">
<input type="number" x-model="currentPage" @change="goToPage(currentPage)"
class="w-16 px-2 py-1 border rounded text-center" min="1" :max="totalPages">
/ <span x-text="totalPages"></span>
</span>
<button @click="nextPage()" :disabled="currentPage >= totalPages"
class="px-3 py-1 bg-blue-600 text-white rounded disabled:bg-gray-300">
<i class="fas fa-chevron-right"></i>
</button>
</div>
<div class="flex items-center space-x-2">
<button @click="zoomOut()" class="px-2 py-1 bg-gray-600 text-white rounded">
<i class="fas fa-search-minus"></i>
</button>
<span class="text-sm" x-text="Math.round(pdfScale * 100) + '%'"></span>
<button @click="zoomIn()" class="px-2 py-1 bg-gray-600 text-white rounded">
<i class="fas fa-search-plus"></i>
</button>
</div>
</div>
<!-- PDF 캔버스 -->
<div class="overflow-auto" style="height: 750px;">
<canvas id="pdf-canvas" class="mx-auto block"></canvas>
</div>
</div>
<!-- 기존 iframe (폴백용) -->
<iframe id="pdf-viewer-iframe"
x-show="false"
class="w-full border-0"
style="height: 800px;"
:src="pdfSrc"
@load="pdfLoaded = true; console.log('PDF iframe 로드 완료')"
@error="handlePdfError()"
allow="fullscreen">
</iframe>
<!-- PDF 로딩 상태 -->
<div x-show="pdfLoading" class="flex items-center justify-center h-full" style="min-height: 400px;">
<div class="text-center">
<i class="fas fa-spinner fa-spin text-3xl text-gray-500 mb-4"></i>
<p class="text-gray-600 text-lg">PDF를 로드하는 중...</p>
</div>
</div>
<!-- PDF 에러 상태 -->
<div x-show="pdfError" class="flex items-center justify-center h-full text-gray-500" style="min-height: 400px;">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-3xl mb-4 text-red-500"></i>
<p class="text-lg mb-4">PDF를 로드할 수 없습니다</p>
<button @click="retryPdfLoad()"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 mr-2">
다시 시도
</button>
<button @click="downloadOriginalFile()"
class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700">
파일 다운로드
</button>
</div>
</div>
</div>
</div>
<!-- 노트 문서 내용 -->
<div x-show="contentType === 'note'"
id="note-content" class="prose max-w-none">
<!-- 노트 내용이 여기에 로드됩니다 -->
</div>
</div>
</div>
</main>
</div>
<!-- PDF 검색 모달 -->
<div x-show="showPdfSearchModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click.self="showPdfSearchModal = false">
<div class="bg-white rounded-2xl shadow-2xl max-w-md w-full">
<!-- 헤더 -->
<div class="flex items-center justify-between p-6 border-b border-gray-200">
<h3 class="text-xl font-bold text-gray-900 flex items-center space-x-2">
<i class="fas fa-search text-green-600"></i>
<span>PDF에서 검색</span>
</h3>
<button @click="showPdfSearchModal = false"
class="text-gray-400 hover:text-gray-600 transition-colors">
<i class="fas fa-times text-xl"></i>
</button>
</div>
<!-- 내용 -->
<div class="p-6">
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">검색어</label>
<div class="relative">
<input type="text"
x-model="pdfSearchQuery"
@keydown.enter="searchInPdf()"
@input="pdfSearchResults = []"
placeholder="예: pressure, vessel, design..."
class="w-full px-3 py-2 pr-10 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-transparent"
x-ref="searchInput">
<div class="absolute inset-y-0 right-0 pr-3 flex items-center">
<i class="fas fa-search text-gray-400"></i>
</div>
</div>
<div class="mt-1 text-xs text-gray-500">
Enter 키를 누르거나 검색 버튼을 클릭하세요
</div>
</div>
<!-- 검색 결과 -->
<div x-show="pdfSearchResults.length > 0" class="mb-4">
<div class="text-sm text-gray-600 mb-2">
<i class="fas fa-check-circle text-green-500 mr-1"></i>
<span x-text="pdfSearchResults.length"></span>개의 결과를 찾았습니다.
</div>
<div class="max-h-40 overflow-y-auto space-y-2">
<template x-for="(result, index) in pdfSearchResults" :key="index">
<div class="p-3 bg-gray-50 rounded cursor-pointer hover:bg-green-50 border hover:border-green-200 transition-colors"
@click="jumpToPdfResult(result)">
<div class="text-sm font-medium text-green-700">
<i class="fas fa-file-pdf mr-1"></i>
페이지 <span x-text="result.page"></span>
</div>
<div class="text-xs text-gray-600 mt-1" x-text="result.context"></div>
</div>
</template>
</div>
</div>
<!-- 검색 결과 없음 -->
<div x-show="pdfSearchQuery.trim() && !pdfSearchLoading && pdfSearchResults.length === 0" class="mb-4">
<div class="text-center py-4 text-gray-500">
<i class="fas fa-search text-2xl mb-2"></i>
<p class="text-sm">검색 결과가 없습니다.</p>
<p class="text-xs mt-1">다른 검색어로 시도해보세요.</p>
</div>
</div>
<!-- 버튼 -->
<div class="flex space-x-3">
<button @click="searchInPdf()"
:disabled="!pdfSearchQuery.trim() || pdfSearchLoading"
class="flex-1 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:bg-gray-300 disabled:cursor-not-allowed transition-colors">
<i :class="pdfSearchLoading ? 'fas fa-spinner fa-spin' : 'fas fa-search'" class="mr-2"></i>
<span x-text="pdfSearchLoading ? '검색 중...' : '검색'"></span>
</button>
<button @click="showPdfSearchModal = false"
class="px-4 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400 transition-colors">
닫기
</button>
</div>
</div>
</div>
</div>
<!-- 링크 모달 -->
<div x-show="showLinksModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click.self="showLinksModal = false">
<div class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
<!-- 헤더 -->
<div class="flex items-center justify-between p-6 border-b border-gray-200">
<h3 class="text-xl font-bold text-gray-900 flex items-center space-x-2">
<i class="fas fa-link text-purple-500"></i>
<span>링크</span>
</h3>
<button @click="showLinksModal = false"
class="w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-lg flex items-center justify-center transition-colors">
<i class="fas fa-times text-gray-600"></i>
</button>
</div>
<!-- 내용 -->
<div class="p-6 overflow-y-auto max-h-96">
<!-- 빈 상태 -->
<template x-if="documentLinks.length === 0">
<div class="text-center py-8">
<i class="fas fa-link text-4xl text-gray-300 mb-4"></i>
<p class="text-gray-500">아직 링크가 없습니다.</p>
<p class="text-sm text-gray-400 mt-2">텍스트를 선택하고 링크를 만들어보세요.</p>
</div>
</template>
<!-- 링크 목록 -->
<template x-for="link in documentLinks" :key="link.id">
<div class="border rounded-lg p-4 mb-3 hover:bg-purple-50 cursor-pointer transition-colors"
@click="navigateToLink(link)">
<div class="flex items-start justify-between">
<div class="flex-1">
<!-- 대상 문서 제목 -->
<div class="font-medium text-purple-700 mb-2 flex items-center">
<span x-text="link.target_document_title || link.target_note_title"></span>
<span x-show="link.target_content_type === 'note'" class="ml-2 text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded">노트</span>
<span x-show="link.target_content_type === 'document'" class="ml-2 text-xs bg-green-100 text-green-700 px-2 py-1 rounded">문서</span>
</div>
<!-- 현재 문서에서 선택한 텍스트 (출발점) -->
<div x-show="link.selected_text" class="mb-3">
<div class="text-xs text-gray-500 mb-1">📍 현재 문서에서 선택한 텍스트:</div>
<div class="text-sm text-gray-700 bg-purple-50 px-3 py-2 rounded border-l-4 border-purple-500" x-text="link.selected_text"></div>
</div>
<!-- 대상 문서의 텍스트 (도착점) -->
<div x-show="link.target_text" class="mb-3">
<div class="text-xs text-gray-500 mb-1">🎯 대상 문서의 텍스트:</div>
<div class="text-sm text-gray-700 bg-blue-50 px-3 py-2 rounded border-l-4 border-blue-500" x-text="link.target_text"></div>
</div>
<!-- 문서 전체 링크인 경우 -->
<div x-show="!link.selected_text && !link.target_text" class="mb-3">
<div class="text-sm text-gray-600 italic bg-gray-50 px-3 py-2 rounded">📄 문서 전체 링크</div>
</div>
<!-- 설명 -->
<div x-show="link.description" class="mb-3">
<div class="text-xs text-gray-500 mb-1">💬 설명:</div>
<div class="text-sm text-gray-600 bg-yellow-50 px-3 py-2 rounded" x-text="link.description"></div>
</div>
<!-- 링크 타입과 날짜 -->
<div class="flex items-center justify-between text-xs text-gray-500">
<span x-text="link.link_type === 'text_fragment' ? '🔗 텍스트 조각 링크' : '📄 문서 링크'"></span>
<span x-text="formatDate(link.created_at)"></span>
</div>
</div>
<div class="ml-3 flex-shrink-0">
<svg class="w-5 h-5 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
</svg>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
<!-- 링크 생성 모달 -->
<div x-show="showLinkModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click.self="closeLinkModal()">
<div class="bg-white rounded-2xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col">
<!-- 헤더 -->
<div class="flex items-center justify-between p-6 border-b border-gray-200">
<h3 class="text-xl font-bold text-gray-900 flex items-center space-x-2">
<i class="fas fa-link text-purple-500"></i>
<span>링크 생성</span>
</h3>
<button @click="closeLinkModal()"
class="w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-lg flex items-center justify-center transition-colors">
<i class="fas fa-times text-gray-600"></i>
</button>
</div>
<!-- 내용 -->
<div class="flex-1 overflow-y-auto p-6">
<!-- 선택된 텍스트 표시 -->
<div class="bg-purple-50 rounded-lg p-4 mb-6">
<h4 class="font-semibold text-purple-800 mb-2">선택된 텍스트</h4>
<p class="text-purple-700" x-text="linkForm?.selected_text || ''"></p>
</div>
<!-- 링크 대상 타입 선택 -->
<div class="mb-6">
<label class="block text-sm font-semibold text-gray-700 mb-3">링크 대상 타입</label>
<div class="flex space-x-4">
<label class="flex items-center">
<input type="radio"
x-model="linkForm.target_type"
value="document"
@change="onTargetTypeChange()"
class="mr-2 text-blue-600">
<span class="text-sm text-gray-700">📄 서적 문서</span>
</label>
<label class="flex items-center">
<input type="radio"
x-model="linkForm.target_type"
value="note"
@change="onTargetTypeChange()"
class="mr-2 text-blue-600">
<span class="text-sm text-gray-700">📝 노트북 노트</span>
</label>
</div>
</div>
<!-- 서적/노트북 선택 -->
<div class="mb-6" x-show="linkForm.target_type">
<label class="block text-sm font-semibold text-gray-700 mb-3"
x-text="linkForm.target_type === 'note' ? '노트북 선택' : '서적 선택'"></label>
<select
x-model="linkForm.target_book_id"
@change="loadDocumentsFromBook()"
class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white"
>
<option value="" x-text="linkForm.target_type === 'note' ? '노트북을 선택하세요' : '서적을 선택하세요'"></option>
<template x-for="book in availableBooks" :key="book.id">
<option :value="book.id" x-text="book.title"></option>
</template>
</select>
</div>
<!-- 대상 문서 선택 -->
<div class="mb-6">
<label class="block text-sm font-semibold text-gray-700 mb-2">
대상 문서
<span x-show="linkForm.target_book_id" class="text-blue-600 text-xs" x-text="`(${getSelectedBookTitle()})`"></span>
</label>
<select x-model="linkForm.target_document_id"
@change="onTargetDocumentChange()"
:disabled="!linkForm.target_book_id"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 disabled:bg-gray-100 disabled:cursor-not-allowed">
<option value="">
<span x-show="!linkForm.target_book_id"
x-text="linkForm.target_type === 'note' ? '먼저 노트북을 선택하세요' : '먼저 서적을 선택하세요'"></span>
<span x-show="linkForm.target_book_id"
x-text="linkForm.target_type === 'note' ? '노트를 선택하세요' : '문서를 선택하세요'"></span>
</option>
<template x-for="doc in filteredDocuments" :key="doc.id">
<option :value="doc.id" x-text="doc.title"></option>
</template>
</select>
<p x-show="filteredDocuments.length > 0" class="text-xs text-gray-500 mt-1" x-text="`${filteredDocuments.length}개 문서`"></p>
</div>
<!-- 대상 텍스트 선택 (무조건 텍스트 선택만 지원) -->
<div class="mb-6">
<label class="block text-sm font-semibold text-gray-700 mb-2">대상 텍스트</label>
<div class="space-y-3">
<button @click="selectTextFromDocument()"
:disabled="!linkForm.target_document_id"
:class="linkForm.target_document_id ? 'bg-blue-500 hover:bg-blue-600 text-white' : 'bg-gray-300 text-gray-500 cursor-not-allowed'"
class="w-full px-4 py-2 rounded-lg transition-colors flex items-center justify-center space-x-2">
<i class="fas fa-crosshairs"></i>
<span>대상 문서에서 텍스트 선택</span>
</button>
<div x-show="linkForm.target_text" class="bg-blue-50 rounded-lg p-3">
<p class="text-sm text-blue-800 font-medium">선택된 대상 텍스트:</p>
<p class="text-blue-700 mt-1" x-text="linkForm.target_text"></p>
</div>
</div>
</div>
<!-- 링크 설명 -->
<div class="mb-6">
<label class="block text-sm font-semibold text-gray-700 mb-2">설명 (선택사항)</label>
<textarea x-model="linkForm.description"
placeholder="링크에 대한 설명을 입력하세요..."
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 resize-none"
rows="3"></textarea>
</div>
</div>
<!-- 버튼 영역 (고정) -->
<div class="border-t border-gray-200 p-6">
<div class="flex justify-end space-x-3">
<button @click="closeLinkModal()"
class="px-4 py-2 text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors">
취소
</button>
<button @click="createDocumentLink()"
:disabled="!linkForm?.target_document_id"
:class="linkForm?.target_document_id ? 'bg-purple-500 hover:bg-purple-600' : 'bg-gray-300 cursor-not-allowed'"
class="px-4 py-2 text-white rounded-lg transition-colors">
링크 생성
</button>
</div>
</div>
</div>
</div>
<!-- 메모 모달 -->
<div x-show="showNotesModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click="showNotesModal = false">
<div @click.stop class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
<div class="flex justify-between items-center p-6 border-b">
<h3 class="text-xl font-bold text-gray-800 flex items-center space-x-2">
<i class="fas fa-sticky-note text-blue-600"></i>
<span>메모</span>
</h3>
<button @click="showNotesModal = false"
class="w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-full flex items-center justify-center transition-colors">
<i class="fas fa-times text-gray-600"></i>
</button>
</div>
<div class="p-6 overflow-y-auto max-h-96">
<!-- 메모가 없을 때 -->
<template x-if="notes.length === 0">
<div class="text-center text-gray-500">
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-sticky-note text-2xl text-blue-500"></i>
</div>
<h4 class="font-semibold text-gray-700 mb-2">메모가 없습니다</h4>
<p class="text-sm text-gray-500">텍스트를 선택하고 메모를 추가해보세요</p>
</div>
</template>
<!-- 메모 목록 -->
<div class="space-y-3">
<template x-for="note in notes" :key="note.id">
<div class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors cursor-pointer"
@click="scrollToHighlight(note.highlight.id)">
<!-- 선택된 텍스트 -->
<div class="bg-blue-50 rounded-md p-2 mb-3" x-show="note.highlight?.selected_text">
<p class="text-sm text-blue-800 font-medium" x-text="note.highlight?.selected_text || ''"></p>
</div>
<!-- 메모 내용 -->
<p class="text-gray-800 mb-2 leading-relaxed" x-text="note.content"></p>
<!-- 날짜 -->
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500" x-text="formatDate(note.created_at)"></span>
<div class="flex space-x-1">
<button @click.stop="editNote(note)"
class="w-6 h-6 bg-blue-100 text-blue-600 rounded-md hover:bg-blue-200 flex items-center justify-center transition-colors">
<i class="fas fa-edit text-xs"></i>
</button>
<button @click.stop="deleteNote(note.id)"
class="w-6 h-6 bg-red-100 text-red-600 rounded-md hover:bg-red-200 flex items-center justify-center transition-colors">
<i class="fas fa-trash text-xs"></i>
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
<!-- 메모 입력 모달 (하이라이트 생성 후) -->
<div x-show="showNoteInputModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click="showNoteInputModal = false">
<div @click.stop class="bg-white rounded-2xl shadow-2xl max-w-md w-full">
<div class="flex justify-between items-center p-6 border-b">
<h3 class="text-xl font-bold text-gray-800 flex items-center space-x-2">
<i class="fas fa-sticky-note text-blue-600"></i>
<span>메모 추가</span>
</h3>
<button @click="showNoteInputModal = false"
class="w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-full flex items-center justify-center transition-colors">
<i class="fas fa-times text-gray-600"></i>
</button>
</div>
<div class="p-6">
<!-- 선택된 텍스트 표시 -->
<div class="bg-blue-50 rounded-lg p-3 mb-4">
<p class="text-sm text-gray-600 mb-1">선택된 텍스트:</p>
<p class="text-blue-800 font-medium" x-text="selectedText"></p>
</div>
<!-- 메모 입력 질문 -->
<p class="text-gray-700 mb-4">이 하이라이트에 메모를 추가하시겠습니까?</p>
<!-- 메모 입력 칸 -->
<textarea x-model="noteForm.content"
placeholder="메모 내용을 입력하세요..."
class="w-full h-32 p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none"
@keydown.ctrl.enter="createNoteForHighlight()"
@keydown.meta.enter="createNoteForHighlight()"></textarea>
<!-- 태그 입력 (선택사항) -->
<input x-model="noteForm.tags"
type="text"
placeholder="태그 (선택사항, 쉼표로 구분)"
class="w-full mt-3 p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<!-- 버튼들 -->
<div class="flex justify-end space-x-3 mt-6">
<button @click="skipNoteForHighlight()"
class="px-4 py-2 text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors">
나중에 입력
</button>
<button @click="createNoteForHighlight()"
:disabled="!noteForm.content.trim()"
:class="noteForm.content.trim() ? 'bg-blue-600 hover:bg-blue-700' : 'bg-gray-300 cursor-not-allowed'"
class="px-6 py-2 text-white rounded-lg transition-colors">
확인
</button>
</div>
</div>
</div>
</div>
<!-- 책갈피 모달 -->
<div x-show="showBookmarksModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click="showBookmarksModal = false">
<div @click.stop class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
<div class="flex justify-between items-center p-6 border-b">
<h3 class="text-xl font-bold text-gray-800 flex items-center space-x-2">
<i class="fas fa-bookmark text-amber-600"></i>
<span>책갈피</span>
</h3>
<button @click="showBookmarksModal = false"
class="w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-full flex items-center justify-center transition-colors">
<i class="fas fa-times text-gray-600"></i>
</button>
</div>
<div class="p-6 overflow-y-auto max-h-96">
<!-- 책갈피가 없을 때 -->
<template x-if="bookmarks.length === 0">
<div class="text-center text-gray-500">
<div class="w-16 h-16 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-bookmark text-2xl text-amber-500"></i>
</div>
<h4 class="font-semibold text-gray-700 mb-2">책갈피가 없습니다</h4>
<p class="text-sm text-gray-500">텍스트를 선택하고 책갈피를 추가해보세요</p>
</div>
</template>
<!-- 책갈피 목록 -->
<div class="space-y-3">
<template x-for="bookmark in bookmarks" :key="bookmark.id">
<div class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors cursor-pointer"
@click="scrollToHighlight(bookmark.highlight.id)">
<!-- 선택된 텍스트 -->
<div class="bg-amber-50 rounded-md p-2 mb-3">
<p class="text-sm text-amber-800 font-medium" x-text="bookmark.highlight.selected_text"></p>
</div>
<!-- 책갈피 제목 -->
<p class="text-gray-800 mb-2 leading-relaxed font-semibold" x-text="bookmark.title || '제목 없음'"></p>
<!-- 날짜 -->
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500" x-text="formatDate(bookmark.created_at)"></span>
<div class="flex space-x-1">
<button @click.stop="editBookmark(bookmark)"
class="w-6 h-6 bg-amber-100 text-amber-600 rounded-md hover:bg-amber-200 flex items-center justify-center transition-colors">
<i class="fas fa-edit text-xs"></i>
</button>
<button @click.stop="deleteBookmark(bookmark.id)"
class="w-6 h-6 bg-red-100 text-red-600 rounded-md hover:bg-red-200 flex items-center justify-center transition-colors">
<i class="fas fa-trash text-xs"></i>
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
<!-- 백링크 모달 -->
<div x-show="showBacklinksModal"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
@click="showBacklinksModal = false">
<div @click.stop class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
<div class="flex justify-between items-center p-6 border-b">
<h3 class="text-xl font-bold text-gray-800 flex items-center space-x-2">
<i class="fas fa-arrow-left text-orange-600"></i>
<span>백링크</span>
</h3>
<button @click="showBacklinksModal = false"
class="w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-full flex items-center justify-center transition-colors">
<i class="fas fa-times text-gray-600"></i>
</button>
</div>
<div class="p-6 overflow-y-auto max-h-96">
<!-- 백링크가 없을 때 -->
<template x-if="backlinks.length === 0">
<div class="text-center text-gray-500">
<div class="w-16 h-16 bg-orange-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-arrow-left text-2xl text-orange-500"></i>
</div>
<h4 class="font-semibold text-gray-700 mb-2">백링크가 없습니다</h4>
<p class="text-sm text-gray-500">다른 문서에서 이 문서를 참조하는 링크가 없습니다</p>
</div>
</template>
<!-- 백링크 목록 -->
<div class="space-y-3">
<template x-for="backlink in backlinks" :key="backlink.id">
<div class="bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors cursor-pointer"
@click="navigateToBacklink(backlink)">
<!-- 참조하는 문서 정보 -->
<div class="bg-orange-50 rounded-md p-2 mb-3">
<p class="text-sm text-orange-800 font-medium" x-text="backlink.source_document_title"></p>
</div>
<!-- 선택된 텍스트 또는 문서 전체 링크 -->
<div x-show="backlink.selected_text" class="mb-2">
<p class="text-gray-800 leading-relaxed" x-text="backlink.selected_text"></p>
</div>
<div x-show="!backlink.selected_text" class="mb-2">
<p class="text-gray-600 italic">📄 문서 전체 링크</p>
</div>
<!-- 설명 -->
<p class="text-sm text-gray-600 mb-2" x-text="backlink.description || '설명 없음'"></p>
<!-- 날짜 -->
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500" x-text="formatDate(backlink.created_at)"></span>
<button class="text-xs text-orange-600 hover:text-orange-800 font-medium">
문서로 이동 →
</button>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
<!-- 스크립트 -->
<script src="/static/js/api.js?v=2025012618"></script>
<!-- 캐시 및 성능 최적화 시스템 -->
<script src="/static/js/viewer/utils/cache-manager.js?v=2025012607"></script>
<script src="/static/js/viewer/utils/cached-api.js?v=2025012618"></script>
<script src="/static/js/viewer/utils/module-loader.js?v=2025012607"></script>
<!-- 모든 모듈들 직접 로드 -->
<script src="/static/js/viewer/core/document-loader.js?v=2025012624"></script>
<script src="/static/js/viewer/features/ui-manager.js?v=2025012607"></script>
<script src="/static/js/viewer/features/highlight-manager.js?v=2025012619"></script>
<script src="/static/js/viewer/features/link-manager.js?v=2025012622"></script>
<script src="/static/js/viewer/features/bookmark-manager.js?v=2025012607"></script>
<!-- ViewerCore (Alpine.js 컴포넌트) -->
<script src="/static/js/viewer/viewer-core.js?v=2025012626"></script>
<!-- PDF.js 라이브러리 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<!-- Alpine.js 프레임워크 -->
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>
[x-cloak] { display: none !important; }
/* 링크된 텍스트 하이라이트 (URL에서 온 것) - 레이아웃 안전 */
.linked-text-highlight {
background-color: #FEF3C7 !important;
border: 1px solid #F59E0B !important;
border-radius: 2px !important;
padding: 0 1px !important;
display: inline !important;
box-decoration-break: clone !important;
-webkit-box-decoration-break: clone !important;
line-height: inherit !important;
vertical-align: baseline !important;
margin: 0 !important;
box-sizing: border-box !important;
}
/* 백링크 강제 스타일 - 레이아웃 안전 */
.backlink-highlight {
color: #EA580C !important;
background-color: rgba(234, 88, 12, 0.2) !important;
border: 1px solid #EA580C !important;
border-radius: 3px !important;
padding: 0 2px !important;
font-weight: bold !important;
display: inline !important;
box-decoration-break: clone !important;
-webkit-box-decoration-break: clone !important;
line-height: inherit !important;
vertical-align: baseline !important;
margin: 0 !important;
box-sizing: border-box !important;
text-decoration: underline !important;
cursor: pointer !important;
}
/* 링크 스타일 */
.document-link {
color: #7C3AED !important;
background-color: rgba(124, 58, 237, 0.1) !important;
border-radius: 2px !important;
padding: 0 1px !important;
display: inline !important;
line-height: inherit !important;
vertical-align: baseline !important;
margin: 0 !important;
box-sizing: border-box !important;
text-decoration: underline !important;
cursor: pointer !important;
}
/* 겹치는 영역 처리 - 백링크 안에 링크가 있는 경우 */
.backlink-highlight .document-link {
background: linear-gradient(to bottom,
rgba(234, 88, 12, 0.3) 0%,
rgba(234, 88, 12, 0.3) 50%,
rgba(124, 58, 237, 0.2) 50%,
rgba(124, 58, 237, 0.2) 100%) !important;
border-top: 1px solid #EA580C !important;
border-bottom: 1px solid #7C3AED !important;
}
/* 겹치는 영역 처리 - 링크 안에 백링크가 있는 경우 */
.document-link .backlink-highlight {
background: linear-gradient(to bottom,
rgba(124, 58, 237, 0.2) 0%,
rgba(124, 58, 237, 0.2) 50%,
rgba(234, 88, 12, 0.3) 50%,
rgba(234, 88, 12, 0.3) 100%) !important;
border-top: 1px solid #7C3AED !important;
border-bottom: 1px solid #EA580C !important;
}
/* 하이라이트 스타일 개선 */
.highlight, .highlight-span {
padding: 1px 2px;
border-radius: 2px;
cursor: pointer;
transition: all 0.2s ease;
}
.highlight:hover, .highlight-span:hover {
box-shadow: 0 0 4px rgba(0,0,0,0.3);
transform: scale(1.02);
}
.multi-highlight {
padding: 1px 2px;
border-radius: 2px;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
}
.multi-highlight:hover {
box-shadow: 0 0 6px rgba(0,0,0,0.4);
transform: scale(1.02);
}
.multi-highlight::after {
content: "🎨";
position: absolute;
top: -8px;
right: -8px;
font-size: 10px;
background: white;
border-radius: 50%;
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
/* 기존 언어 전환 버튼 숨기기 */
.language-toggle-old,
button[onclick*="toggleLanguage"],
button[onclick*="language"],
.lang-toggle,
#old-language-toggle {
display: none !important;
}
/* 문서 내 기존 언어 버튼들 숨기기 */
#document-content button[onclick*="toggleLanguage"],
#document-content button[onclick*="language"],
#document-content .language-toggle,
#document-content .lang-btn {
display: none !important;
}
</style>
</body>
</html>