- 拆分 FileSystem.vue 为模块化组件架构 - 新增 Markdown Mermaid 图表渲染支持 - 新增 180+ 编程语言代码高亮 - 修复编辑/预览模式切换渲染问题 - 优化亮色/暗色模式主题适配 - 新增 TypeScript 类型定义
232 lines
4.9 KiB
TypeScript
232 lines
4.9 KiB
TypeScript
/**
|
|
* 收藏夹管理 Composable
|
|
* 提供收藏文件的添加、删除、排序等功能
|
|
*/
|
|
|
|
import { ref, watch } from 'vue'
|
|
import { STORAGE_KEYS } from '@/utils/constants'
|
|
import type { FavoriteFile, FileItem, DraggingState } from '@/types/file-system'
|
|
|
|
export function useFavorites() {
|
|
// 收藏列表
|
|
const favorites = ref<FavoriteFile[]>([])
|
|
|
|
// 拖拽状态
|
|
const draggingState = ref<DraggingState>({
|
|
isDragging: false,
|
|
draggedIndex: -1,
|
|
pressedIndex: -1
|
|
})
|
|
|
|
/**
|
|
* 从 localStorage 加载收藏列表
|
|
*/
|
|
const loadFavorites = () => {
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEYS.FAVORITE_FILES)
|
|
if (stored) {
|
|
favorites.value = JSON.parse(stored)
|
|
}
|
|
} catch (error) {
|
|
console.error('加载收藏列表失败:', error)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存收藏列表到 localStorage
|
|
*/
|
|
const saveFavorites = () => {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEYS.FAVORITE_FILES, JSON.stringify(favorites.value))
|
|
} catch (error) {
|
|
console.error('保存收藏列表失败:', error)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加收藏
|
|
*/
|
|
const addFavorite = (file: FileItem) => {
|
|
// 检查是否已存在
|
|
const exists = favorites.value.some(fav => fav.path === file.path)
|
|
if (exists) {
|
|
return false
|
|
}
|
|
|
|
favorites.value.push({
|
|
...file,
|
|
addedAt: Date.now()
|
|
} as FavoriteFile)
|
|
saveFavorites()
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* 标准化路径用于比较(处理正斜杠/反斜杠不一致)
|
|
*/
|
|
const normalizePath = (path: string): string => {
|
|
return path.replace(/\\/g, '/').toLowerCase()
|
|
}
|
|
|
|
/**
|
|
* 删除收藏
|
|
*/
|
|
const removeFavorite = (path: string) => {
|
|
const normalizedPath = normalizePath(path)
|
|
const index = favorites.value.findIndex(fav => normalizePath(fav.path) === normalizedPath)
|
|
if (index !== -1) {
|
|
favorites.value.splice(index, 1)
|
|
saveFavorites()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 切换收藏状态
|
|
*/
|
|
const toggleFavorite = (file: FileItem) => {
|
|
const exists = isFavorite(file.path)
|
|
if (exists) {
|
|
removeFavorite(file.path)
|
|
return false
|
|
} else {
|
|
addFavorite(file)
|
|
return true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查是否已收藏
|
|
*/
|
|
const isFavorite = (path: string): boolean => {
|
|
const normalizedPath = normalizePath(path)
|
|
return favorites.value.some(fav => normalizePath(fav.path) === normalizedPath)
|
|
}
|
|
|
|
/**
|
|
* 长按开始
|
|
*/
|
|
const onLongPressStart = (event: MouseEvent | TouchEvent, index: number) => {
|
|
const isMouse = event instanceof MouseEvent
|
|
const isTouch = event instanceof TouchEvent
|
|
|
|
// 只支持鼠标左键或触摸
|
|
if (isMouse && event.button !== 0) return
|
|
if (!isMouse && !isTouch) return
|
|
|
|
draggingState.value.pressedIndex = index
|
|
draggingState.value.draggedIndex = index
|
|
}
|
|
|
|
/**
|
|
* 长按取消
|
|
*/
|
|
const onLongPressCancel = () => {
|
|
if (!draggingState.value.isDragging) {
|
|
draggingState.value.pressedIndex = -1
|
|
draggingState.value.draggedIndex = -1
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 拖拽开始
|
|
*/
|
|
const onDragStart = (event: DragEvent, index: number) => {
|
|
draggingState.value.isDragging = true
|
|
draggingState.value.draggedIndex = index
|
|
|
|
// 设置拖拽数据
|
|
if (event.dataTransfer) {
|
|
event.dataTransfer.effectAllowed = 'move'
|
|
event.dataTransfer.setData('text/plain', index.toString())
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 拖拽经过
|
|
*/
|
|
const onDragOver = (event: DragEvent) => {
|
|
event.preventDefault()
|
|
if (event.dataTransfer) {
|
|
event.dataTransfer.dropEffect = 'move'
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 放置
|
|
*/
|
|
const onDrop = (event: DragEvent, targetIndex: number) => {
|
|
event.preventDefault()
|
|
|
|
const fromIndex = draggingState.value.draggedIndex
|
|
const toIndex = targetIndex
|
|
|
|
if (fromIndex === toIndex || fromIndex === -1) {
|
|
resetDragging()
|
|
return
|
|
}
|
|
|
|
// 移动元素
|
|
const item = favorites.value.splice(fromIndex, 1)[0]
|
|
favorites.value.splice(toIndex, 0, item)
|
|
saveFavorites()
|
|
|
|
resetDragging()
|
|
}
|
|
|
|
/**
|
|
* 拖拽结束
|
|
*/
|
|
const onDragEnd = () => {
|
|
resetDragging()
|
|
}
|
|
|
|
/**
|
|
* 重置拖拽状态
|
|
*/
|
|
const resetDragging = () => {
|
|
draggingState.value.isDragging = false
|
|
draggingState.value.draggedIndex = -1
|
|
draggingState.value.pressedIndex = -1
|
|
}
|
|
|
|
/**
|
|
* 重新排序
|
|
*/
|
|
const reorder = (fromIndex: number, toIndex: number) => {
|
|
if (fromIndex === toIndex) return
|
|
|
|
const item = favorites.value.splice(fromIndex, 1)[0]
|
|
favorites.value.splice(toIndex, 0, item)
|
|
saveFavorites()
|
|
}
|
|
|
|
// 组件挂载时加载收藏列表
|
|
loadFavorites()
|
|
|
|
return {
|
|
// 状态
|
|
favorites,
|
|
draggingState,
|
|
|
|
// 方法
|
|
addFavorite,
|
|
removeFavorite,
|
|
toggleFavorite,
|
|
isFavorite,
|
|
|
|
// 拖拽方法
|
|
onLongPressStart,
|
|
onLongPressCancel,
|
|
onDragStart,
|
|
onDragOver,
|
|
onDrop,
|
|
onDragEnd,
|
|
reorder,
|
|
|
|
// 工具方法
|
|
loadFavorites,
|
|
saveFavorites,
|
|
resetDragging
|
|
}
|
|
}
|