feat(ui): improve readability and fix workspace regressions
Separate interface typography from document text and enlarge controls across the workspace and public reader. Keep tree menus within the viewport and make constrained dialogs scrollable. Preserve nested image references, escape moved link paths, synchronize note creation and daily-note opening, and hydrate shared headings. Add regression coverage for settings and workspace behavior.
This commit is contained in:
1 parent
4d1339851b
commit
a716794e41
31 files changed
+556
-246
No files matched your search
@@ -15,6 +15,9 @@ const isOpen = computed(() => expanded.has(props.node.path))
|
||||
const isActive = computed(() => (image.value ? ws.image : ws.active) === props.node.path)
|
||||
const isRenaming = computed(() => ws.renaming === props.node.path)
|
||||
const menuOpen = ref(false)
|
||||
const row = ref<HTMLElement>()
|
||||
const menuElement = ref<HTMLElement>()
|
||||
const menuPosition = ref({ left: 0, top: 0 })
|
||||
const dropTarget = ref(false)
|
||||
const input = ref<HTMLInputElement>()
|
||||
const draft = ref('')
|
||||
@@ -30,8 +33,7 @@ function onTouchStart(e: TouchEvent) {
|
||||
pressStart = { x: e.touches[0].clientX, y: e.touches[0].clientY }
|
||||
pressTimer = setTimeout(() => {
|
||||
longPressed = true
|
||||
contextSelection(props.node.path)
|
||||
menuOpen.value = true
|
||||
showMenu()
|
||||
}, LONG_PRESS_MS)
|
||||
}
|
||||
|
||||
@@ -98,6 +100,21 @@ function showMenu() {
|
||||
menuOpen.value = true
|
||||
}
|
||||
|
||||
watch(menuOpen, async (open, _previous, onCleanup) => {
|
||||
if (!open) return
|
||||
const close = () => { menuOpen.value = false }
|
||||
window.addEventListener('resize', close)
|
||||
onCleanup(() => window.removeEventListener('resize', close))
|
||||
await nextTick()
|
||||
if (!menuOpen.value || !row.value || !menuElement.value) return
|
||||
const anchor = row.value.getBoundingClientRect()
|
||||
const { width, height } = menuElement.value.getBoundingClientRect()
|
||||
menuPosition.value = {
|
||||
left: Math.max(4, Math.min(anchor.right - width, innerWidth - width - 4)),
|
||||
top: Math.max(4, Math.min(anchor.bottom, innerHeight - height - 4)),
|
||||
}
|
||||
})
|
||||
|
||||
function cancelRename() {
|
||||
ws.renaming = null
|
||||
}
|
||||
@@ -129,6 +146,7 @@ function onDrop(e: DragEvent) {
|
||||
<template>
|
||||
<li class="rm-tree-item">
|
||||
<div
|
||||
ref="row"
|
||||
class="rm-tree-row"
|
||||
:class="{ active: isActive, selected: selectedPaths.has(node.path), drop: dropTarget, 'menu-open': menuOpen }"
|
||||
:style="{ paddingLeft: depth * 14 + 8 + 'px' }"
|
||||
@@ -146,7 +164,7 @@ function onDrop(e: DragEvent) {
|
||||
@dragleave="dropTarget = false"
|
||||
@drop="onDrop"
|
||||
>
|
||||
<span class="rm-tree-chevron" :class="{ open: isOpen, hidden: !node.dir }"><Icon name="chevron" :size="12" /></span>
|
||||
<span class="rm-tree-chevron" :class="{ open: isOpen, hidden: !node.dir }"><Icon name="chevron" :size="16" /></span>
|
||||
<input
|
||||
v-if="isRenaming"
|
||||
ref="input"
|
||||
@@ -157,12 +175,15 @@ function onDrop(e: DragEvent) {
|
||||
@keydown.esc.prevent="cancelRename"
|
||||
@blur="commitRename"
|
||||
/>
|
||||
<Icon v-if="image" name="image" :size="14" />
|
||||
<Icon v-if="image" name="image" :size="18" />
|
||||
<span v-if="!isRenaming" class="rm-tree-name">{{ node.dir ? node.name : node.name.replace(/\.md$/, '') }}</span>
|
||||
<button class="rm-icon-btn rm-tree-more" title="更多操作" @click.stop="menuOpen ? (menuOpen = false) : showMenu()">
|
||||
<Icon name="more" />
|
||||
</button>
|
||||
<div v-if="menuOpen" class="rm-menu" @click.stop>
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<div v-if="menuOpen" class="rm-menu-backdrop rm-tree-menu-backdrop" @click.stop="menuOpen = false" @contextmenu.prevent.stop="menuOpen = false" />
|
||||
<div v-if="menuOpen" ref="menuElement" class="rm-menu rm-tree-menu" :style="{ left: menuPosition.left + 'px', top: menuPosition.top + 'px' }" @click.stop>
|
||||
<template v-if="node.dir && !assetDir && selectedPaths.size === 1">
|
||||
<button @click="runMenu('note')"><Icon name="noteAdd" />新建笔记</button>
|
||||
<button @click="runMenu('folder')"><Icon name="folderAdd" />新建文件夹</button>
|
||||
@@ -176,10 +197,15 @@ function onDrop(e: DragEvent) {
|
||||
<button @click="runMenu('export')"><Icon name="note" />导出 Markdown</button>
|
||||
<button v-if="!assetDir" class="danger" @click="runMenu('delete')"><Icon name="trash" />删除</button>
|
||||
</div>
|
||||
<div v-if="menuOpen" class="rm-menu-backdrop" @click.stop="menuOpen = false" @contextmenu.prevent.stop="menuOpen = false" />
|
||||
</div>
|
||||
</Teleport>
|
||||
<ul v-if="node.dir && isOpen" class="rm-tree-list">
|
||||
<TreeNode v-for="child in node.children" :key="child.path" :node="child" :depth="depth + 1" />
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rm-tree-menu { position: fixed; right: auto; z-index: 45; width: max-content; min-width: 0; max-width: calc(100vw - 8px); max-height: calc(100dvh - 8px); box-sizing: border-box; overflow: auto; }
|
||||
.rm-tree-menu button { flex: none; white-space: nowrap; }
|
||||
.rm-tree-menu-backdrop { z-index: 44; }
|
||||
</style>
|
||||
Reference in new issue
Block a user