mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
revert(ui): remove floating viewer
There are unresolved platform-specific issues with this component, and its utility is debatable. Should be easy to just revert this commit to add it back in the future if desired.
This commit is contained in:
committed by
Kent Keirsey
parent
a826f8f8c5
commit
72ce239592
@ -89,7 +89,6 @@
|
|||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-redux": "9.1.2",
|
"react-redux": "9.1.2",
|
||||||
"react-resizable-panels": "^2.0.19",
|
"react-resizable-panels": "^2.0.19",
|
||||||
"react-rnd": "^10.4.10",
|
|
||||||
"react-select": "5.8.0",
|
"react-select": "5.8.0",
|
||||||
"react-use": "^17.5.0",
|
"react-use": "^17.5.0",
|
||||||
"react-virtuoso": "^4.7.10",
|
"react-virtuoso": "^4.7.10",
|
||||||
|
43
invokeai/frontend/web/pnpm-lock.yaml
generated
43
invokeai/frontend/web/pnpm-lock.yaml
generated
@ -122,9 +122,6 @@ dependencies:
|
|||||||
react-resizable-panels:
|
react-resizable-panels:
|
||||||
specifier: ^2.0.19
|
specifier: ^2.0.19
|
||||||
version: 2.0.19(react-dom@18.3.1)(react@18.3.1)
|
version: 2.0.19(react-dom@18.3.1)(react@18.3.1)
|
||||||
react-rnd:
|
|
||||||
specifier: ^10.4.10
|
|
||||||
version: 10.4.10(react-dom@18.3.1)(react@18.3.1)
|
|
||||||
react-select:
|
react-select:
|
||||||
specifier: 5.8.0
|
specifier: 5.8.0
|
||||||
version: 5.8.0(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1)
|
version: 5.8.0(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1)
|
||||||
@ -7208,11 +7205,6 @@ packages:
|
|||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/clsx@1.2.1:
|
|
||||||
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/color-convert@1.9.3:
|
/color-convert@1.9.3:
|
||||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -10814,16 +10806,6 @@ packages:
|
|||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/re-resizable@6.9.14(react-dom@18.3.1)(react@18.3.1):
|
|
||||||
resolution: {integrity: sha512-2UbPrpezMr6gkHKNCRA/N6QGGU237SKOZ78yMHId204A/oXWSAREAIuGZNQ9qlrJosewzcsv2CphZH3u7hC6ng==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^16.13.1 || ^17.0.0 || ^18.0.0
|
|
||||||
react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0
|
|
||||||
dependencies:
|
|
||||||
react: 18.3.1
|
|
||||||
react-dom: 18.3.1(react@18.3.1)
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/react-clientside-effect@1.2.6(react@18.3.1):
|
/react-clientside-effect@1.2.6(react@18.3.1):
|
||||||
resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==}
|
resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -10877,18 +10859,6 @@ packages:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
scheduler: 0.23.2
|
scheduler: 0.23.2
|
||||||
|
|
||||||
/react-draggable@4.4.6(react-dom@18.3.1)(react@18.3.1):
|
|
||||||
resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==}
|
|
||||||
peerDependencies:
|
|
||||||
react: '>= 16.3.0'
|
|
||||||
react-dom: '>= 16.3.0'
|
|
||||||
dependencies:
|
|
||||||
clsx: 1.2.1
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 18.3.1
|
|
||||||
react-dom: 18.3.1(react@18.3.1)
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/react-dropzone@14.2.3(react@18.3.1):
|
/react-dropzone@14.2.3(react@18.3.1):
|
||||||
resolution: {integrity: sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==}
|
resolution: {integrity: sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==}
|
||||||
engines: {node: '>= 10.13'}
|
engines: {node: '>= 10.13'}
|
||||||
@ -11099,19 +11069,6 @@ packages:
|
|||||||
react-dom: 18.3.1(react@18.3.1)
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/react-rnd@10.4.10(react-dom@18.3.1)(react@18.3.1):
|
|
||||||
resolution: {integrity: sha512-YjQAgEeSbNUoOXSD9ZBvIiLVizFb+bNhpDk8DbIRHA557NW02CXbwsAeOTpJQnsdhEL+NP2I+Ssrwejqcodtjg==}
|
|
||||||
peerDependencies:
|
|
||||||
react: '>=16.3.0'
|
|
||||||
react-dom: '>=16.3.0'
|
|
||||||
dependencies:
|
|
||||||
re-resizable: 6.9.14(react-dom@18.3.1)(react@18.3.1)
|
|
||||||
react: 18.3.1
|
|
||||||
react-dom: 18.3.1(react@18.3.1)
|
|
||||||
react-draggable: 4.4.6(react-dom@18.3.1)(react@18.3.1)
|
|
||||||
tslib: 2.6.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/react-select@5.7.7(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1):
|
/react-select@5.7.7(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1):
|
||||||
resolution: {integrity: sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==}
|
resolution: {integrity: sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -12,7 +12,6 @@ import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
|
|||||||
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
|
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
|
||||||
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
|
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
|
||||||
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
|
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
|
||||||
import { FloatingImageViewer } from 'features/gallery/components/ImageViewer/FloatingImageViewer';
|
|
||||||
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
|
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
|
||||||
import { configChanged } from 'features/system/store/configSlice';
|
import { configChanged } from 'features/system/store/configSlice';
|
||||||
import { languageSelector } from 'features/system/store/systemSelectors';
|
import { languageSelector } from 'features/system/store/systemSelectors';
|
||||||
@ -97,7 +96,6 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
|
|||||||
<DynamicPromptsModal />
|
<DynamicPromptsModal />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<PreselectedImage selectedImage={selectedImage} />
|
<PreselectedImage selectedImage={selectedImage} />
|
||||||
<FloatingImageViewer />
|
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,190 +0,0 @@
|
|||||||
import { Flex, IconButton, Spacer, Text, useShiftModifier } from '@invoke-ai/ui-library';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import CurrentImagePreview from 'features/gallery/components/ImageViewer/CurrentImagePreview';
|
|
||||||
import { isFloatingImageViewerOpenChanged } from 'features/gallery/store/gallerySlice';
|
|
||||||
import { memo, useCallback, useLayoutEffect, useRef } from 'react';
|
|
||||||
import { flushSync } from 'react-dom';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { PiHourglassBold, PiXBold } from 'react-icons/pi';
|
|
||||||
import { Rnd } from 'react-rnd';
|
|
||||||
|
|
||||||
const defaultDim = 256;
|
|
||||||
const maxDim = 512;
|
|
||||||
const defaultSize = { width: defaultDim, height: defaultDim + 24 };
|
|
||||||
const maxSize = { width: maxDim, height: maxDim + 24 };
|
|
||||||
const rndDefault = { x: 0, y: 0, ...defaultSize };
|
|
||||||
|
|
||||||
const rndStyles = {
|
|
||||||
zIndex: 11,
|
|
||||||
};
|
|
||||||
|
|
||||||
const enableResizing = {
|
|
||||||
top: false,
|
|
||||||
right: false,
|
|
||||||
bottom: false,
|
|
||||||
left: false,
|
|
||||||
topRight: false,
|
|
||||||
bottomRight: true,
|
|
||||||
bottomLeft: false,
|
|
||||||
topLeft: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const FloatingImageViewerComponent = memo(() => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const shift = useShiftModifier();
|
|
||||||
const rndRef = useRef<Rnd>(null);
|
|
||||||
const imagePreviewRef = useRef<HTMLDivElement>(null);
|
|
||||||
const onClose = useCallback(() => {
|
|
||||||
dispatch(isFloatingImageViewerOpenChanged(false));
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const fitToScreen = useCallback(() => {
|
|
||||||
if (!imagePreviewRef.current || !rndRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const el = imagePreviewRef.current;
|
|
||||||
const rnd = rndRef.current;
|
|
||||||
|
|
||||||
const { top, right, bottom, left, width, height } = el.getBoundingClientRect();
|
|
||||||
const { innerWidth, innerHeight } = window;
|
|
||||||
|
|
||||||
const newPosition = rnd.getDraggablePosition();
|
|
||||||
|
|
||||||
if (top < 0) {
|
|
||||||
newPosition.y = 0;
|
|
||||||
}
|
|
||||||
if (left < 0) {
|
|
||||||
newPosition.x = 0;
|
|
||||||
}
|
|
||||||
if (bottom > innerHeight) {
|
|
||||||
newPosition.y = innerHeight - height;
|
|
||||||
}
|
|
||||||
if (right > innerWidth) {
|
|
||||||
newPosition.x = innerWidth - width;
|
|
||||||
}
|
|
||||||
rnd.updatePosition(newPosition);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onDoubleClick = useCallback(() => {
|
|
||||||
if (!rndRef.current || !imagePreviewRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { width, height } = imagePreviewRef.current.getBoundingClientRect();
|
|
||||||
if (width === defaultSize.width && height === defaultSize.height) {
|
|
||||||
rndRef.current.updateSize(maxSize);
|
|
||||||
} else {
|
|
||||||
rndRef.current.updateSize(defaultSize);
|
|
||||||
}
|
|
||||||
flushSync(fitToScreen);
|
|
||||||
}, [fitToScreen]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
window.addEventListener('resize', fitToScreen);
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', fitToScreen);
|
|
||||||
};
|
|
||||||
}, [fitToScreen]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
// Set the initial position
|
|
||||||
if (!imagePreviewRef.current || !rndRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { width, height } = imagePreviewRef.current.getBoundingClientRect();
|
|
||||||
|
|
||||||
const initialPosition = {
|
|
||||||
// 54 = width of left-hand vertical bar of tab icons
|
|
||||||
// 430 = width of parameters panel
|
|
||||||
x: 54 + 430 / 2 - width / 2,
|
|
||||||
// 16 = just a reasonable bottom padding
|
|
||||||
y: window.innerHeight - height - 16,
|
|
||||||
};
|
|
||||||
|
|
||||||
rndRef.current.updatePosition(initialPosition);
|
|
||||||
}, [fitToScreen]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Rnd
|
|
||||||
ref={rndRef}
|
|
||||||
default={rndDefault}
|
|
||||||
bounds="window"
|
|
||||||
lockAspectRatio={shift}
|
|
||||||
minWidth={defaultSize.width}
|
|
||||||
minHeight={defaultSize.height}
|
|
||||||
maxWidth={maxSize.width}
|
|
||||||
maxHeight={maxSize.height}
|
|
||||||
style={rndStyles}
|
|
||||||
enableResizing={enableResizing}
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
ref={imagePreviewRef}
|
|
||||||
flexDir="column"
|
|
||||||
bg="base.850"
|
|
||||||
borderRadius="base"
|
|
||||||
w="full"
|
|
||||||
h="full"
|
|
||||||
borderWidth={1}
|
|
||||||
shadow="dark-lg"
|
|
||||||
cursor="move"
|
|
||||||
>
|
|
||||||
<Flex bg="base.800" w="full" p={1} onDoubleClick={onDoubleClick}>
|
|
||||||
<Text fontSize="sm" fontWeight="semibold" color="base.300" ps={2}>
|
|
||||||
{t('common.viewer')}
|
|
||||||
</Text>
|
|
||||||
<Spacer />
|
|
||||||
<IconButton aria-label={t('common.close')} icon={<PiXBold />} size="sm" variant="link" onClick={onClose} />
|
|
||||||
</Flex>
|
|
||||||
<Flex p={2} w="full" h="full">
|
|
||||||
<CurrentImagePreview
|
|
||||||
isDragDisabled={true}
|
|
||||||
isDropDisabled={true}
|
|
||||||
withNextPrevButtons={false}
|
|
||||||
withMetadata={false}
|
|
||||||
alwaysShowProgress
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Rnd>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
FloatingImageViewerComponent.displayName = 'FloatingImageViewerComponent';
|
|
||||||
|
|
||||||
export const FloatingImageViewer = memo(() => {
|
|
||||||
const isOpen = useAppSelector((s) => s.gallery.isFloatingImageViewerOpen);
|
|
||||||
|
|
||||||
if (!isOpen) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <FloatingImageViewerComponent />;
|
|
||||||
});
|
|
||||||
|
|
||||||
FloatingImageViewer.displayName = 'FloatingImageViewer';
|
|
||||||
|
|
||||||
export const ToggleFloatingImageViewerButton = memo(() => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const isOpen = useAppSelector((s) => s.gallery.isFloatingImageViewerOpen);
|
|
||||||
|
|
||||||
const onToggle = useCallback(() => {
|
|
||||||
dispatch(isFloatingImageViewerOpenChanged(!isOpen));
|
|
||||||
}, [dispatch, isOpen]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IconButton
|
|
||||||
tooltip={isOpen ? t('gallery.closeFloatingViewer') : t('gallery.openFloatingViewer')}
|
|
||||||
aria-label={isOpen ? t('gallery.closeFloatingViewer') : t('gallery.openFloatingViewer')}
|
|
||||||
icon={<PiHourglassBold fontSize={16} />}
|
|
||||||
size="sm"
|
|
||||||
onClick={onToggle}
|
|
||||||
variant="link"
|
|
||||||
colorScheme={isOpen ? 'invokeBlue' : 'base'}
|
|
||||||
boxSize={8}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
ToggleFloatingImageViewerButton.displayName = 'ToggleFloatingImageViewerButton';
|
|
@ -24,7 +24,6 @@ const initialGalleryState: GalleryState = {
|
|||||||
limit: INITIAL_IMAGE_LIMIT,
|
limit: INITIAL_IMAGE_LIMIT,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
isImageViewerOpen: false,
|
isImageViewerOpen: false,
|
||||||
isFloatingImageViewerOpen: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const gallerySlice = createSlice({
|
export const gallerySlice = createSlice({
|
||||||
@ -82,9 +81,6 @@ export const gallerySlice = createSlice({
|
|||||||
isImageViewerOpenChanged: (state, action: PayloadAction<boolean>) => {
|
isImageViewerOpenChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
state.isImageViewerOpen = action.payload;
|
state.isImageViewerOpen = action.payload;
|
||||||
},
|
},
|
||||||
isFloatingImageViewerOpenChanged: (state, action: PayloadAction<boolean>) => {
|
|
||||||
state.isFloatingImageViewerOpen = action.payload;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(setActiveTab, (state) => {
|
builder.addCase(setActiveTab, (state) => {
|
||||||
@ -129,7 +125,6 @@ export const {
|
|||||||
moreImagesLoaded,
|
moreImagesLoaded,
|
||||||
alwaysShowImageSizeBadgeChanged,
|
alwaysShowImageSizeBadgeChanged,
|
||||||
isImageViewerOpenChanged,
|
isImageViewerOpenChanged,
|
||||||
isFloatingImageViewerOpenChanged,
|
|
||||||
} = gallerySlice.actions;
|
} = gallerySlice.actions;
|
||||||
|
|
||||||
const isAnyBoardDeleted = isAnyOf(
|
const isAnyBoardDeleted = isAnyOf(
|
||||||
|
@ -21,5 +21,4 @@ export type GalleryState = {
|
|||||||
limit: number;
|
limit: number;
|
||||||
alwaysShowImageSizeBadge: boolean;
|
alwaysShowImageSizeBadge: boolean;
|
||||||
isImageViewerOpen: boolean;
|
isImageViewerOpen: boolean;
|
||||||
isFloatingImageViewerOpen: boolean;
|
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,6 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|||||||
import { $customNavComponent } from 'app/store/nanostores/customNavComponent';
|
import { $customNavComponent } from 'app/store/nanostores/customNavComponent';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
|
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
|
||||||
import { ToggleFloatingImageViewerButton } from 'features/gallery/components/ImageViewer/FloatingImageViewer';
|
|
||||||
import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer';
|
import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer';
|
||||||
import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup';
|
import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup';
|
||||||
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
|
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
|
||||||
@ -224,7 +223,6 @@ const InvokeTabs = () => {
|
|||||||
</TabList>
|
</TabList>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<StatusIndicator />
|
<StatusIndicator />
|
||||||
<ToggleFloatingImageViewerButton />
|
|
||||||
{customNavComponent ? customNavComponent : <SettingsMenu />}
|
{customNavComponent ? customNavComponent : <SettingsMenu />}
|
||||||
</Flex>
|
</Flex>
|
||||||
<PanelGroup
|
<PanelGroup
|
||||||
|
Reference in New Issue
Block a user