- note-editor.html: notebook.name → notebook.title 수정 - notes.html: 모든 notebook.name → notebook.title 수정 - note-editor.js: 디버깅 로그 추가하여 노트북 데이터 구조 확인 백엔드 API에서는 'title' 필드를 사용하는데 프론트엔드에서 'name' 필드를 참조하여 노트북 선택창이 빈칸으로 표시되는 문제 해결
203 lines
9.8 KiB
HTML
203 lines
9.8 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>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<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">
|
|
|
|
<!-- Quill.js (WYSIWYG HTML 에디터) -->
|
|
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
|
<script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script>
|
|
|
|
<style>
|
|
.ql-editor {
|
|
min-height: 400px;
|
|
font-size: 16px;
|
|
line-height: 1.6;
|
|
}
|
|
.ql-toolbar {
|
|
border-top: 1px solid #ccc;
|
|
border-left: 1px solid #ccc;
|
|
border-right: 1px solid #ccc;
|
|
}
|
|
.ql-container {
|
|
border-bottom: 1px solid #ccc;
|
|
border-left: 1px solid #ccc;
|
|
border-right: 1px solid #ccc;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-50 min-h-screen" x-data="noteEditorApp()">
|
|
<!-- 헤더 -->
|
|
<div id="header-container"></div>
|
|
|
|
<!-- 메인 컨텐츠 -->
|
|
<main class="container mx-auto px-4 py-8">
|
|
<!-- 페이지 헤더 -->
|
|
<div class="mb-8">
|
|
<div class="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900 flex items-center">
|
|
<i class="fas fa-edit text-blue-600 mr-3"></i>
|
|
<span x-text="isEditing ? '노트 편집' : '새 노트 작성'"></span>
|
|
</h1>
|
|
<p class="text-gray-600 mt-2">HTML 에디터로 풍부한 노트를 작성하세요</p>
|
|
</div>
|
|
|
|
<div class="flex space-x-3">
|
|
<button @click="goBack()"
|
|
class="flex items-center px-4 py-2 bg-gray-600 hover:bg-gray-700 text-white rounded-lg transition-colors">
|
|
<i class="fas fa-arrow-left mr-2"></i>
|
|
<span>돌아가기</span>
|
|
</button>
|
|
|
|
<button @click="saveNote()"
|
|
:disabled="saving || !noteData.title"
|
|
:class="saving || !noteData.title ? 'bg-gray-400 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700'"
|
|
class="flex items-center px-4 py-2 text-white rounded-lg transition-colors">
|
|
<i class="fas fa-save mr-2" :class="{'fa-spin': saving}"></i>
|
|
<span x-text="saving ? '저장 중...' : '저장'"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 노트 설정 -->
|
|
<div class="bg-white rounded-lg shadow-sm border p-6 mb-6">
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<!-- 제목 -->
|
|
<div class="md:col-span-2">
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">제목 *</label>
|
|
<input type="text"
|
|
x-model="noteData.title"
|
|
placeholder="노트 제목을 입력하세요..."
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
required>
|
|
</div>
|
|
|
|
<!-- 노트북 선택 -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">노트북</label>
|
|
<select x-model="noteData.notebook_id"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
<option value="">미분류</option>
|
|
<template x-for="notebook in availableNotebooks" :key="notebook.id">
|
|
<option :value="notebook.id" x-text="notebook.title"></option>
|
|
</template>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
|
|
<!-- 노트 타입 -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">타입</label>
|
|
<select x-model="noteData.note_type"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
<option value="note">일반 노트</option>
|
|
<option value="research">연구 노트</option>
|
|
<option value="summary">요약</option>
|
|
<option value="idea">아이디어</option>
|
|
<option value="guide">가이드</option>
|
|
<option value="reference">참고 자료</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
|
|
<!-- 태그 -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">태그</label>
|
|
<input type="text"
|
|
x-model="tagInput"
|
|
@keydown.enter.prevent="addTag()"
|
|
placeholder="태그를 입력하고 Enter를 누르세요..."
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
|
|
<!-- 태그 목록 -->
|
|
<div x-show="noteData.tags.length > 0" class="mt-3 flex flex-wrap gap-2">
|
|
<template x-for="(tag, index) in noteData.tags" :key="index">
|
|
<span class="inline-flex items-center px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full">
|
|
<span x-text="tag"></span>
|
|
<button @click="removeTag(index)" class="ml-2 text-blue-600 hover:text-blue-800">
|
|
<i class="fas fa-times text-xs"></i>
|
|
</button>
|
|
</span>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 공개 설정 -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">공개 설정</label>
|
|
<div class="flex items-center space-x-4">
|
|
<label class="flex items-center">
|
|
<input type="radio"
|
|
x-model="noteData.is_published"
|
|
:value="false"
|
|
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="noteData.is_published"
|
|
:value="true"
|
|
class="mr-2 text-blue-600">
|
|
<span class="text-sm text-gray-700">공개</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- HTML 에디터 -->
|
|
<div class="bg-white rounded-lg shadow-sm border overflow-hidden">
|
|
<div class="p-4 border-b bg-gray-50">
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="text-lg font-semibold text-gray-900">노트 내용</h3>
|
|
<div class="flex items-center space-x-4">
|
|
<button @click="toggleEditorMode()"
|
|
class="text-sm text-gray-600 hover:text-gray-800">
|
|
<i class="fas fa-code mr-1"></i>
|
|
<span x-text="editorMode === 'wysiwyg' ? 'HTML 코드' : 'WYSIWYG'"></span>
|
|
</button>
|
|
<span class="text-sm text-gray-500" x-text="getWordCount() + '자'"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- WYSIWYG 에디터 -->
|
|
<div x-show="editorMode === 'wysiwyg'" id="quill-editor"></div>
|
|
|
|
<!-- HTML 코드 에디터 -->
|
|
<div x-show="editorMode === 'html'" class="p-4">
|
|
<textarea x-model="noteData.content"
|
|
rows="20"
|
|
placeholder="HTML 코드를 직접 입력하세요..."
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent font-mono text-sm"
|
|
style="resize: vertical;"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 미리보기 -->
|
|
<div x-show="noteData.content" class="mt-6 bg-white rounded-lg shadow-sm border">
|
|
<div class="p-4 border-b bg-gray-50">
|
|
<h3 class="text-lg font-semibold text-gray-900">미리보기</h3>
|
|
</div>
|
|
<div class="p-6">
|
|
<div x-html="noteData.content" class="prose max-w-none"></div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- JavaScript 파일들 -->
|
|
<script src="/static/js/header-loader.js?v=2025012603"></script>
|
|
<script src="/static/js/api.js?v=2025012607"></script>
|
|
<script src="/static/js/auth.js?v=2025012351"></script>
|
|
<script src="/static/js/note-editor.js?v=2025012608"></script>
|
|
</body>
|
|
</html>
|