feat: 소설 분기 시스템 및 트리 메모장 구현
🌟 주요 기능: - 트리 구조 메모장 시스템 - 소설 분기 관리 (정사 경로 설정) - 중앙 배치 트리 다이어그램 - 정사 경로 목차 뷰 - 인라인 편집 기능 📚 백엔드: - MemoTree, MemoNode 모델 추가 - 정사 경로 자동 순서 관리 - 분기점에서 하나만 선택 가능한 로직 - RESTful API 엔드포인트 🎨 프론트엔드: - memo-tree.html: 트리 다이어그램 에디터 - story-view.html: 정사 경로 목차 뷰 - SVG 연결선으로 시각적 트리 표현 - Alpine.js 기반 반응형 UI - Monaco Editor 통합 ✨ 특별 기능: - 정사 경로 황금색 배지 표시 - 확대/축소 및 패닝 지원 - 드래그 앤 드롭 준비 - 내보내기 및 인쇄 기능 - 인라인 편집 모달
This commit is contained in:
@@ -119,7 +119,32 @@ class DocumentServerAPI {
|
||||
|
||||
// 인증 관련 API
|
||||
async login(email, password) {
|
||||
return await this.post('/auth/login', { email, password });
|
||||
const response = await this.post('/auth/login', { email, password });
|
||||
|
||||
// 토큰 저장
|
||||
if (response.access_token) {
|
||||
this.setToken(response.access_token);
|
||||
|
||||
// 사용자 정보 가져오기
|
||||
try {
|
||||
const user = await this.getCurrentUser();
|
||||
return {
|
||||
success: true,
|
||||
user: user,
|
||||
token: response.access_token
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
message: '사용자 정보를 가져올 수 없습니다.'
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: '로그인에 실패했습니다.'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
@@ -414,6 +439,73 @@ class DocumentServerAPI {
|
||||
async deleteNote(noteId) {
|
||||
return await this.delete(`/notes/${noteId}`);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 트리 메모장 API
|
||||
// ============================================================================
|
||||
|
||||
// 메모 트리 관리
|
||||
async getUserMemoTrees(includeArchived = false) {
|
||||
const params = includeArchived ? '?include_archived=true' : '';
|
||||
return await this.get(`/memo-trees/${params}`);
|
||||
}
|
||||
|
||||
async createMemoTree(treeData) {
|
||||
return await this.post('/memo-trees/', treeData);
|
||||
}
|
||||
|
||||
async getMemoTree(treeId) {
|
||||
return await this.get(`/memo-trees/${treeId}`);
|
||||
}
|
||||
|
||||
async updateMemoTree(treeId, treeData) {
|
||||
return await this.put(`/memo-trees/${treeId}`, treeData);
|
||||
}
|
||||
|
||||
async deleteMemoTree(treeId) {
|
||||
return await this.delete(`/memo-trees/${treeId}`);
|
||||
}
|
||||
|
||||
// 메모 노드 관리
|
||||
async getMemoTreeNodes(treeId) {
|
||||
return await this.get(`/memo-trees/${treeId}/nodes`);
|
||||
}
|
||||
|
||||
async createMemoNode(nodeData) {
|
||||
return await this.post(`/memo-trees/${nodeData.tree_id}/nodes`, nodeData);
|
||||
}
|
||||
|
||||
async getMemoNode(nodeId) {
|
||||
return await this.get(`/memo-trees/nodes/${nodeId}`);
|
||||
}
|
||||
|
||||
async updateMemoNode(nodeId, nodeData) {
|
||||
return await this.put(`/memo-trees/nodes/${nodeId}`, nodeData);
|
||||
}
|
||||
|
||||
async deleteMemoNode(nodeId) {
|
||||
return await this.delete(`/memo-trees/nodes/${nodeId}`);
|
||||
}
|
||||
|
||||
// 노드 이동
|
||||
async moveMemoNode(nodeId, moveData) {
|
||||
return await this.put(`/memo-trees/nodes/${nodeId}/move`, moveData);
|
||||
}
|
||||
|
||||
// 트리 통계
|
||||
async getMemoTreeStats(treeId) {
|
||||
return await this.get(`/memo-trees/${treeId}/stats`);
|
||||
}
|
||||
|
||||
// 검색
|
||||
async searchMemoNodes(searchData) {
|
||||
return await this.post('/memo-trees/search', searchData);
|
||||
}
|
||||
|
||||
// 내보내기
|
||||
async exportMemoTree(exportData) {
|
||||
return await this.post('/memo-trees/export', exportData);
|
||||
}
|
||||
}
|
||||
|
||||
// 전역 API 인스턴스
|
||||
|
||||
Reference in New Issue
Block a user