Improves gallery resize behaviour

This commit is contained in:
psychedelicious 2022-11-21 14:13:21 +11:00 committed by blessedcoolant
parent c787a3a801
commit d9c7a28c90

View File

@ -1,11 +1,10 @@
import { Button } from '@chakra-ui/button'; import { Button } from '@chakra-ui/button';
import { NumberSize, Resizable } from 're-resizable'; import { NumberSize, Resizable } from 're-resizable';
import { import React, {
ChangeEvent, ChangeEvent,
useCallback, useCallback,
useEffect, useEffect,
useLayoutEffect,
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
@ -29,7 +28,7 @@ import {
} from 'features/gallery/store/gallerySlice'; } from 'features/gallery/store/gallerySlice';
import HoverableImage from './HoverableImage'; import HoverableImage from './HoverableImage';
import { setShouldShowGallery } from 'features/gallery/store/gallerySlice'; import { setShouldShowGallery } from 'features/gallery/store/gallerySlice';
import { ButtonGroup, useToast } from '@chakra-ui/react'; import { ButtonGroup } from '@chakra-ui/react';
import { CSSTransition } from 'react-transition-group'; import { CSSTransition } from 'react-transition-group';
import { Direction } from 're-resizable/lib/resizer'; import { Direction } from 're-resizable/lib/resizer';
import { imageGallerySelector } from 'features/gallery/store/gallerySliceSelectors'; import { imageGallerySelector } from 'features/gallery/store/gallerySliceSelectors';
@ -41,12 +40,24 @@ import IAICheckbox from 'common/components/IAICheckbox';
import { setDoesCanvasNeedScaling } from 'features/canvas/store/canvasSlice'; import { setDoesCanvasNeedScaling } from 'features/canvas/store/canvasSlice';
import _ from 'lodash'; import _ from 'lodash';
import IAIButton from 'common/components/IAIButton'; import IAIButton from 'common/components/IAIButton';
import { InvokeTabName } from 'features/tabs/components/InvokeTabs';
const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 320; const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 320;
const GALLERY_IMAGE_WIDTH_OFFSET = 40;
const GALLERY_TAB_WIDTHS: Record<
InvokeTabName,
{ galleryMinWidth: number; galleryMaxWidth: number }
> = {
txt2img: { galleryMinWidth: 200, galleryMaxWidth: 500 },
img2img: { galleryMinWidth: 200, galleryMaxWidth: 500 },
unifiedCanvas: { galleryMinWidth: 200, galleryMaxWidth: 500 },
nodes: { galleryMinWidth: 200, galleryMaxWidth: 500 },
postprocess: { galleryMinWidth: 200, galleryMaxWidth: 500 },
};
export default function ImageGallery() { export default function ImageGallery() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const toast = useToast();
const { const {
images, images,
@ -67,45 +78,15 @@ export default function ImageGallery() {
isStaging, isStaging,
} = useAppSelector(imageGallerySelector); } = useAppSelector(imageGallerySelector);
const [galleryMinWidth, setGalleryMinWidth] = useState<number>(300); const { galleryMinWidth, galleryMaxWidth } =
const [galleryMaxWidth, setGalleryMaxWidth] = useState<number>(590); GALLERY_TAB_WIDTHS[activeTabName];
const [shouldShowButtons, setShouldShowButtons] = useState<boolean>( const [shouldShowButtons, setShouldShowButtons] = useState<boolean>(
galleryWidth >= GALLERY_SHOW_BUTTONS_MIN_WIDTH galleryWidth >= GALLERY_SHOW_BUTTONS_MIN_WIDTH
); );
useLayoutEffect(() => { const [isResizing, setIsResizing] = useState(false);
if (!shouldPinGallery) return; const [galleryResizeHeight, setGalleryResizeHeight] = useState(0);
if (isLightBoxOpen) {
dispatch(setGalleryWidth(400));
setGalleryMinWidth(400);
setGalleryMaxWidth(400);
return;
}
if (activeTabName === 'unifiedCanvas') {
setGalleryMinWidth(190);
setGalleryMaxWidth(190);
dispatch(setDoesCanvasNeedScaling(true));
} else if (activeTabName === 'img2img') {
dispatch(
setGalleryWidth(Math.min(Math.max(Number(galleryWidth), 0), 490))
);
setGalleryMaxWidth(490);
} else {
dispatch(
setGalleryWidth(Math.min(Math.max(Number(galleryWidth), 0), 590))
);
setGalleryMaxWidth(590);
}
}, [dispatch, activeTabName, shouldPinGallery, galleryWidth, isLightBoxOpen]);
useLayoutEffect(() => {
if (!shouldPinGallery) {
setGalleryMaxWidth(window.innerWidth);
}
}, [shouldPinGallery, isLightBoxOpen]);
const galleryRef = useRef<HTMLDivElement>(null); const galleryRef = useRef<HTMLDivElement>(null);
const galleryContainerRef = useRef<HTMLDivElement>(null); const galleryContainerRef = useRef<HTMLDivElement>(null);
@ -141,7 +122,6 @@ export default function ImageGallery() {
const handleChangeGalleryImageMinimumWidth = (v: number) => { const handleChangeGalleryImageMinimumWidth = (v: number) => {
dispatch(setGalleryImageMinimumWidth(v)); dispatch(setGalleryImageMinimumWidth(v));
// dispatch(setDoesCanvasNeedScaling(true));
}; };
const setCloseGalleryTimer = () => { const setCloseGalleryTimer = () => {
@ -208,28 +188,13 @@ export default function ImageGallery() {
useHotkeys( useHotkeys(
'shift+up', 'shift+up',
() => { () => {
if (galleryImageMinimumWidth >= 256) {
return;
}
if (galleryImageMinimumWidth < 256) { if (galleryImageMinimumWidth < 256) {
const newMinWidth = galleryImageMinimumWidth + IMAGE_SIZE_STEP; const newMinWidth = _.clamp(
if (newMinWidth <= 256) { galleryImageMinimumWidth + IMAGE_SIZE_STEP,
dispatch(setGalleryImageMinimumWidth(newMinWidth)); 32,
toast({ 256
title: `Gallery Thumbnail Size set to ${newMinWidth}`, );
status: 'success', dispatch(setGalleryImageMinimumWidth(newMinWidth));
duration: 1000,
isClosable: true,
});
} else {
dispatch(setGalleryImageMinimumWidth(256));
toast({
title: `Gallery Thumbnail Size set to 256`,
status: 'success',
duration: 1000,
isClosable: true,
});
}
} }
}, },
[galleryImageMinimumWidth] [galleryImageMinimumWidth]
@ -238,28 +203,13 @@ export default function ImageGallery() {
useHotkeys( useHotkeys(
'shift+down', 'shift+down',
() => { () => {
if (galleryImageMinimumWidth <= 32) {
return;
}
if (galleryImageMinimumWidth > 32) { if (galleryImageMinimumWidth > 32) {
const newMinWidth = galleryImageMinimumWidth - IMAGE_SIZE_STEP; const newMinWidth = _.clamp(
if (newMinWidth > 32) { galleryImageMinimumWidth - IMAGE_SIZE_STEP,
dispatch(setGalleryImageMinimumWidth(newMinWidth)); 32,
toast({ 256
title: `Gallery Thumbnail Size set to ${newMinWidth}`, );
status: 'success', dispatch(setGalleryImageMinimumWidth(newMinWidth));
duration: 1000,
isClosable: true,
});
} else {
dispatch(setGalleryImageMinimumWidth(32));
toast({
title: `Gallery Thumbnail Size set to 32`,
status: 'success',
duration: 1000,
isClosable: true,
});
}
} }
}, },
[galleryImageMinimumWidth] [galleryImageMinimumWidth]
@ -271,10 +221,6 @@ export default function ImageGallery() {
galleryContainerRef.current.scrollTop = galleryScrollPosition; galleryContainerRef.current.scrollTop = galleryScrollPosition;
}, [galleryScrollPosition, shouldShowGallery]); }, [galleryScrollPosition, shouldShowGallery]);
useEffect(() => {
setShouldShowButtons(galleryWidth >= 280);
}, [galleryWidth]);
useEffect(() => { useEffect(() => {
function handleClickOutside(e: MouseEvent) { function handleClickOutside(e: MouseEvent) {
if ( if (
@ -310,7 +256,7 @@ export default function ImageGallery() {
> >
<Resizable <Resizable
minWidth={galleryMinWidth} minWidth={galleryMinWidth}
maxWidth={galleryMaxWidth} maxWidth={shouldPinGallery ? galleryMaxWidth : undefined}
className={'image-gallery-popup'} className={'image-gallery-popup'}
handleStyles={{ left: { width: '15px' } }} handleStyles={{ left: { width: '15px' } }}
enable={{ left: true }} enable={{ left: true }}
@ -318,22 +264,48 @@ export default function ImageGallery() {
width: galleryWidth, width: galleryWidth,
height: shouldPinGallery ? '100%' : '100vh', height: shouldPinGallery ? '100%' : '100vh',
}} }}
onResizeStart={(
_event:
| React.MouseEvent<HTMLElement>
| React.TouchEvent<HTMLElement>,
_direction: Direction,
elementRef: HTMLElement
) => {
setGalleryResizeHeight(elementRef.clientHeight);
elementRef.style.height = `${elementRef.clientHeight}px`;
if (shouldPinGallery) {
elementRef.style.position = 'fixed';
elementRef.style.right = '1rem';
setIsResizing(true);
}
}}
onResizeStop={( onResizeStop={(
_event: MouseEvent | TouchEvent, _event: MouseEvent | TouchEvent,
_direction: Direction, _direction: Direction,
elementRef: HTMLElement, elementRef: HTMLElement,
delta: NumberSize delta: NumberSize
) => { ) => {
dispatch( const newWidth = shouldPinGallery
setGalleryWidth( ? _.clamp(
_.clamp(
Number(galleryWidth) + delta.width, Number(galleryWidth) + delta.width,
0, galleryMinWidth,
Number(galleryMaxWidth) Number(galleryMaxWidth)
) )
) : Number(galleryWidth) + delta.width;
); dispatch(setGalleryWidth(newWidth));
elementRef.removeAttribute('data-resize-alert'); elementRef.removeAttribute('data-resize-alert');
if (shouldPinGallery) {
elementRef.style.position = 'relative';
elementRef.style.removeProperty('right');
elementRef.style.setProperty(
'height',
shouldPinGallery ? '100%' : '100vh'
);
setIsResizing(false);
dispatch(setDoesCanvasNeedScaling(true));
}
}} }}
onResize={( onResize={(
_event: MouseEvent | TouchEvent, _event: MouseEvent | TouchEvent,
@ -343,21 +315,42 @@ export default function ImageGallery() {
) => { ) => {
const newWidth = _.clamp( const newWidth = _.clamp(
Number(galleryWidth) + delta.width, Number(galleryWidth) + delta.width,
0, galleryMinWidth,
Number(galleryMaxWidth) Number(galleryMaxWidth)
); );
if (newWidth >= 315 && !shouldShowButtons) { if (
newWidth >= GALLERY_SHOW_BUTTONS_MIN_WIDTH &&
!shouldShowButtons
) {
setShouldShowButtons(true); setShouldShowButtons(true);
} else if (newWidth < 315 && shouldShowButtons) { } else if (
newWidth < GALLERY_SHOW_BUTTONS_MIN_WIDTH &&
shouldShowButtons
) {
setShouldShowButtons(false); setShouldShowButtons(false);
} }
if (newWidth >= galleryMaxWidth) { if (
elementRef.setAttribute('data-resize-alert', 'true'); galleryImageMinimumWidth >
} else { newWidth - GALLERY_IMAGE_WIDTH_OFFSET
elementRef.removeAttribute('data-resize-alert'); ) {
dispatch(
setGalleryImageMinimumWidth(
newWidth - GALLERY_IMAGE_WIDTH_OFFSET
)
);
} }
if (shouldPinGallery) {
if (newWidth >= galleryMaxWidth) {
elementRef.setAttribute('data-resize-alert', 'true');
} else {
elementRef.removeAttribute('data-resize-alert');
}
}
elementRef.style.height = `${galleryResizeHeight}px`;
}} }}
> >
<div className="image-gallery-header"> <div className="image-gallery-header">
@ -513,6 +506,14 @@ export default function ImageGallery() {
)} )}
</div> </div>
</Resizable> </Resizable>
{isResizing && (
<div
style={{
width: galleryWidth + 'px',
height: '100%',
}}
/>
)}
</div> </div>
</CSSTransition> </CSSTransition>
); );