Initial commit
This commit is contained in:
4
src/hooks/ui/index.ts
Normal file
4
src/hooks/ui/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export { useSidebarState, type UseSidebarStateReturn } from './useSidebarState'
|
||||
export { useSidebarResize } from './useSidebarResize'
|
||||
export { useTOCState, type UseTOCStateReturn } from './useTOCState'
|
||||
export { useKeyboardShortcuts, type UseKeyboardShortcutsParams } from './useKeyboardShortcuts'
|
||||
54
src/hooks/ui/useKeyboardShortcuts.ts
Normal file
54
src/hooks/ui/useKeyboardShortcuts.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { useEffect } from 'react'
|
||||
import type { FileItem } from '@/lib/api'
|
||||
|
||||
export interface UseKeyboardShortcutsParams {
|
||||
selectedFile: FileItem | null
|
||||
isSpecialTab: (file: FileItem | null) => boolean
|
||||
isAsyncImportProcessing: boolean
|
||||
isCurrentTabEditing: boolean
|
||||
hasCurrentTabUnsavedChanges: boolean
|
||||
handleSave: () => Promise<void>
|
||||
toggleTabEdit: (path: string) => void
|
||||
}
|
||||
|
||||
export function useKeyboardShortcuts({
|
||||
selectedFile,
|
||||
isSpecialTab,
|
||||
isAsyncImportProcessing,
|
||||
isCurrentTabEditing,
|
||||
hasCurrentTabUnsavedChanges,
|
||||
handleSave,
|
||||
toggleTabEdit
|
||||
}: UseKeyboardShortcutsParams): void {
|
||||
useEffect(() => {
|
||||
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
||||
if (isCurrentTabEditing && hasCurrentTabUnsavedChanges) {
|
||||
e.preventDefault()
|
||||
e.returnValue = ''
|
||||
}
|
||||
}
|
||||
window.addEventListener('beforeunload', handleBeforeUnload)
|
||||
return () => window.removeEventListener('beforeunload', handleBeforeUnload)
|
||||
}, [isCurrentTabEditing, hasCurrentTabUnsavedChanges])
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (isSpecialTab(selectedFile) || isAsyncImportProcessing) return
|
||||
|
||||
if (e.ctrlKey && e.key === 's') {
|
||||
e.preventDefault()
|
||||
if (isCurrentTabEditing) {
|
||||
handleSave()
|
||||
}
|
||||
} else if (e.ctrlKey && e.key === 'e') {
|
||||
e.preventDefault()
|
||||
if (selectedFile) {
|
||||
toggleTabEdit(selectedFile.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [selectedFile, isSpecialTab, isAsyncImportProcessing, isCurrentTabEditing, handleSave, toggleTabEdit])
|
||||
}
|
||||
33
src/hooks/ui/useSidebarResize.ts
Normal file
33
src/hooks/ui/useSidebarResize.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
export const useSidebarResize = (initialWidth: number = 250) => {
|
||||
const [sidebarWidth, setSidebarWidth] = useState(initialWidth)
|
||||
const [isResizing, setIsResizing] = useState(false)
|
||||
|
||||
const startResizing = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
setIsResizing(true)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isResizing) return
|
||||
|
||||
const stopResizing = () => setIsResizing(false)
|
||||
const resize = (e: MouseEvent) => {
|
||||
const newWidth = e.clientX
|
||||
if (newWidth > 150 && newWidth < 600) {
|
||||
setSidebarWidth(newWidth)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('mousemove', resize)
|
||||
window.addEventListener('mouseup', stopResizing)
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', resize)
|
||||
window.removeEventListener('mouseup', stopResizing)
|
||||
}
|
||||
}, [isResizing])
|
||||
|
||||
return { sidebarWidth, startResizing }
|
||||
}
|
||||
|
||||
22
src/hooks/ui/useSidebarState.ts
Normal file
22
src/hooks/ui/useSidebarState.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useState, useCallback } from 'react'
|
||||
|
||||
export interface UseSidebarStateReturn {
|
||||
sidebarOpen: boolean
|
||||
setSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||
refreshKey: number
|
||||
bumpRefresh: () => void
|
||||
}
|
||||
|
||||
export function useSidebarState(): UseSidebarStateReturn {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(true)
|
||||
const [refreshKey, setRefreshKey] = useState(0)
|
||||
|
||||
const bumpRefresh = useCallback(() => setRefreshKey((prev) => prev + 1), [])
|
||||
|
||||
return {
|
||||
sidebarOpen,
|
||||
setSidebarOpen,
|
||||
refreshKey,
|
||||
bumpRefresh
|
||||
}
|
||||
}
|
||||
60
src/hooks/ui/useTOCState.ts
Normal file
60
src/hooks/ui/useTOCState.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { useState, useCallback } from 'react'
|
||||
import type { FileItem } from '@/lib/api'
|
||||
import type { TOCItem } from '@/lib/utils'
|
||||
import { scrollToElementInTab } from '@/components/tabs'
|
||||
|
||||
export interface UseTOCStateReturn {
|
||||
showTOC: boolean
|
||||
tocItems: TOCItem[]
|
||||
showTOCButton: boolean
|
||||
handleTOCClick: () => void
|
||||
handleTOCClose: () => void
|
||||
handleTOCItemClick: (id: string) => void
|
||||
handleTocUpdated: (filePath: string, items: TOCItem[]) => void
|
||||
}
|
||||
|
||||
export function useTOCState(selectedFile: FileItem | null): UseTOCStateReturn {
|
||||
const [showTOC, setShowTOC] = useState(false)
|
||||
const [tocItems, setTocItems] = useState<TOCItem[]>([])
|
||||
const [showTOCButton, setShowTOCButton] = useState(true)
|
||||
|
||||
const handleTocUpdated = useCallback((filePath: string, items: TOCItem[]) => {
|
||||
if (selectedFile?.path === filePath) {
|
||||
setTocItems(items)
|
||||
}
|
||||
}, [selectedFile])
|
||||
|
||||
const handleTOCClick = useCallback(() => {
|
||||
const newState = !showTOC
|
||||
setShowTOC(newState)
|
||||
|
||||
if (newState) {
|
||||
setTimeout(() => {
|
||||
setShowTOCButton(false)
|
||||
}, 300)
|
||||
} else {
|
||||
setShowTOCButton(true)
|
||||
}
|
||||
}, [showTOC])
|
||||
|
||||
const handleTOCClose = useCallback(() => {
|
||||
setShowTOC(false)
|
||||
setShowTOCButton(true)
|
||||
}, [])
|
||||
|
||||
const handleTOCItemClick = useCallback((id: string) => {
|
||||
if (selectedFile) {
|
||||
scrollToElementInTab(id, selectedFile.path)
|
||||
}
|
||||
}, [selectedFile])
|
||||
|
||||
return {
|
||||
showTOC,
|
||||
tocItems,
|
||||
showTOCButton,
|
||||
handleTOCClick,
|
||||
handleTOCClose,
|
||||
handleTOCItemClick,
|
||||
handleTocUpdated
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user