- 集成 MetonaToast v2.0.0 替换自研 Toast 组件(右上角、进度条、自动关闭、主题联动) - 修复 sidebar resize 未持久化到 IndexedDB - 修复 Ctrl+Tab MRU 切换逻辑与文档不一致 - 完善 WYSIWYG 模式标签切换选区恢复 - 清理死代码(useActiveHeading observerRef、旧 Toast 样式、重复滚动条样式、SearchReplace 重复检查) - 同步 DESIGN.md / docs 文档(CodeMirror→Milkdown、stores 计数、editorStore 字段) - 新增 .npmrc.example 模板 - 更新关于对话框与文档远程地址为 Gitea - 版本号 0.3.12 → 0.3.13
75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
import { useEffect, useCallback } from 'react'
|
|
import { useTabStore } from '../stores/tabStore'
|
|
import { isAllowedFile } from '../lib/fileUtils'
|
|
import { MAX_FILE_SIZE } from '../lib/constants'
|
|
import { logError } from '../lib/errorHandler'
|
|
import { showToast } from '../lib/toast'
|
|
|
|
export function useDragDrop() {
|
|
const createTab = useTabStore(s => s.createTab)
|
|
|
|
const handleDrop = useCallback(async (e: DragEvent) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
const files = e.dataTransfer?.files
|
|
if (!files) return
|
|
|
|
let rejected = 0
|
|
for (const file of Array.from(files)) {
|
|
// Electron adds a `path` property to File objects
|
|
const electronFile = file as File & { path?: string }
|
|
const filePath: string = electronFile.path || file.name
|
|
if (!isAllowedFile(filePath)) {
|
|
rejected++
|
|
continue
|
|
}
|
|
if (file.size > MAX_FILE_SIZE) {
|
|
showToast(`"${file.name}" 过大,暂不支持超过 20MB 的文件`)
|
|
continue
|
|
}
|
|
|
|
if (window.electronAPI) {
|
|
try {
|
|
const result = await window.electronAPI.readFile(filePath)
|
|
if (result.success && result.content !== undefined) {
|
|
createTab(filePath, result.content)
|
|
}
|
|
} catch (error) {
|
|
logError('拖拽读取文件失败', error)
|
|
}
|
|
} else {
|
|
const reader = new FileReader()
|
|
reader.onload = (ev: ProgressEvent<FileReader>) => {
|
|
const content = ev.target?.result as string
|
|
createTab(file.name, content)
|
|
}
|
|
reader.readAsText(file)
|
|
}
|
|
}
|
|
|
|
if (rejected > 0) {
|
|
showToast(`仅支持 .md / .markdown / .txt 文件,已忽略 ${rejected} 个文件`)
|
|
}
|
|
}, [createTab])
|
|
|
|
useEffect(() => {
|
|
const prevent = (e: DragEvent) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
}
|
|
|
|
document.addEventListener('dragenter', prevent)
|
|
document.addEventListener('dragleave', prevent)
|
|
document.addEventListener('dragover', prevent)
|
|
document.addEventListener('drop', handleDrop)
|
|
|
|
return () => {
|
|
document.removeEventListener('dragenter', prevent)
|
|
document.removeEventListener('dragleave', prevent)
|
|
document.removeEventListener('dragover', prevent)
|
|
document.removeEventListener('drop', handleDrop)
|
|
}
|
|
}, [handleDrop])
|
|
}
|