feat(web): add Vue workspace with file tree, tabs, autosave and live sync
- Login and first-run setup screens - File tree with inline create/rename, context menu, drag-and-drop move and trash with undo; all operations update the UI first and roll back on failure - Tabs keep a CodeMirror state each; edits autosave after 500 ms with If-Match revisions, unsent edits persist in IndexedDB, and conflicts or remote deletions surface as banners with explicit choices - WebSocket events sync external edits, moves and deletions into open tabs; reconnects trigger a full resync - Pasted or dropped images show instantly and upload to note.assets/ - Responsive layout with a swipe-in sidebar drawer on phones - Switch to TypeScript 6: vue-tsc does not support TypeScript 7 yet
This commit is contained in:
1 parent
c4d2bd4636
commit
02d904056c
28 files changed
+2231
-398
No files matched your search
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import Icon from './Icon.vue'
|
||||
import { noteTitle } from './paths'
|
||||
import { closeTab, ws } from './workspace'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="rm-tabs" role="tablist">
|
||||
<div
|
||||
v-for="tab in ws.tabs"
|
||||
:key="tab.path"
|
||||
class="rm-tab"
|
||||
:class="{ active: ws.active === tab.path }"
|
||||
role="tab"
|
||||
:aria-selected="ws.active === tab.path"
|
||||
:title="tab.path"
|
||||
@click="ws.active = tab.path"
|
||||
@auxclick.prevent="$event.button === 1 && closeTab(tab.path)"
|
||||
>
|
||||
<span class="rm-tab-title">{{ noteTitle(tab.path) }}</span>
|
||||
<button class="rm-tab-close" :class="{ dirty: tab.dirty }" title="关闭" @click.stop="closeTab(tab.path)">
|
||||
<span class="rm-dirty-dot" />
|
||||
<Icon name="close" :size="12" />
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
Reference in new issue
Block a user