diff --git a/src/App.tsx b/src/App.tsx index 16b3cc318..f78b07cb4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import { ToastContainer, toast, Slide } from 'react-toastify'; import clsx from 'clsx'; import TitleBar from './window/TitleBar'; +import SettingsPanel from './components/panel/SettingsPanel'; import FolderTree from './components/panel/FolderTree'; import LibraryExportPanel from './components/panel/right/LibraryExportPanel'; import Resizer from './components/ui/Resizer'; @@ -130,6 +131,7 @@ function App() { rightPanelWidth, compactEditorPanelHeightOverride, activeRightPanel, + isSettingsOpen, setUI, setRightPanel, } = useUIStore( @@ -144,6 +146,7 @@ function App() { rightPanelWidth: state.rightPanelWidth, compactEditorPanelHeightOverride: state.compactEditorPanelHeightOverride, activeRightPanel: state.activeRightPanel, + isSettingsOpen: state.isSettingsOpen, setUI: state.setUI, setRightPanel: state.setRightPanel, })), @@ -907,6 +910,26 @@ function App() { executeDelete={executeDelete} handleSaveCollage={handleSaveCollage} /> + {isSettingsOpen && appSettings && ( +
+
+
+ setUI({ isSettingsOpen: false })} + onLibraryRefresh={handleLibraryRefresh} + onSettingsChange={handleSettingsChange} + rootPath={rootPath} + /> +
+
+
+ )} { - const rootStyle = getComputedStyle(document.documentElement); - const bgPrimaryStr = rootStyle.getPropertyValue('--app-bg-primary') || 'rgb(24, 24, 24)'; - const bgSecondaryStr = rootStyle.getPropertyValue('--app-bg-secondary') || 'rgb(35, 35, 35)'; - - wgpuStateRef.current = { - useWgpuRenderer: appSettings?.useWgpuRenderer, - isReady: selectedImage?.isReady ?? false, - hasRenderedFirstFrame, - isCropping, - uncroppedAdjustedPreviewUrl, - showOriginal, - bgPrimary: parseRgb(bgPrimaryStr), - bgSecondary: parseRgb(bgSecondaryStr), + let isCancelled = false; + const applyDocumentThemeToWgpuRef = () => { + if (isCancelled) return; + const rootStyle = getComputedStyle(document.documentElement); + const bgPrimaryStr = rootStyle.getPropertyValue('--app-bg-primary') || 'rgb(24, 24, 24)'; + const bgSecondaryStr = rootStyle.getPropertyValue('--app-bg-secondary') || 'rgb(35, 35, 35)'; + + wgpuStateRef.current = { + useWgpuRenderer: appSettings?.useWgpuRenderer, + isReady: selectedImage?.isReady ?? false, + hasRenderedFirstFrame, + isCropping, + uncroppedAdjustedPreviewUrl, + showOriginal, + bgPrimary: parseRgb(bgPrimaryStr), + bgSecondary: parseRgb(bgSecondaryStr), + }; + }; + queueMicrotask(applyDocumentThemeToWgpuRef); + return () => { + isCancelled = true; }; }, [ appSettings?.useWgpuRenderer, diff --git a/src/components/panel/SettingsPanel.tsx b/src/components/panel/SettingsPanel.tsx index a9140f877..e017d34b6 100644 --- a/src/components/panel/SettingsPanel.tsx +++ b/src/components/panel/SettingsPanel.tsx @@ -837,7 +837,7 @@ export default function SettingsPanel({ onClick={onBack} size="icon" variant="ghost" - data-tooltip="Go to Home" + data-tooltip="Back" > diff --git a/src/components/panel/right/RightPanelSwitcher.tsx b/src/components/panel/right/RightPanelSwitcher.tsx index 704000b73..5e9b001a4 100644 --- a/src/components/panel/right/RightPanelSwitcher.tsx +++ b/src/components/panel/right/RightPanelSwitcher.tsx @@ -1,5 +1,15 @@ import { motion } from 'framer-motion'; -import { SlidersHorizontal, Info, Crop, Layers, Paintbrush, SwatchBook, FileInput, type LucideIcon } from 'lucide-react'; +import { + SlidersHorizontal, + Info, + Crop, + Layers, + Paintbrush, + SwatchBook, + FileInput, + Cog, + type LucideIcon, +} from 'lucide-react'; import { Panel } from '../../ui/AppProperties'; interface PanelOptions { @@ -11,6 +21,7 @@ interface PanelOptions { interface RightPanelSwitcherProps { activePanel: Panel | null; onPanelSelect(id: Panel): void; + onOpenAppSettings?(): void; isInstantTransition: boolean; layout?: 'horizontal' | 'vertical'; } @@ -32,6 +43,7 @@ const panelGroups: Array> = [ export default function RightPanelSwitcher({ activePanel, onPanelSelect, + onOpenAppSettings, isInstantTransition, layout = 'vertical', }: RightPanelSwitcherProps) { @@ -69,6 +81,22 @@ export default function RightPanelSwitcher({ ))} ))} + {!isHorizontal && onOpenAppSettings && ( + <> +
+
+ +
+ + )}
); } diff --git a/src/components/views/EditorView.tsx b/src/components/views/EditorView.tsx index 8886ced0b..f467deee0 100644 --- a/src/components/views/EditorView.tsx +++ b/src/components/views/EditorView.tsx @@ -318,6 +318,7 @@ export default function EditorView({ setUI({ isSettingsOpen: true })} isInstantTransition={isInstantTransition} /> diff --git a/src/hooks/useKeyboardShortcuts.tsx b/src/hooks/useKeyboardShortcuts.tsx index 092afea6b..264884257 100644 --- a/src/hooks/useKeyboardShortcuts.tsx +++ b/src/hooks/useKeyboardShortcuts.tsx @@ -441,7 +441,8 @@ export const useKeyboardShortcuts = ({ match: (e: KeyboardEvent) => e.code === 'Escape', execute: (e: KeyboardEvent, s: any) => { e.preventDefault(); - if (s.editor.isStraightenActive) s.editor.setEditor({ isStraightenActive: false }); + if (s.ui.isSettingsOpen) s.ui.setUI({ isSettingsOpen: false }); + else if (s.editor.isStraightenActive) s.editor.setEditor({ isStraightenActive: false }); else if (s.ui.customEscapeHandler) s.ui.customEscapeHandler(); else if (s.editor.activeAiSubMaskId) s.editor.setEditor({ activeAiSubMaskId: null }); else if (s.editor.activeAiPatchContainerId) s.editor.setEditor({ activeAiPatchContainerId: null }); @@ -504,7 +505,14 @@ export const useKeyboardShortcuts = ({ const handleKeyDown = (event: KeyboardEvent) => { const state = getStoreState(); + if (state.ui.isSettingsOpen && event.code === 'Escape') { + event.preventDefault(); + state.ui.setUI({ isSettingsOpen: false }); + return; + } + const isModalOpen = + state.ui.isSettingsOpen || state.ui.isCreateFolderModalOpen || state.ui.isRenameFolderModalOpen || state.ui.isRenameFileModalOpen || diff --git a/src/store/useUIStore.ts b/src/store/useUIStore.ts index e7ef4eb7c..87c193a26 100644 --- a/src/store/useUIStore.ts +++ b/src/store/useUIStore.ts @@ -94,6 +94,7 @@ interface UIState { renameTargetPaths: Array; isImportModalOpen: boolean; isCopyPasteSettingsModalOpen: boolean; + isSettingsOpen: boolean; importTargetFolder: string | null; importSourcePaths: Array; folderActionTarget: string | null; @@ -139,6 +140,7 @@ export const useUIStore = create((set, get) => ({ renameTargetPaths: [], isImportModalOpen: false, isCopyPasteSettingsModalOpen: false, + isSettingsOpen: false, importTargetFolder: null, importSourcePaths: [], folderActionTarget: null,