diff --git a/invokeai/frontend/web/.eslintrc.js b/invokeai/frontend/web/.eslintrc.js index 489d3cfdff..b1a2b6a7e4 100644 --- a/invokeai/frontend/web/.eslintrc.js +++ b/invokeai/frontend/web/.eslintrc.js @@ -35,6 +35,7 @@ module.exports = { { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, ], 'prettier/prettier': ['error', { endOfLine: 'auto' }], + '@typescript-eslint/ban-ts-comment': 'warn', }, settings: { react: { diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index d61c46a2d3..ba4371f86f 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -52,6 +52,8 @@ "i18next-http-backend": "^2.1.1", "konva": "^8.4.2", "lodash": "^4.17.21", + "overlayscrollbars": "^2.1.0", + "overlayscrollbars-react": "^0.5.0", "re-resizable": "^6.9.9", "react": "^18.2.0", "react-colorful": "^5.6.1", diff --git a/invokeai/frontend/web/src/app/App.tsx b/invokeai/frontend/web/src/app/App.tsx index 3599577ca1..29c0a91613 100644 --- a/invokeai/frontend/web/src/app/App.tsx +++ b/invokeai/frontend/web/src/app/App.tsx @@ -9,7 +9,7 @@ import useToastWatcher from 'features/system/hooks/useToastWatcher'; import FloatingGalleryButton from 'features/ui/components/FloatingGalleryButton'; import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons'; -import { Box, Grid } from '@chakra-ui/react'; +import { Box, Grid, Portal } from '@chakra-ui/react'; import { APP_HEIGHT, APP_PADDING, APP_WIDTH } from 'theme/util/constants'; keepGUIAlive(); @@ -18,26 +18,32 @@ const App = () => { useToastWatcher(); return ( - - - - - - - - - - - - - - + <> + + + + + + + + + + + + + + + + + + + ); }; diff --git a/invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx b/invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx index 51fad5a431..a2ea3dac3a 100644 --- a/invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx +++ b/invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx @@ -9,6 +9,17 @@ import { greenTeaThemeColors } from 'theme/colors/greenTea'; import { invokeAIThemeColors } from 'theme/colors/invokeAI'; import { lightThemeColors } from 'theme/colors/lightTheme'; import { oceanBlueColors } from 'theme/colors/oceanBlue'; +import '@fontsource/inter/100.css'; +import '@fontsource/inter/200.css'; +import '@fontsource/inter/300.css'; +import '@fontsource/inter/400.css'; +import '@fontsource/inter/500.css'; +import '@fontsource/inter/600.css'; +import '@fontsource/inter/700.css'; +import '@fontsource/inter/800.css'; +import '@fontsource/inter/900.css'; +import 'overlayscrollbars/overlayscrollbars.css'; +import 'theme/overlayscrollbar.css'; type ThemeLocaleProviderProps = { children: ReactNode; diff --git a/invokeai/frontend/web/src/common/components/GuidePopover.tsx b/invokeai/frontend/web/src/common/components/GuidePopover.tsx index ee376901e0..4c53e6e8a1 100644 --- a/invokeai/frontend/web/src/common/components/GuidePopover.tsx +++ b/invokeai/frontend/web/src/common/components/GuidePopover.tsx @@ -30,7 +30,7 @@ const GuidePopover = ({ children, feature }: GuideProps) => { if (!shouldDisplayGuides) return null; return ( - + {children} diff --git a/invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImageSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImageSettings.tsx rename to invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings.tsx diff --git a/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx b/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx index 019fb02f90..76277867de 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx @@ -59,6 +59,11 @@ const ParametersAccordion = (props: ParametersAccordionsType) => { allowMultiple reduceMotion onChange={handleChangeAccordionState} + sx={{ + display: 'flex', + flexDirection: 'column', + gap: 2, + }} > {renderAccordions()} diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx index 0466131156..2749da2890 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx @@ -28,7 +28,6 @@ export const floatingSelector = createSelector( const { shouldPinParametersPanel, shouldShowParametersPanel, - shouldHoldParametersPanelOpen, shouldUseCanvasBetaLayout, } = ui; @@ -40,10 +39,7 @@ export const floatingSelector = createSelector( const shouldShowParametersPanelButton = !canvasBetaLayoutCheck && - !( - shouldShowParametersPanel || - (shouldHoldParametersPanelOpen && !shouldPinParametersPanel) - ) && + !shouldPinParametersPanel && ['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName); const shouldShowGalleryButton = @@ -51,8 +47,7 @@ export const floatingSelector = createSelector( ['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName); const shouldShowProcessButtons = - !canvasBetaLayoutCheck && - (!shouldPinParametersPanel || !shouldShowParametersPanel); + !canvasBetaLayoutCheck && !shouldPinParametersPanel; return { shouldPinParametersPanel, diff --git a/invokeai/frontend/web/src/features/ui/components/ImageToImage/InitialImageOverlay.tsx b/invokeai/frontend/web/src/features/ui/components/ImageToImage/InitialImageOverlay.tsx deleted file mode 100644 index 99b3ba4c32..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/ImageToImage/InitialImageOverlay.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Image } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; - -export default function InitialImageOverlay() { - const initialImage = useAppSelector( - (state: RootState) => state.generation.initialImage - ); - - return initialImage ? ( - - ) : null; -} diff --git a/invokeai/frontend/web/src/features/ui/components/ImageToImage/index.tsx b/invokeai/frontend/web/src/features/ui/components/ImageToImage/index.tsx deleted file mode 100644 index e1c38ad75f..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/ImageToImage/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import InvokeWorkarea from 'features/ui/components/InvokeWorkarea'; -import ImageToImageDisplay from './ImageToImageDisplay'; -import ImageToImagePanel from './ImageToImagePanel'; - -export default function ImageToImageWorkarea() { - return ( - }> - - - ); -} diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeParametersPanel.css b/invokeai/frontend/web/src/features/ui/components/InvokeParametersPanel.css deleted file mode 100644 index f43861edba..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/InvokeParametersPanel.css +++ /dev/null @@ -1,35 +0,0 @@ -.ltr-parameters-panel-transition-enter { - transform: translateX(-150%); -} - -.ltr-parameters-panel-transition-enter-active { - transform: translateX(0); - transition: all 120ms ease-out; -} - -.ltr-parameters-panel-transition-exit { - transform: translateX(0); -} - -.ltr-parameters-panel-transition-exit-active { - transform: translateX(-150%); - transition: all 120ms ease-out; -} - -.rtl-parameters-panel-transition-enter { - transform: translateX(150%); -} - -.rtl-parameters-panel-transition-enter-active { - transform: translateX(0); - transition: all 120ms ease-out; -} - -.rtl-parameters-panel-transition-exit { - transform: translateX(0); -} - -.rtl-parameters-panel-transition-exit-active { - transform: translateX(150%); - transition: all 120ms ease-out; -} diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeParametersPanel.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeParametersPanel.tsx deleted file mode 100644 index e7e610df6c..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/InvokeParametersPanel.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import { Box, Flex, Tooltip, Icon, useTheme } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { - setShouldHoldParametersPanelOpen, - setShouldPinParametersPanel, - setShouldShowParametersPanel, -} from 'features/ui/store/uiSlice'; - -import React, { ReactNode, useCallback, useEffect, useRef } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; -import { CSSTransition } from 'react-transition-group'; - -import { setDoesCanvasNeedScaling } from 'features/canvas/store/canvasSlice'; -import { setParametersPanelScrollPosition } from 'features/ui/store/uiSlice'; - -import { isEqual } from 'lodash'; -import { uiSelector } from '../store/uiSelectors'; -import { useTranslation } from 'react-i18next'; -import { - APP_CONTENT_HEIGHT, - OPTIONS_BAR_MAX_WIDTH, - PROGRESS_BAR_THICKNESS, -} from 'theme/util/constants'; -import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent'; - -import './InvokeParametersPanel.css'; -import { no_scrollbar } from 'theme/components/scrollbar'; - -type Props = { children: ReactNode }; - -const optionsPanelSelector = createSelector( - uiSelector, - (ui) => { - const { - shouldShowParametersPanel, - shouldHoldParametersPanelOpen, - shouldPinParametersPanel, - parametersPanelScrollPosition, - } = ui; - - return { - shouldShowParametersPanel, - shouldHoldParametersPanelOpen, - shouldPinParametersPanel, - parametersPanelScrollPosition, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: isEqual, - }, - } -); - -const InvokeOptionsPanel = (props: Props) => { - const dispatch = useAppDispatch(); - const { direction } = useTheme(); - - const { - shouldShowParametersPanel, - shouldHoldParametersPanelOpen, - shouldPinParametersPanel, - } = useAppSelector(optionsPanelSelector); - - const optionsPanelRef = useRef(null); - const optionsPanelContainerRef = useRef(null); - - const timeoutIdRef = useRef(null); - - const { children } = props; - - const { t } = useTranslation(); - - // Hotkeys - useHotkeys( - 'o', - () => { - dispatch(setShouldShowParametersPanel(!shouldShowParametersPanel)); - shouldPinParametersPanel && - setTimeout(() => dispatch(setDoesCanvasNeedScaling(true)), 400); - }, - [shouldShowParametersPanel, shouldPinParametersPanel] - ); - - useHotkeys( - 'esc', - () => { - dispatch(setShouldShowParametersPanel(false)); - }, - { - enabled: () => !shouldPinParametersPanel, - preventDefault: true, - }, - [shouldPinParametersPanel] - ); - - useHotkeys( - 'shift+o', - () => { - handleClickPinOptionsPanel(); - dispatch(setDoesCanvasNeedScaling(true)); - }, - [shouldPinParametersPanel] - ); - - const handleCloseOptionsPanel = useCallback(() => { - if (shouldPinParametersPanel) return; - dispatch( - setParametersPanelScrollPosition( - optionsPanelContainerRef.current - ? optionsPanelContainerRef.current.scrollTop - : 0 - ) - ); - dispatch(setShouldShowParametersPanel(false)); - dispatch(setShouldHoldParametersPanelOpen(false)); - }, [dispatch, shouldPinParametersPanel]); - - const setCloseOptionsPanelTimer = () => { - timeoutIdRef.current = window.setTimeout( - () => handleCloseOptionsPanel(), - 500 - ); - }; - - const cancelCloseOptionsPanelTimer = () => { - timeoutIdRef.current && window.clearTimeout(timeoutIdRef.current); - }; - - const handleClickPinOptionsPanel = () => { - dispatch(setShouldPinParametersPanel(!shouldPinParametersPanel)); - dispatch(setDoesCanvasNeedScaling(true)); - }; - - useEffect(() => { - function handleClickOutside(e: MouseEvent) { - if ( - optionsPanelRef.current && - !optionsPanelRef.current.contains(e.target as Node) - ) { - handleCloseOptionsPanel(); - } - } - document.addEventListener('mousedown', handleClickOutside); - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [handleCloseOptionsPanel]); - - return ( - - - - ) => { - if (e.target !== optionsPanelContainerRef.current) { - cancelCloseOptionsPanelTimer(); - } else { - !shouldPinParametersPanel && setCloseOptionsPanelTimer(); - } - }} - sx={{ - display: 'flex', - flexDirection: 'column', - rowGap: 2, - height: '100%', - }} - > - - - - - - {!shouldPinParametersPanel && ( - - - - )} - {children} - - - - - ); -}; - -export default InvokeOptionsPanel; diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx index 740c71edfd..b4d27d484e 100644 --- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx +++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx @@ -36,9 +36,9 @@ import { } from 'react-icons/md'; import { activeTabIndexSelector } from '../store/uiSelectors'; import { floatingSelector } from './FloatingParametersPanelButtons'; -import ImageToImageWorkarea from './ImageToImage'; -import TextToImageWorkarea from './TextToImage'; -import UnifiedCanvasWorkarea from './UnifiedCanvas/UnifiedCanvasWorkarea'; +import ImageToImageWorkarea from 'features/ui/components/tabs/ImageToImage/ImageToImageWorkarea'; +import TextToImageWorkarea from 'features/ui/components/tabs/TextToImage/TextToImageWorkarea'; +import UnifiedCanvasWorkarea from 'features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasWorkarea'; export interface InvokeTabInfo { title: ReactElement; diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx deleted file mode 100644 index 0210d249cf..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Box, BoxProps, Flex } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import ImageGallery from 'features/gallery/components/ImageGallery'; -import { setInitialImage } from 'features/parameters/store/generationSlice'; -import { - activeTabNameSelector, - uiSelector, -} from 'features/ui/store/uiSelectors'; -import { DragEvent, ReactNode } from 'react'; - -import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; -import useGetImageByUuid from 'features/gallery/hooks/useGetImageByUuid'; -import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; -import { isEqual } from 'lodash'; - -const workareaSelector = createSelector( - [uiSelector, lightboxSelector, activeTabNameSelector], - (ui, lightbox, activeTabName) => { - const { shouldPinParametersPanel } = ui; - const { isLightboxOpen } = lightbox; - return { - shouldPinParametersPanel, - isLightboxOpen, - activeTabName, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: isEqual, - }, - } -); - -type InvokeWorkareaProps = BoxProps & { - optionsPanel: ReactNode; - children: ReactNode; -}; - -const InvokeWorkarea = (props: InvokeWorkareaProps) => { - const dispatch = useAppDispatch(); - const { optionsPanel, children, ...rest } = props; - const { activeTabName, isLightboxOpen } = useAppSelector(workareaSelector); - - const getImageByUuid = useGetImageByUuid(); - - const handleDrop = (e: DragEvent) => { - const uuid = e.dataTransfer.getData('invokeai/imageUuid'); - const image = getImageByUuid(uuid); - if (!image) return; - if (activeTabName === 'img2img') { - dispatch(setInitialImage(image)); - } else if (activeTabName === 'unifiedCanvas') { - dispatch(setInitialCanvasImage(image)); - } - }; - - return ( - - - {optionsPanel} - - {children} - - {!isLightboxOpen && } - - - ); -}; - -export default InvokeWorkarea; diff --git a/invokeai/frontend/web/src/features/ui/components/TextToImage/index.tsx b/invokeai/frontend/web/src/features/ui/components/TextToImage/index.tsx deleted file mode 100644 index fccd862160..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/TextToImage/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import InvokeWorkarea from 'features/ui/components/InvokeWorkarea'; -import TextToImageDisplay from './TextToImageDisplay'; -import TextToImagePanel from './TextToImagePanel'; - -export default function TextToImageWorkarea() { - return ( - }> - - - ); -} diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasWorkarea.tsx deleted file mode 100644 index b35504a2ac..0000000000 --- a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasWorkarea.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; -import InvokeWorkarea from 'features/ui/components/InvokeWorkarea'; -import UnifiedCanvasDisplayBeta from './UnifiedCanvasBeta/UnifiedCanvasDisplayBeta'; -import UnifiedCanvasDisplay from './UnifiedCanvasDisplay'; -import UnifiedCanvasPanel from './UnifiedCanvasPanel'; - -export default function UnifiedCanvasWorkarea() { - const shouldUseCanvasBetaLayout = useAppSelector( - (state: RootState) => state.ui.shouldUseCanvasBetaLayout - ); - return ( - }> - {shouldUseCanvasBetaLayout ? ( - - ) : ( - - )} - - ); -} diff --git a/invokeai/frontend/web/src/features/ui/components/common/InvokeWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/common/InvokeWorkarea.tsx new file mode 100644 index 0000000000..53f4877636 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/common/InvokeWorkarea.tsx @@ -0,0 +1,147 @@ +import { Box, BoxProps, Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import ImageGallery from 'features/gallery/components/ImageGallery'; +import { setInitialImage } from 'features/parameters/store/generationSlice'; +import { + activeTabNameSelector, + uiSelector, +} from 'features/ui/store/uiSelectors'; +import { DragEvent, ReactNode } from 'react'; + +import { + setDoesCanvasNeedScaling, + setInitialCanvasImage, +} from 'features/canvas/store/canvasSlice'; +import useGetImageByUuid from 'features/gallery/hooks/useGetImageByUuid'; +import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; +import { isEqual } from 'lodash'; +import { + APP_CONTENT_HEIGHT, + PARAMETERS_PANEL_WIDTH, +} from 'theme/util/constants'; +import ResizableDrawer from 'features/ui/components/common/ResizableDrawer/ResizableDrawer'; +import { + setShouldPinParametersPanel, + setShouldShowParametersPanel, +} from 'features/ui/store/uiSlice'; +import { useHotkeys } from 'react-hotkeys-hook'; +import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent'; + +const workareaSelector = createSelector( + [uiSelector, lightboxSelector, activeTabNameSelector], + (ui, lightbox, activeTabName) => { + const { shouldPinParametersPanel } = ui; + const { isLightboxOpen } = lightbox; + return { + shouldPinParametersPanel, + isLightboxOpen, + activeTabName, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +type InvokeWorkareaProps = BoxProps & { + parametersPanel: ReactNode; + children: ReactNode; +}; + +const InvokeWorkarea = (props: InvokeWorkareaProps) => { + const { parametersPanel, children, ...rest } = props; + const dispatch = useAppDispatch(); + const { activeTabName, isLightboxOpen } = useAppSelector(workareaSelector); + const { shouldPinParametersPanel, shouldShowParametersPanel } = + useAppSelector(uiSelector); + + const getImageByUuid = useGetImageByUuid(); + + const handleDrop = (e: DragEvent) => { + const uuid = e.dataTransfer.getData('invokeai/imageUuid'); + const image = getImageByUuid(uuid); + if (!image) return; + if (activeTabName === 'img2img') { + dispatch(setInitialImage(image)); + } else if (activeTabName === 'unifiedCanvas') { + dispatch(setInitialCanvasImage(image)); + } + }; + + const closeParametersPanel = () => { + dispatch(setShouldShowParametersPanel(false)); + }; + + useHotkeys( + 'o', + () => { + dispatch(setShouldShowParametersPanel(!shouldShowParametersPanel)); + shouldPinParametersPanel && + setTimeout(() => dispatch(setDoesCanvasNeedScaling(true)), 400); + }, + [shouldShowParametersPanel, shouldPinParametersPanel] + ); + + useHotkeys( + 'esc', + () => { + dispatch(setShouldShowParametersPanel(false)); + }, + { + enabled: () => !shouldPinParametersPanel, + preventDefault: true, + }, + [shouldPinParametersPanel] + ); + + useHotkeys( + 'shift+o', + () => { + dispatch(setShouldPinParametersPanel(!shouldPinParametersPanel)); + dispatch(setDoesCanvasNeedScaling(true)); + }, + [shouldPinParametersPanel] + ); + + return ( + + + + {!shouldPinParametersPanel && } + {parametersPanel} + + + + {children} + + {!isLightboxOpen && } + + ); +}; + +export default InvokeWorkarea; diff --git a/invokeai/frontend/web/src/features/ui/components/common/PinParametersPanelButton.tsx b/invokeai/frontend/web/src/features/ui/components/common/PinParametersPanelButton.tsx new file mode 100644 index 0000000000..d00b039f73 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/common/PinParametersPanelButton.tsx @@ -0,0 +1,44 @@ +import { Box, Icon, Tooltip } from '@chakra-ui/react'; +import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import IAIIconButton, { + IAIIconButtonProps, +} from 'common/components/IAIIconButton'; +import { setDoesCanvasNeedScaling } from 'features/canvas/store/canvasSlice'; +import { useTranslation } from 'react-i18next'; +import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; +import { setShouldPinParametersPanel } from '../../store/uiSlice'; + +const PinParametersPanelButton = () => { + const dispatch = useAppDispatch(); + const shouldPinParametersPanel = useAppSelector( + (state) => state.ui.shouldPinParametersPanel + ); + + const { t } = useTranslation(); + + const handleClickPinOptionsPanel = () => { + dispatch(setShouldPinParametersPanel(!shouldPinParametersPanel)); + dispatch(setDoesCanvasNeedScaling(true)); + }; + + return ( + + : } + variant="unstyled" + size="sm" + padding={2} + sx={{ + position: 'absolute', + top: 1, + insetInlineEnd: 1, + }} + /> + + ); +}; + +export default PinParametersPanelButton; diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx new file mode 100644 index 0000000000..df8fcf5a72 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx @@ -0,0 +1,217 @@ +import { + Box, + chakra, + ChakraProps, + Slide, + useOutsideClick, + useTheme, + SlideDirection, +} from '@chakra-ui/react'; +import { + Resizable, + ResizableProps, + ResizeCallback, + ResizeStartCallback, +} from 're-resizable'; +import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'; +import { LangDirection } from './types'; +import { + getDefaultSize, + getHandleEnables, + getHandleStyles, + getMinMaxDimensions, + getResizableStyles, +} from './util'; +import Scrollable from '../Scrollable'; + +type ResizableDrawerProps = ResizableProps & { + children: ReactNode; + isResizable: boolean; + isPinned: boolean; + isOpen: boolean; + onClose: () => void; + direction?: SlideDirection; + initialWidth?: string | number; + minWidth?: string | number; + maxWidth?: string | number; + initialHeight?: string | number; + minHeight?: string | number; + maxHeight?: string | number; + shouldAllowResize?: boolean; + onResizeStart?: ResizeStartCallback; + onResizeStop?: ResizeCallback; + onResize?: ResizeCallback; + handleWidth?: number; + handleInteractWidth?: string | number; + sx?: ChakraProps['sx']; + pinnedWidth: number; + pinnedHeight: string | number; +}; + +const ChakraResizeable = chakra(Resizable, { + shouldForwardProp: (prop) => !['sx'].includes(prop), +}); + +const ResizableDrawer = ({ + direction = 'left', + isResizable, + isPinned, + isOpen, + onClose, + children, + initialWidth = undefined, + minWidth = undefined, + maxWidth = undefined, + initialHeight = undefined, + minHeight = undefined, + maxHeight = undefined, + shouldAllowResize, + onResizeStart, + onResizeStop, + onResize, + handleWidth = 5, + handleInteractWidth = '15px', + pinnedWidth, + pinnedHeight, + sx = {}, +}: ResizableDrawerProps) => { + const langDirection = useTheme().direction as LangDirection; + + const outsideClickRef = useRef(null); + + useOutsideClick({ + ref: outsideClickRef, + handler: () => { + if (isPinned) { + return; + } + + onClose(); + }, + }); + + const [width, setWidth] = useState(0); + const [height, setHeight] = useState(0); + + const handleEnables = useMemo( + () => + isResizable && shouldAllowResize + ? getHandleEnables({ direction, langDirection }) + : {}, + [isResizable, shouldAllowResize, langDirection, direction] + ); + + const handleStyles = useMemo( + () => + getHandleStyles({ + handleEnables, + handleStyle: { + width: handleInteractWidth, + }, + }), + [handleEnables, handleInteractWidth] + ); + + const minMaxDimensions = useMemo( + () => + getMinMaxDimensions({ + direction, + minWidth, + maxWidth, + minHeight, + maxHeight, + }), + [minWidth, maxWidth, minHeight, maxHeight, direction] + ); + + const resizableStyles = useMemo( + () => getResizableStyles({ isPinned, direction, sx, handleWidth }), + [sx, handleWidth, direction, isPinned] + ); + + useEffect(() => { + const { width, height } = getDefaultSize({ + initialWidth, + initialHeight, + direction, + }); + + setWidth(width); + setHeight(height); + }, [initialWidth, initialHeight, direction, langDirection]); + + useEffect(() => { + if (['left', 'right'].includes(direction)) { + setHeight(isPinned ? '100%' : '100vh'); + } + if (['top', 'bottom'].includes(direction)) { + setWidth(isPinned ? '100%' : '100vw'); + } + }, [isPinned, direction]); + + return ( + + + { + onResizeStart && onResizeStart(event, direction, elementRef); + }} + onResize={(event, direction, elementRef, delta) => { + onResize && onResize(event, direction, elementRef, delta); + }} + onResizeStop={(event, direction, elementRef, delta) => { + event.stopPropagation(); + event.stopImmediatePropagation(); + event.preventDefault(); + if (direction === 'left' || direction === 'right') { + setWidth(Number(width) + delta.width); + } + if (direction === 'top' || direction === 'bottom') { + setHeight(Number(height) + delta.height); + } + onResizeStop && onResizeStop(event, direction, elementRef, delta); + }} + > + {children} + + + + ); +}; + +export default ResizableDrawer; diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts new file mode 100644 index 0000000000..5aa42ab7e5 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts @@ -0,0 +1,2 @@ +export type Placement = 'top' | 'right' | 'bottom' | 'left'; +export type LangDirection = 'ltr' | 'rtl' | undefined; diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts new file mode 100644 index 0000000000..61c5f1093f --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts @@ -0,0 +1,211 @@ +import { ChakraProps, SlideDirection } from '@chakra-ui/react'; +import { AnimationProps } from 'framer-motion'; +import { Enable } from 're-resizable'; +import React from 'react'; +import { LangDirection } from './types'; + +export type GetHandleEnablesOptions = { + direction: SlideDirection; + langDirection: LangDirection; +}; + +// Determine handles to enable, taking into account language direction +export const getHandleEnables = ({ + direction, + langDirection, +}: GetHandleEnablesOptions) => { + const top = direction === 'bottom'; + + const right = + (langDirection !== 'rtl' && direction === 'left') || + (langDirection === 'rtl' && direction === 'right'); + + const bottom = direction === 'top'; + + const left = + (langDirection !== 'rtl' && direction === 'right') || + (langDirection === 'rtl' && direction === 'left'); + + return { top, right, bottom, left }; +}; + +export type GetDefaultSizeOptions = { + initialWidth?: string | number; + initialHeight?: string | number; + direction: SlideDirection; +}; + +// Get default sizes based on direction and initial values +export const getDefaultSize = ({ + initialWidth, + initialHeight, + direction, +}: GetDefaultSizeOptions) => { + const width = + initialWidth ?? (['left', 'right'].includes(direction) ? 500 : '100vw'); + + const height = + initialHeight ?? (['top', 'bottom'].includes(direction) ? 500 : '100vh'); + + return { width, height }; +}; + +export type GetMinMaxDimensionsOptions = { + direction: SlideDirection; + minWidth?: string | number; + maxWidth?: string | number; + minHeight?: string | number; + maxHeight?: string | number; +}; + +// Get the min/max width/height based on direction and provided values +export const getMinMaxDimensions = ({ + direction, + minWidth, + maxWidth, + minHeight, + maxHeight, +}: GetMinMaxDimensionsOptions) => { + const minW = + minWidth ?? (['left', 'right'].includes(direction) ? 10 : undefined); + + const maxW = + maxWidth ?? (['left', 'right'].includes(direction) ? '95vw' : undefined); + + const minH = + minHeight ?? (['top', 'bottom'].includes(direction) ? 10 : undefined); + + const maxH = + maxHeight ?? (['top', 'bottom'].includes(direction) ? '95vh' : undefined); + + return { minWidth: minW, maxWidth: maxW, minHeight: minH, maxHeight: maxH }; +}; + +export type GetHandleStylesOptions = { + handleEnables: Enable; + handleStyle?: React.CSSProperties; +}; + +// Get handle styles, the enables already have language direction factored in so +// that does not need to be handled here +export const getHandleStyles = ({ + handleEnables, + handleStyle, +}: GetHandleStylesOptions) => { + if (!handleStyle) { + return {}; + } + + const top = handleEnables.top ? handleStyle : {}; + const right = handleEnables.right ? handleStyle : {}; + const bottom = handleEnables.bottom ? handleStyle : {}; + const left = handleEnables.left ? handleStyle : {}; + + return { + top, + right, + bottom, + left, + }; +}; + +export type GetAnimationsOptions = { + direction: SlideDirection; + langDirection: LangDirection; +}; + +// Get the framer-motion animation props, taking into account language direction +export const getAnimations = ({ + direction, + langDirection, +}: GetAnimationsOptions): AnimationProps => { + const baseAnimation = { + initial: { opacity: 0 }, + animate: { opacity: 1 }, + exit: { opacity: 0 }, + // chakra consumes the transition prop, which, for it, is a string. + // however we know the transition prop will make it to framer motion, + // which wants it as an object. cast as string to satisfy TS. + transition: { duration: 0.2, ease: 'easeInOut' }, + }; + + const langDirectionFactor = langDirection === 'rtl' ? -1 : 1; + + if (direction === 'top') { + return { + ...baseAnimation, + initial: { y: -999 }, + animate: { y: 0 }, + exit: { y: -999 }, + }; + } + + if (direction === 'right') { + return { + ...baseAnimation, + initial: { x: 999 * langDirectionFactor }, + animate: { x: 0 }, + exit: { x: 999 * langDirectionFactor }, + }; + } + + if (direction === 'bottom') { + return { + ...baseAnimation, + initial: { y: 999 }, + animate: { y: 0 }, + exit: { y: 999 }, + }; + } + + if (direction === 'left') { + return { + ...baseAnimation, + initial: { x: -999 * langDirectionFactor }, + animate: { x: 0 }, + exit: { x: -999 * langDirectionFactor }, + }; + } + + return {}; +}; + +export type GetResizableStylesProps = { + sx: ChakraProps['sx']; + direction: SlideDirection; + handleWidth: number; + isPinned: boolean; +}; + +export const getResizableStyles = ({ + isPinned, // TODO add borderRadius for pinned? + sx, + direction, + handleWidth, +}: GetResizableStylesProps): ChakraProps['sx'] => { + if (isPinned) { + return sx; + } + + if (direction === 'top') { + return { + borderBottomWidth: handleWidth, + ...sx, + }; + } + + if (direction === 'right') { + return { borderInlineStartWidth: handleWidth, ...sx }; + } + + if (direction === 'bottom') { + return { + borderTopWidth: handleWidth, + ...sx, + }; + } + + if (direction === 'left') { + return { borderInlineEndWidth: handleWidth, ...sx }; + } +}; diff --git a/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx b/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx new file mode 100644 index 0000000000..f8c0b6a1ce --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx @@ -0,0 +1,117 @@ +import { Box, ChakraProps } from '@chakra-ui/react'; +import { useOverlayScrollbars } from 'overlayscrollbars-react'; +import { ReactNode, useEffect, useRef } from 'react'; + +type ScrollableProps = { + children: ReactNode; + containerProps?: ChakraProps; +}; + +const Scrollable = ({ + children, + containerProps = { + width: 'full', + height: 'full', + flexShrink: 0, + }, +}: ScrollableProps) => { + const scrollableRef = useRef(null); + const topShadowRef = useRef(null); + const bottomShadowRef = useRef(null); + + const [initialize, _instance] = useOverlayScrollbars({ + defer: true, + events: { + initialized(instance) { + if (!topShadowRef.current || !bottomShadowRef.current) { + return; + } + + const { scrollTop, scrollHeight, offsetHeight } = + instance.elements().content; + + const scrollPercentage = scrollTop / (scrollHeight - offsetHeight); + + topShadowRef.current.style.opacity = String(scrollPercentage * 5); + + bottomShadowRef.current.style.opacity = String( + (1 - scrollPercentage) * 5 + ); + }, + scroll: (_instance, event) => { + if ( + !topShadowRef.current || + !bottomShadowRef.current || + !scrollableRef.current + ) { + return; + } + + const { scrollTop, scrollHeight, offsetHeight } = + event.target as HTMLDivElement; + + const scrollPercentage = scrollTop / (scrollHeight - offsetHeight); + + topShadowRef.current.style.opacity = String(scrollPercentage * 5); + + bottomShadowRef.current.style.opacity = String( + (1 - scrollPercentage) * 5 + ); + }, + }, + }); + + useEffect(() => { + if ( + !scrollableRef.current || + !topShadowRef.current || + !bottomShadowRef.current + ) { + return; + } + + topShadowRef.current.style.opacity = '0'; + + bottomShadowRef.current.style.opacity = '0'; + + initialize(scrollableRef.current); + }, [initialize]); + + return ( + + + {children} + + + + + ); +}; + +export default Scrollable; diff --git a/invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImageDisplay.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageContent.tsx similarity index 94% rename from invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImageDisplay.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageContent.tsx index 173985697f..db62d2ed80 100644 --- a/invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImageDisplay.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageContent.tsx @@ -14,7 +14,7 @@ const workareaSplitViewStyle: ChakraProps['sx'] = { padding: 4, }; -const ImageToImageDisplay = () => { +const ImageToImageContent = () => { const initialImage = useAppSelector( (state: RootState) => state.generation.initialImage ); @@ -47,4 +47,4 @@ const ImageToImageDisplay = () => { ); }; -export default ImageToImageDisplay; +export default ImageToImageContent; diff --git a/invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImagePanel.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageParameters.tsx similarity index 88% rename from invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImagePanel.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageParameters.tsx index d5f2268cb8..d7c3006d32 100644 --- a/invokeai/frontend/web/src/features/ui/components/ImageToImage/ImageToImagePanel.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageParameters.tsx @@ -15,11 +15,11 @@ import ParametersAccordion from 'features/parameters/components/ParametersAccord import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput'; import PromptInput from 'features/parameters/components/PromptInput/PromptInput'; -import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel'; import { useTranslation } from 'react-i18next'; -import ImageToImageSettings from './ImageToImageSettings'; +import PinParametersPanelButton from 'features/ui/components/common/PinParametersPanelButton'; +import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings'; -export default function ImageToImagePanel() { +export default function ImageToImageParameters() { const { t } = useTranslation(); const imageToImageAccordions = { @@ -69,13 +69,12 @@ export default function ImageToImagePanel() { }; return ( - - - - - + + + - + + ); } diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageWorkarea.tsx new file mode 100644 index 0000000000..f9bd582624 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageWorkarea.tsx @@ -0,0 +1,11 @@ +import InvokeWorkarea from 'features/ui/components/common/InvokeWorkarea'; +import ImageToImageContent from './ImageToImageContent'; +import ImageToImageParameters from './ImageToImageParameters'; + +export default function ImageToImageWorkarea() { + return ( + }> + + + ); +} diff --git a/invokeai/frontend/web/src/features/ui/components/ImageToImage/InitImagePreview.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/InitImagePreview.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/ImageToImage/InitImagePreview.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/InitImagePreview.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/TextToImage/TextToImageDisplay.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageContent.tsx similarity index 85% rename from invokeai/frontend/web/src/features/ui/components/TextToImage/TextToImageDisplay.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageContent.tsx index 219b70bc2d..886e3a5331 100644 --- a/invokeai/frontend/web/src/features/ui/components/TextToImage/TextToImageDisplay.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageContent.tsx @@ -1,7 +1,7 @@ import { Box, Flex } from '@chakra-ui/react'; import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay'; -const TextToImageDisplay = () => { +const TextToImageContent = () => { return ( { ); }; -export default TextToImageDisplay; +export default TextToImageContent; diff --git a/invokeai/frontend/web/src/features/ui/components/TextToImage/TextToImagePanel.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageParameters.tsx similarity index 90% rename from invokeai/frontend/web/src/features/ui/components/TextToImage/TextToImagePanel.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageParameters.tsx index 09b96be20c..c970482c26 100644 --- a/invokeai/frontend/web/src/features/ui/components/TextToImage/TextToImagePanel.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageParameters.tsx @@ -15,10 +15,10 @@ import ParametersAccordion from 'features/parameters/components/ParametersAccord import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput'; import PromptInput from 'features/parameters/components/PromptInput/PromptInput'; -import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel'; import { useTranslation } from 'react-i18next'; +import PinParametersPanelButton from 'features/ui/components/common/PinParametersPanelButton'; -export default function TextToImagePanel() { +export default function TextToImageParameters() { const { t } = useTranslation(); const textToImageAccordions = { @@ -63,13 +63,12 @@ export default function TextToImagePanel() { }; return ( - - - - - + + + - + + ); } diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageWorkarea.tsx new file mode 100644 index 0000000000..a1de45d8e6 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageWorkarea.tsx @@ -0,0 +1,11 @@ +import InvokeWorkarea from 'features/ui/components/common/InvokeWorkarea'; +import TextToImageContent from './TextToImageContent'; +import TextToImageParameters from './TextToImageParameters'; + +export default function TextToImageWorkarea() { + return ( + }> + + + ); +} diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasDisplayBeta.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasContentBeta.tsx similarity index 96% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasDisplayBeta.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasContentBeta.tsx index 2ca4139ed0..f6382eeab7 100644 --- a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasDisplayBeta.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasContentBeta.tsx @@ -27,7 +27,7 @@ const selector = createSelector( } ); -const UnifiedCanvasDisplayBeta = () => { +const UnifiedCanvasContentBeta = () => { const dispatch = useAppDispatch(); const { doesCanvasNeedScaling } = useAppSelector(selector); @@ -70,4 +70,4 @@ const UnifiedCanvasDisplayBeta = () => { ); }; -export default UnifiedCanvasDisplayBeta; +export default UnifiedCanvasContentBeta; diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBaseBrushSettings.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBaseBrushSettings.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBaseBrushSettings.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBaseBrushSettings.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSettings.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSettings.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSettings.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSettings.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSize.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSize.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSize.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasBrushSize.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasClearMask.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasClearMask.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasClearMask.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasClearMask.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasDarkenOutsideSelection.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasDarkenOutsideSelection.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasDarkenOutsideSelection.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasDarkenOutsideSelection.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasEnableMask.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasEnableMask.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasEnableMask.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasEnableMask.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasLimitStrokesToBox.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasLimitStrokesToBox.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasLimitStrokesToBox.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasLimitStrokesToBox.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMaskBrushSettings.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMaskBrushSettings.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMaskBrushSettings.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMaskBrushSettings.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMoveSettings.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMoveSettings.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMoveSettings.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasMoveSettings.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasPreserveMask.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasPreserveMask.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasPreserveMask.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasPreserveMask.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasShowGrid.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasShowGrid.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasShowGrid.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasShowGrid.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSnapToGrid.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSnapToGrid.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSnapToGrid.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSnapToGrid.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasCopyToClipboard.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasCopyToClipboard.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasCopyToClipboard.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasCopyToClipboard.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasDownloadImage.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasDownloadImage.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasDownloadImage.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasDownloadImage.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasFileUploader.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasFileUploader.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasFileUploader.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasFileUploader.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasLayerSelect.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasLayerSelect.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasLayerSelect.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasLayerSelect.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMergeVisible.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMergeVisible.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMergeVisible.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMergeVisible.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMoveTool.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMoveTool.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMoveTool.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasMoveTool.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetView.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetView.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetView.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetView.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasSaveToGallery.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasSaveToGallery.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasSaveToGallery.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasSaveToGallery.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx similarity index 100% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasDisplay.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx similarity index 96% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasDisplay.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx index ac7f086bea..66e4f8b0ad 100644 --- a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasDisplay.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx @@ -26,7 +26,7 @@ const selector = createSelector( } ); -const UnifiedCanvasDisplay = () => { +const UnifiedCanvasContent = () => { const dispatch = useAppDispatch(); const { doesCanvasNeedScaling } = useAppSelector(selector); @@ -80,4 +80,4 @@ const UnifiedCanvasDisplay = () => { ); }; -export default UnifiedCanvasDisplay; +export default UnifiedCanvasContent; diff --git a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasPanel.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx similarity index 89% rename from invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasPanel.tsx rename to invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx index 97ba3f23ec..e7b0af7bdc 100644 --- a/invokeai/frontend/web/src/features/ui/components/UnifiedCanvas/UnifiedCanvasPanel.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasParameters.tsx @@ -15,10 +15,10 @@ import ParametersAccordion from 'features/parameters/components/ParametersAccord import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput'; import PromptInput from 'features/parameters/components/PromptInput/PromptInput'; -import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel'; import { useTranslation } from 'react-i18next'; +import PinParametersPanelButton from 'features/ui/components/common/PinParametersPanelButton'; -export default function UnifiedCanvasPanel() { +export default function UnifiedCanvasParameters() { const { t } = useTranslation(); const unifiedCanvasAccordions = { @@ -66,14 +66,12 @@ export default function UnifiedCanvasPanel() { }; return ( - - - - - + + + - {/* */} - + + ); } diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasWorkarea.tsx new file mode 100644 index 0000000000..ae1ace0b04 --- /dev/null +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasWorkarea.tsx @@ -0,0 +1,21 @@ +import { RootState } from 'app/store'; +import { useAppSelector } from 'app/storeHooks'; +import InvokeWorkarea from 'features/ui/components/common/InvokeWorkarea'; +import UnifiedCanvasContentBeta from './UnifiedCanvasBeta/UnifiedCanvasContentBeta'; +import UnifiedCanvasContent from './UnifiedCanvasContent'; +import UnifiedCanvasParameters from './UnifiedCanvasParameters'; + +export default function UnifiedCanvasWorkarea() { + const shouldUseCanvasBetaLayout = useAppSelector( + (state: RootState) => state.ui.shouldUseCanvasBetaLayout + ); + return ( + }> + {shouldUseCanvasBetaLayout ? ( + + ) : ( + + )} + + ); +} diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index d9abae23d8..60fe177172 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -7,7 +7,6 @@ const initialtabsState: UIState = { activeTab: 0, currentTheme: 'dark', parametersPanelScrollPosition: 0, - shouldHoldParametersPanelOpen: false, shouldPinParametersPanel: true, shouldShowParametersPanel: true, shouldShowImageDetails: false, @@ -41,16 +40,11 @@ export const uiSlice = createSlice({ }, setShouldPinParametersPanel: (state, action: PayloadAction) => { state.shouldPinParametersPanel = action.payload; + state.shouldShowParametersPanel = true; }, setShouldShowParametersPanel: (state, action: PayloadAction) => { state.shouldShowParametersPanel = action.payload; }, - setShouldHoldParametersPanelOpen: ( - state, - action: PayloadAction - ) => { - state.shouldHoldParametersPanelOpen = action.payload; - }, setShouldShowImageDetails: (state, action: PayloadAction) => { state.shouldShowImageDetails = action.payload; }, @@ -76,7 +70,6 @@ export const { setActiveTab, setCurrentTheme, setParametersPanelScrollPosition, - setShouldHoldParametersPanelOpen, setShouldPinParametersPanel, setShouldShowParametersPanel, setShouldShowImageDetails, diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index 5885bc3ed7..d7656df78b 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -4,7 +4,6 @@ export interface UIState { activeTab: number; currentTheme: string; parametersPanelScrollPosition: number; - shouldHoldParametersPanelOpen: boolean; shouldPinParametersPanel: boolean; shouldShowParametersPanel: boolean; shouldShowImageDetails: boolean; diff --git a/invokeai/frontend/web/src/theme/components/accordion.ts b/invokeai/frontend/web/src/theme/components/accordion.ts index 46a0c69fd7..3477548c70 100644 --- a/invokeai/frontend/web/src/theme/components/accordion.ts +++ b/invokeai/frontend/web/src/theme/components/accordion.ts @@ -9,7 +9,6 @@ const { definePartsStyle, defineMultiStyleConfig } = const invokeAIContainer = defineStyle({ border: 'none', - pt: 2, }); const invokeAIButton = defineStyle((props) => { @@ -40,7 +39,6 @@ const invokeAIPanel = defineStyle((props) => { bg: `${c}.800`, borderRadius: 'base', borderTopRadius: 'none', - p: 4, }; }); diff --git a/invokeai/frontend/web/src/theme/overlayscrollbar.css b/invokeai/frontend/web/src/theme/overlayscrollbar.css new file mode 100644 index 0000000000..8d80296978 --- /dev/null +++ b/invokeai/frontend/web/src/theme/overlayscrollbar.css @@ -0,0 +1,25 @@ +.os-scrollbar { + /* --os-size: 0; */ + /* --os-padding-perpendicular: 0; */ + /* --os-padding-axis: 0; */ + /* --os-track-border-radius: 0; */ + /* --os-track-bg: none; */ + /* --os-track-bg-hover: none; */ + /* --os-track-bg-active: none; */ + /* --os-track-border: none; */ + /* --os-track-border-hover: none; */ + /* --os-track-border-active: none; */ + /* --os-handle-border-radius: 0; */ + --os-handle-bg: var(--invokeai-colors-accent-600); + --os-handle-bg-hover: var(--invokeai-colors-accent-550); + --os-handle-bg-active: var(--invokeai-colors-accent-500); + /* --os-handle-border: none; */ + /* --os-handle-border-hover: none; */ + /* --os-handle-border-active: none; */ + /* --os-handle-min-size: 33px; */ + /* --os-handle-max-size: none; */ + /* --os-handle-perpendicular-size: 100%; */ + /* --os-handle-perpendicular-size-hover: 100%; */ + /* --os-handle-perpendicular-size-active: 100%; */ + /* --os-handle-interactive-area-offset: 0; */ +} diff --git a/invokeai/frontend/web/src/theme/theme.ts b/invokeai/frontend/web/src/theme/theme.ts index 6cb658564c..b51458d33d 100644 --- a/invokeai/frontend/web/src/theme/theme.ts +++ b/invokeai/frontend/web/src/theme/theme.ts @@ -12,7 +12,7 @@ import { modalTheme } from './components/modal'; import { numberInputTheme } from './components/numberInput'; import { popoverTheme } from './components/popover'; import { progressTheme } from './components/progress'; -import { scrollbar } from './components/scrollbar'; +import { no_scrollbar, scrollbar } from './components/scrollbar'; import { selectTheme } from './components/select'; import { sliderTheme } from './components/slider'; import { switchTheme } from './components/switch'; @@ -31,7 +31,7 @@ export const theme: ThemeOverride = { color: 'base.50', overflow: 'hidden', }, - ...scrollbar, + ...no_scrollbar, }), }, direction: 'ltr', diff --git a/invokeai/frontend/web/src/theme/util/constants.ts b/invokeai/frontend/web/src/theme/util/constants.ts index 85d9185f31..064c71242f 100644 --- a/invokeai/frontend/web/src/theme/util/constants.ts +++ b/invokeai/frontend/web/src/theme/util/constants.ts @@ -11,6 +11,9 @@ export const APP_GALLERY_HEIGHT = 'calc(100vw - 0.3rem + 5rem)'; export const APP_GALLERY_POPOVER_HEIGHT = `calc(100vh - (${APP_CONTENT_HEIGHT_CUTOFF} + 6rem))`; export const APP_METADATA_HEIGHT = `calc(100vh - (${APP_CONTENT_HEIGHT_CUTOFF} + 4.4rem))`; +// this is in pixels +export const PARAMETERS_PANEL_WIDTH = 384; + // do not touch ffs export const APP_TEXT_TO_IMAGE_HEIGHT = 'calc(100vh - 9.4375rem - 1.925rem - 1.15rem)'; diff --git a/invokeai/frontend/web/yarn.lock b/invokeai/frontend/web/yarn.lock index 1a40014efe..da7f1435a5 100644 --- a/invokeai/frontend/web/yarn.lock +++ b/invokeai/frontend/web/yarn.lock @@ -4204,6 +4204,16 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +overlayscrollbars-react@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/overlayscrollbars-react/-/overlayscrollbars-react-0.5.0.tgz#0272bdc6304c7228a58d30e5b678e97fd5c5d8dd" + integrity sha512-uCNTnkfWW74veoiEv3kSwoLelKt4e8gTNv65D771X3il0x5g5Yo0fUbro7SpQzR9yNgi23cvB2mQHTTdQH96pA== + +overlayscrollbars@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-2.1.0.tgz#d647034ef388980e0e5e092f7429c501215330a1" + integrity sha512-L6p4o4aWse5pDstRnJjZaos+al+bkuAgzGIlWwlsxRSgW6+7Kvrp+kAzlWoTZ1bgB4CJj+8u5bjdq8XHEhWjrw== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"