import { useCallback, useState } from 'react'; import { ApiClientError } from '../../services/apiClient'; import { renameEditorProject } from '../../services/image-editor/editorProjectClient'; import { DEFAULT_CANVAS_BACKGROUND_COLOR, normalizeCanvasBackgroundHex, } from './ImageCanvasEditorModel'; import type { CanvasTool, SidebarPanel } from './ImageCanvasEditorTypes'; type UseImageCanvasEditorChromeOptions = { openEditorLoginModal: (postLoginAction?: (() => void) | null) => void; }; function isEditorAuthError(error: unknown) { return ( error instanceof ApiClientError && (error.status === 401 || error.status === 403) ); } export function useImageCanvasEditorChrome({ openEditorLoginModal, }: UseImageCanvasEditorChromeOptions) { const [projectTitle, setProjectTitle] = useState('未命名画布'); const [projectRenameValue, setProjectRenameValue] = useState('未命名画布'); const [isRenamingProject, setIsRenamingProject] = useState(false); const [isProjectRenameSaving, setIsProjectRenameSaving] = useState(false); const [projectRenameError, setProjectRenameError] = useState( null, ); const [activeSidebarPanel, setActiveSidebarPanel] = useState(null); const [activeTool, setActiveTool] = useState('select'); const [isZoomMenuOpen, setIsZoomMenuOpen] = useState(false); const [isBackgroundSettingsOpen, setIsBackgroundSettingsOpen] = useState(false); const [isMinimapOpen, setIsMinimapOpen] = useState(false); const [canvasBackgroundColor, setCanvasBackgroundColor] = useState( DEFAULT_CANVAS_BACKGROUND_COLOR, ); const [canvasBackgroundHexValue, setCanvasBackgroundHexValue] = useState( DEFAULT_CANVAS_BACKGROUND_COLOR, ); const applyCanvasBackgroundColor = useCallback((color: string) => { const normalizedColor = normalizeCanvasBackgroundHex(color); if (!normalizedColor) { return false; } setCanvasBackgroundColor(normalizedColor); setCanvasBackgroundHexValue(normalizedColor); return true; }, []); const handleCanvasBackgroundHexChange = useCallback((nextValue: string) => { setCanvasBackgroundHexValue(nextValue); const normalizedColor = normalizeCanvasBackgroundHex(nextValue); if (normalizedColor) { setCanvasBackgroundColor(normalizedColor); setCanvasBackgroundHexValue(normalizedColor); } }, []); const startProjectRename = useCallback(() => { setProjectRenameValue(projectTitle); setProjectRenameError(null); setIsRenamingProject(true); }, [projectTitle]); const cancelProjectRename = useCallback(() => { setProjectRenameValue(projectTitle); setProjectRenameError(null); setIsRenamingProject(false); }, [projectTitle]); const submitProjectRename = useCallback( (projectId: string | null) => { const nextTitle = projectRenameValue.trim(); if (!nextTitle) { setProjectRenameError('项目名称不能为空'); return; } if (!projectId || nextTitle === projectTitle) { setProjectRenameValue(projectTitle); setProjectRenameError(null); setIsRenamingProject(false); return; } setIsProjectRenameSaving(true); setProjectRenameError(null); renameEditorProject(projectId, nextTitle) .then((project: Awaited>) => { const savedTitle = project.title?.trim() || nextTitle; setProjectTitle(savedTitle); setProjectRenameValue(savedTitle); setIsRenamingProject(false); }) .catch((error: unknown) => { if (isEditorAuthError(error)) { openEditorLoginModal(); } setProjectRenameError( error instanceof Error ? error.message : '重命名项目失败', ); }) .finally(() => setIsProjectRenameSaving(false)); }, [openEditorLoginModal, projectRenameValue, projectTitle], ); const resetProjectRenameError = useCallback(() => { setProjectRenameError(null); }, []); const closeEditorChromePanels = useCallback(() => { setActiveSidebarPanel(null); setIsZoomMenuOpen(false); setIsBackgroundSettingsOpen(false); }, []); const toggleSidebarPanel = useCallback((panel: SidebarPanel) => { setActiveSidebarPanel((currentPanel) => currentPanel === panel ? null : panel, ); }, []); const toggleZoomMenu = useCallback(() => { setIsZoomMenuOpen((open) => !open); }, []); const closeZoomMenu = useCallback(() => { setIsZoomMenuOpen(false); }, []); const toggleBackgroundSettings = useCallback(() => { setIsBackgroundSettingsOpen((isOpen) => !isOpen); }, []); const toggleMinimap = useCallback(() => { setIsMinimapOpen((open) => !open); }, []); return { projectTitle, setProjectTitle, projectRenameValue, setProjectRenameValue, isRenamingProject, isProjectRenameSaving, projectRenameError, activeSidebarPanel, setActiveSidebarPanel, activeTool, setActiveTool, isZoomMenuOpen, isBackgroundSettingsOpen, isMinimapOpen, canvasBackgroundColor, canvasBackgroundHexValue, startProjectRename, cancelProjectRename, submitProjectRename, resetProjectRenameError, applyCanvasBackgroundColor, handleCanvasBackgroundHexChange, closeEditorChromePanels, toggleSidebarPanel, toggleZoomMenu, closeZoomMenu, toggleBackgroundSettings, toggleMinimap, }; }