하이라이트 색상 문제 해결 및 다중 하이라이트 렌더링 개선
주요 수정사항: - 하이라이트 생성 시 color → highlight_color 필드명 수정으로 색상 전달 문제 해결 - 분홍색을 더 연하게 변경하여 글씨 가독성 향상 - 다중 하이라이트 렌더링을 위아래 균등 분할로 개선 - CSS highlight-span 클래스 추가 및 색상 적용 강화 - 하이라이트 생성/렌더링 과정에 상세한 디버깅 로그 추가 UI 개선: - 단일 하이라이트: 선택한 색상으로 정확히 표시 - 다중 하이라이트: 위아래로 균등하게 색상 분할 표시 - 메모 입력 모달에서 선택된 텍스트 표시 개선 버그 수정: - 프론트엔드-백엔드 API 스키마 불일치 해결 - CSS 스타일 우선순위 문제 해결 - 하이라이트 색상이 노랑색으로만 표시되던 문제 해결
This commit is contained in:
@@ -12,6 +12,20 @@
|
||||
<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()">
|
||||
<!-- 헤더 - 투명하고 세련된 3줄 디자인 -->
|
||||
<header class="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-50 w-full">
|
||||
@@ -108,9 +122,9 @@
|
||||
: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('#FFB6C1')"
|
||||
:class="selectedHighlightColor === '#FFB6C1' ? 'ring-2 ring-pink-400 scale-110' : 'hover:scale-110'"
|
||||
class="w-6 h-6 bg-gradient-to-br from-pink-300 to-pink-400 rounded-full border border-white shadow-sm transition-all duration-200"
|
||||
<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'"
|
||||
@@ -209,6 +223,11 @@
|
||||
<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>
|
||||
|
||||
@@ -459,33 +478,8 @@
|
||||
<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-3">링크 타입</label>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<button @click="linkForm.link_type = 'document'"
|
||||
:class="linkForm.link_type === 'document' ? 'bg-purple-100 border-purple-500 text-purple-700' : 'bg-gray-50 border-gray-300 text-gray-600'"
|
||||
class="p-4 border-2 rounded-lg transition-all duration-200 text-left">
|
||||
<div class="flex items-center space-x-2 mb-2">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
<span class="font-semibold">문서 전체</span>
|
||||
</div>
|
||||
<p class="text-xs">문서 전체로 이동</p>
|
||||
</button>
|
||||
<button @click="linkForm.link_type = 'text_fragment'"
|
||||
:class="linkForm.link_type === 'text_fragment' ? 'bg-purple-100 border-purple-500 text-purple-700' : 'bg-gray-50 border-gray-300 text-gray-600'"
|
||||
class="p-4 border-2 rounded-lg transition-all duration-200 text-left">
|
||||
<div class="flex items-center space-x-2 mb-2">
|
||||
<i class="fas fa-crosshairs"></i>
|
||||
<span class="font-semibold">특정 텍스트</span>
|
||||
</div>
|
||||
<p class="text-xs">문서 내 특정 부분으로 이동</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 특정 텍스트 선택 (text_fragment 타입일 때만) -->
|
||||
<div x-show="linkForm.link_type === 'text_fragment'" class="mb-6">
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">대상 텍스트</label>
|
||||
<div class="space-y-3">
|
||||
<button @click="openTargetDocumentSelector()"
|
||||
@@ -599,6 +593,69 @@
|
||||
</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"
|
||||
@@ -739,36 +796,108 @@
|
||||
|
||||
<!-- 스크립트 -->
|
||||
<script src="/static/js/api.js?v=2025012614"></script>
|
||||
<script src="/static/js/viewer.js?v=2025012641"></script>
|
||||
|
||||
<!-- 캐시 및 성능 최적화 시스템 -->
|
||||
<script src="/static/js/viewer/utils/cache-manager.js?v=2025012607"></script>
|
||||
<script src="/static/js/viewer/utils/cached-api.js?v=2025012607"></script>
|
||||
<script src="/static/js/viewer/utils/module-loader.js?v=2025012607"></script>
|
||||
|
||||
<!-- 모든 모듈들 직접 로드 -->
|
||||
<script src="/static/js/viewer/core/document-loader.js?v=2025012607"></script>
|
||||
<script src="/static/js/viewer/features/ui-manager.js?v=2025012607"></script>
|
||||
<script src="/static/js/viewer/features/highlight-manager.js?v=2025012607"></script>
|
||||
<script src="/static/js/viewer/features/link-manager.js?v=2025012607"></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=2025012607"></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.3) !important;
|
||||
border: 3px solid #EA580C !important;
|
||||
border-radius: 6px !important;
|
||||
padding: 6px 8px !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;
|
||||
box-shadow: 0 4px 8px rgba(234, 88, 12, 0.4) !important;
|
||||
display: inline-block !important;
|
||||
margin: 2px !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, .highlight-span {
|
||||
padding: 1px 2px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.highlight:hover {
|
||||
.highlight:hover, .highlight-span:hover {
|
||||
box-shadow: 0 0 4px rgba(0,0,0,0.3);
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user