Initial commit: Phase 1+2 prototype

- Go backend with SQLite, JWT auth, file CRUD
- Vue 3 frontend with split/raw/WYSIWYG editor modes
- Markdown preview (marked, GFM)
- Formatting toolbar + keyboard shortcuts
- File tree with search, create, delete
- Light/dark theme toggle
- Admin panel (user management)
- Preferences (timezone, theme, default mode)
- Shared documents section (placeholder)
- Export: PDF, HTML, MD
- Build daemon (Python, stdlib only)
- Build job queue API
- Docker deployment
This commit is contained in:
2026-05-22 19:48:48 +02:00
commit 0c1047d390
26 changed files with 6206 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
<template>
<div class="file-tree">
<div v-for="item in files" :key="item.path" class="tree-item">
<div
class="tree-node"
:class="{ selected: item.path === selected, folder: item.isDir }"
@click="item.isDir ? toggleFolder(item) : $emit('select', item.path)"
@contextmenu.prevent="showContext($event, item)"
>
<span class="icon">{{ item.isDir ? (expanded[item.path] ? '📂' : '📁') : '📄' }}</span>
<span class="name">{{ item.name }}</span>
<button class="delete-btn" @click.stop="$emit('delete', item)" title="Delete">×</button>
</div>
<div v-if="item.isDir && expanded[item.path] && item.children" class="children">
<FileTree :files="item.children" :selected="selected" @select="$emit('select', $event)" @delete="$emit('delete', $event)" />
</div>
</div>
</div>
</template>
<script setup>
import { reactive } from 'vue'
defineProps({
files: { type: Array, default: () => [] },
selected: { type: String, default: '' },
})
defineEmits(['select', 'delete'])
const expanded = reactive({})
function toggleFolder(item) {
expanded[item.path] = !expanded[item.path]
}
</script>
<style scoped>
.file-tree { padding: 8px; overflow-y: auto; flex: 1; }
.tree-item { user-select: none; }
.tree-node {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
position: relative;
}
.tree-node:hover { background: var(--hover-bg, #313244); }
.tree-node.selected { background: var(--selected-bg, #45475a); }
.icon { font-size: 14px; }
.name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.delete-btn {
display: none;
background: none;
border: none;
color: #f38ba8;
font-size: 16px;
cursor: pointer;
padding: 0 4px;
line-height: 1;
}
.tree-node:hover .delete-btn { display: block; }
.children { padding-left: 16px; }
</style>