重构:文件系统模块化架构,增强 Markdown 渲染
- 拆分 FileSystem.vue 为模块化组件架构 - 新增 Markdown Mermaid 图表渲染支持 - 新增 180+ 编程语言代码高亮 - 修复编辑/预览模式切换渲染问题 - 优化亮色/暗色模式主题适配 - 新增 TypeScript 类型定义
This commit is contained in:
231
web/src/components/FileSystem/composables/useFavorites.ts
Normal file
231
web/src/components/FileSystem/composables/useFavorites.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* 收藏夹管理 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user