update at 2026-02-07 14:16:46

This commit is contained in:
douboer
2026-02-07 14:16:46 +08:00
parent dcaac46f65
commit 50c20700c0
6 changed files with 27 additions and 265 deletions

View File

@@ -1,28 +1,14 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
import selectAllIcon from '../assets/icons/selectall.svg'
import unselectAllIcon from '../assets/icons/unselectall.svg'
import { deleteFontFile, renameFontFile } from '../services/font-file-api'
import type { FontInfo, FontTreeNode } from '../types/font'
import type { FontTreeNode } from '../types/font'
import { useFontStore } from '../stores/fontStore'
import { toFontInfoList } from '../utils/font-list'
const props = defineProps<{
nodes: FontTreeNode[]
}>()
const fontStore = useFontStore()
const contextMenu = ref<{
visible: boolean
x: number
y: number
fontInfo: FontInfo | null
}>({
visible: false,
x: 0,
y: 0,
fontInfo: null,
})
function toggleExpand(node: FontTreeNode) {
const next = !node.expanded
@@ -81,105 +67,6 @@ function handleCategorySelectAll(node: FontTreeNode, event: Event) {
ids.forEach(id => fontStore.addToPreview(id))
}
}
function closeContextMenu() {
contextMenu.value.visible = false
contextMenu.value.fontInfo = null
}
function openFontContextMenu(node: FontTreeNode, event: MouseEvent) {
event.preventDefault()
event.stopPropagation()
if (node.type !== 'font' || !node.fontInfo) {
closeContextMenu()
return
}
const menuWidth = 140
const menuHeight = 80
const safeX = Math.min(event.clientX, window.innerWidth - menuWidth - 8)
const safeY = Math.min(event.clientY, window.innerHeight - menuHeight - 8)
contextMenu.value = {
visible: true,
x: Math.max(8, safeX),
y: Math.max(8, safeY),
fontInfo: node.fontInfo,
}
}
async function handleRenameFromContextMenu() {
const targetFont = contextMenu.value.fontInfo
if (!targetFont) {
return
}
closeContextMenu()
const renamed = window.prompt('请输入新的字体名称', targetFont.name)
if (renamed === null) {
return
}
const nextName = renamed.trim()
if (!nextName || nextName === targetFont.name) {
return
}
try {
const fontList = await renameFontFile(targetFont.path, nextName)
fontStore.replaceFonts(toFontInfoList(fontList))
} catch (error) {
const message = error instanceof Error ? error.message : '字体重命名失败'
window.alert(message)
}
}
async function handleDeleteFromContextMenu() {
const targetFont = contextMenu.value.fontInfo
if (!targetFont) {
return
}
closeContextMenu()
const confirmed = window.confirm(`确认删除字体“${targetFont.name}”?此操作不可恢复。`)
if (!confirmed) {
return
}
try {
const fontList = await deleteFontFile(targetFont.path)
fontStore.replaceFonts(toFontInfoList(fontList))
} catch (error) {
const message = error instanceof Error ? error.message : '字体删除失败'
window.alert(message)
}
}
function handleGlobalPointerDown() {
if (!contextMenu.value.visible) {
return
}
closeContextMenu()
}
function handleGlobalKeyDown(event: KeyboardEvent) {
if (event.key === 'Escape') {
closeContextMenu()
}
}
onMounted(() => {
window.addEventListener('pointerdown', handleGlobalPointerDown)
window.addEventListener('keydown', handleGlobalKeyDown)
})
onBeforeUnmount(() => {
window.removeEventListener('pointerdown', handleGlobalPointerDown)
window.removeEventListener('keydown', handleGlobalKeyDown)
})
</script>
<template>
@@ -242,7 +129,6 @@ onBeforeUnmount(() => {
v-for="child in node.children"
:key="child.name"
class="flex items-center gap-2 border-b border-[#c9cdd4] pb-2 relative"
@contextmenu.prevent="openFontContextMenu(child, $event)"
>
<!-- 水平连接线 -->
<div class="tree-horizontal-line"></div>
@@ -283,29 +169,6 @@ onBeforeUnmount(() => {
</div>
</div>
</div>
<teleport to="body">
<div
v-if="contextMenu.visible"
class="fixed z-[2000] min-w-[140px] rounded-md border border-[#d9d9d9] bg-white shadow-md overflow-hidden"
:style="{ left: `${contextMenu.x}px`, top: `${contextMenu.y}px` }"
@pointerdown.stop
@contextmenu.prevent
>
<button
class="w-full h-9 px-3 text-left text-sm text-[#1f2329] hover:bg-[#f2f3f5] border-0 bg-transparent cursor-pointer"
@click="handleRenameFromContextMenu"
>
重命名
</button>
<button
class="w-full h-9 px-3 text-left text-sm text-[#f53f3f] hover:bg-[#fff2f0] border-0 bg-transparent cursor-pointer"
@click="handleDeleteFromContextMenu"
>
删除
</button>
</div>
</teleport>
</template>
<style scoped>