Major UI overhaul and upload system improvements
- Removed hierarchy view and integrated functionality into index.html - Added book-based document grouping with dedicated book-documents.html page - Implemented comprehensive multi-file upload system with drag-and-drop reordering - Added HTML-PDF matching functionality with download capability - Enhanced upload workflow with 3-step process (File Selection, Book Settings, Order & Match) - Added book conflict resolution (existing book vs new edition) - Improved document order adjustment with one-click sort options - Added modular header component system - Updated API connectivity for Docker environment - Enhanced viewer.html with PDF download functionality - Fixed browser caching issues with version management - Improved mobile responsiveness and modern UI design
This commit is contained in:
@@ -9,6 +9,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.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
|
||||
<!-- 헤더 로더 -->
|
||||
<script src="static/js/header-loader.js"></script>
|
||||
</head>
|
||||
<body class="bg-gray-50 min-h-screen">
|
||||
<!-- 메인 앱 -->
|
||||
@@ -48,87 +51,8 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 헤더 -->
|
||||
<header class="bg-white shadow-sm border-b">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
<!-- 로고 -->
|
||||
<div class="flex items-center space-x-4">
|
||||
<h1 class="text-xl font-bold text-gray-900">
|
||||
<i class="fas fa-file-alt mr-2"></i>
|
||||
Document Server
|
||||
</h1>
|
||||
<div class="flex space-x-2">
|
||||
<span class="px-3 py-1 text-sm bg-blue-100 text-blue-800 rounded-full">📖 그리드 뷰</span>
|
||||
<a href="hierarchy.html" class="px-3 py-1 text-sm bg-gray-100 text-gray-600 rounded-full hover:bg-gray-200">📚 계층구조 뷰</a>
|
||||
<a href="memo-tree.html" class="px-3 py-1 text-sm bg-gray-100 text-gray-600 rounded-full hover:bg-gray-200">🌳 트리 메모장</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 검색바 -->
|
||||
<div class="flex-1 max-w-lg mx-8" x-show="isAuthenticated">
|
||||
<div class="relative">
|
||||
<input type="text" x-model="searchQuery" @input="searchDocuments"
|
||||
placeholder="문서, 메모 검색..."
|
||||
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 사용자 메뉴 -->
|
||||
<div class="flex items-center space-x-4">
|
||||
<template x-if="!isAuthenticated">
|
||||
<button @click="showLoginModal = true"
|
||||
class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700">
|
||||
로그인
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template x-if="isAuthenticated">
|
||||
<div class="flex items-center space-x-4">
|
||||
<!-- 업로드 버튼 -->
|
||||
<button @click="showUploadModal = true"
|
||||
class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
업로드
|
||||
</button>
|
||||
|
||||
<!-- 사용자 드롭다운 -->
|
||||
<div class="relative" x-data="{ open: false }">
|
||||
<button @click="open = !open" class="flex items-center text-gray-700 hover:text-gray-900">
|
||||
<i class="fas fa-user-circle text-2xl"></i>
|
||||
<span x-text="user?.full_name || user?.email" class="ml-2"></span>
|
||||
<i class="fas fa-chevron-down ml-1"></i>
|
||||
</button>
|
||||
|
||||
<div x-show="open" @click.away="open = false" x-cloak
|
||||
class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50">
|
||||
<a href="#" @click="showProfile = true" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-user mr-2"></i>프로필
|
||||
</a>
|
||||
<a href="#" @click="showMyNotes = true" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-sticky-note mr-2"></i>내 메모
|
||||
</a>
|
||||
<a href="#" @click="showBookmarks = true" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-bookmark mr-2"></i>책갈피
|
||||
</a>
|
||||
<template x-if="user?.is_admin">
|
||||
<a href="#" @click="showAdmin = true" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-cog mr-2"></i>관리자
|
||||
</a>
|
||||
</template>
|
||||
<hr class="my-1">
|
||||
<a href="#" @click="logout" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-sign-out-alt mr-2"></i>로그아웃
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- 공통 헤더 컨테이너 -->
|
||||
<div id="header-container"></div>
|
||||
|
||||
<!-- 메인 컨텐츠 -->
|
||||
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
@@ -149,35 +73,69 @@
|
||||
<template x-if="isAuthenticated">
|
||||
<div>
|
||||
<!-- 필터 및 정렬 -->
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div class="flex items-center space-x-4">
|
||||
<div class="mb-6">
|
||||
<!-- 첫 번째 줄: 제목과 뷰 모드 -->
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-2xl font-bold text-gray-900">문서 목록</h2>
|
||||
<select x-model="selectedTag" @change="loadDocuments"
|
||||
class="px-3 py-2 border border-gray-300 rounded-md">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="viewMode = 'grid'"
|
||||
:class="viewMode === 'grid' ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-700'"
|
||||
class="px-3 py-2 rounded-md">
|
||||
<i class="fas fa-th-large mr-2"></i>그리드
|
||||
</button>
|
||||
<button @click="viewMode = 'books'"
|
||||
:class="viewMode === 'books' ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-700'"
|
||||
class="px-3 py-2 rounded-md">
|
||||
<i class="fas fa-list mr-2"></i>목차
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 두 번째 줄: 검색과 필터 -->
|
||||
<div class="flex items-center space-x-4">
|
||||
<!-- 검색 입력창 -->
|
||||
<div class="flex-1 relative">
|
||||
<input type="text"
|
||||
x-model="searchQuery"
|
||||
@input="filterDocuments"
|
||||
placeholder="문서 제목, 내용, 태그로 검색..."
|
||||
class="w-full pl-10 pr-4 py-2.5 bg-white border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm transition-all duration-200">
|
||||
<i class="fas fa-search absolute left-3 top-3.5 text-gray-400"></i>
|
||||
<!-- 검색 결과 개수 표시 -->
|
||||
<span x-show="searchQuery && filteredDocuments.length !== documents.length"
|
||||
class="absolute right-3 top-3 text-sm text-gray-500">
|
||||
<span x-text="filteredDocuments.length"></span>개 결과
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 태그 필터 -->
|
||||
<select x-model="selectedTag" @change="filterDocuments"
|
||||
class="px-4 py-2.5 border border-gray-200 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 min-w-[140px]">
|
||||
<option value="">모든 태그</option>
|
||||
<template x-for="tag in tags" :key="tag.id">
|
||||
<option :value="tag.name" x-text="tag.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="viewMode = 'grid'"
|
||||
:class="viewMode === 'grid' ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-700'"
|
||||
class="px-3 py-2 rounded-md">
|
||||
<i class="fas fa-th-large"></i>
|
||||
|
||||
<!-- 업로드 버튼 -->
|
||||
<button @click="openUploadPage()"
|
||||
class="px-6 py-2.5 bg-gradient-to-r from-blue-600 to-indigo-600 text-white rounded-xl hover:from-blue-700 hover:to-indigo-700 transition-all duration-200 shadow-md hover:shadow-lg flex items-center space-x-2">
|
||||
<i class="fas fa-upload"></i>
|
||||
<span>업로드</span>
|
||||
</button>
|
||||
<button @click="viewMode = 'list'"
|
||||
:class="viewMode === 'list' ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-700'"
|
||||
class="px-3 py-2 rounded-md">
|
||||
<i class="fas fa-list"></i>
|
||||
|
||||
<!-- 검색 초기화 버튼 -->
|
||||
<button x-show="searchQuery || selectedTag"
|
||||
@click="clearFilters"
|
||||
class="px-4 py-2.5 bg-gray-100 text-gray-600 rounded-xl hover:bg-gray-200 transition-all duration-200">
|
||||
<i class="fas fa-times mr-2"></i>초기화
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 문서 그리드/리스트 -->
|
||||
<!-- 기존 그리드 뷰 (모든 문서 평면적으로) -->
|
||||
<div x-show="viewMode === 'grid'" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<template x-for="doc in documents" :key="doc.id">
|
||||
<template x-for="doc in filteredDocuments" :key="doc.id">
|
||||
<div class="bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow cursor-pointer"
|
||||
@click="openDocument(doc.id)">
|
||||
<div class="p-6">
|
||||
@@ -229,17 +187,66 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 서적별 그룹화 뷰 (목차) -->
|
||||
<div x-show="viewMode === 'books'" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<!-- 서적 카드들 -->
|
||||
<template x-for="bookGroup in groupedDocuments" :key="bookGroup.book?.id || 'no-book'">
|
||||
<div class="bg-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 cursor-pointer border border-gray-200"
|
||||
@click="openBookDocuments(bookGroup.book)">
|
||||
<div class="p-6">
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-lg flex items-center justify-center mr-4">
|
||||
<i class="fas fa-book text-white text-lg"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-bold text-gray-900 line-clamp-2" x-text="bookGroup.book?.title || '서적 미분류'"></h3>
|
||||
<p class="text-sm text-gray-600 mt-1" x-show="bookGroup.book?.author" x-text="bookGroup.book.author"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm text-gray-500 mb-3">
|
||||
<span class="flex items-center">
|
||||
<i class="fas fa-file-alt mr-2"></i>
|
||||
<span x-text="bookGroup.documents.length"></span>개 문서
|
||||
</span>
|
||||
<i class="fas fa-chevron-right text-gray-400"></i>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 text-sm line-clamp-2" x-text="bookGroup.book?.description || '서적 설명이 없습니다'"></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 빈 상태 -->
|
||||
<template x-if="documents.length === 0 && !loading">
|
||||
<template x-if="filteredDocuments.length === 0 && !loading">
|
||||
<div class="text-center py-16">
|
||||
<i class="fas fa-folder-open text-6xl text-gray-400 mb-4"></i>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">문서가 없습니다</h3>
|
||||
<p class="text-gray-600 mb-6">첫 번째 문서를 업로드해보세요</p>
|
||||
<button @click="showUploadModal = true"
|
||||
class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
문서 업로드
|
||||
</button>
|
||||
<template x-if="searchQuery || selectedTag">
|
||||
<!-- 검색 결과 없음 -->
|
||||
<div>
|
||||
<i class="fas fa-search text-6xl text-gray-400 mb-4"></i>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">검색 결과가 없습니다</h3>
|
||||
<p class="text-gray-600 mb-6">다른 검색어나 필터를 시도해보세요</p>
|
||||
<button @click="clearFilters"
|
||||
class="bg-gray-600 text-white px-6 py-3 rounded-lg hover:bg-gray-700">
|
||||
<i class="fas fa-times mr-2"></i>
|
||||
필터 초기화
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!searchQuery && !selectedTag">
|
||||
<!-- 문서 없음 -->
|
||||
<div>
|
||||
<i class="fas fa-folder-open text-6xl text-gray-400 mb-4"></i>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">문서가 없습니다</h3>
|
||||
<p class="text-gray-600 mb-6">첫 번째 문서를 업로드해보세요</p>
|
||||
<button @click="showUploadModal = true"
|
||||
class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">
|
||||
<i class="fas fa-upload mr-2"></i>
|
||||
문서 업로드
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -478,8 +485,8 @@
|
||||
</style>
|
||||
|
||||
<!-- JavaScript 파일들 -->
|
||||
<script src="/static/js/api.js?v=2025012225"></script>
|
||||
<script src="/static/js/auth.js?v=2025012225"></script>
|
||||
<script src="/static/js/main.js?v=2025012225"></script>
|
||||
<script src="/static/js/api.js?v=2025012380"></script>
|
||||
<script src="/static/js/auth.js?v=2025012351"></script>
|
||||
<script src="/static/js/main.js?v=2025012374"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user