Refactors gallery resizing, persists width

This commit is contained in:
psychedelicious 2022-10-29 16:30:51 +11:00
parent 9fc6ee0c4c
commit f22f81b4ff
5 changed files with 148 additions and 151 deletions

View File

@ -59,6 +59,7 @@ const galleryPersistConfig = {
key: 'gallery', key: 'gallery',
storage, storage,
whitelist: [ whitelist: [
'galleryWidth',
'shouldPinGallery', 'shouldPinGallery',
'shouldShowGallery', 'shouldShowGallery',
'galleryScrollPosition', 'galleryScrollPosition',

View File

@ -52,9 +52,15 @@
.image-gallery-header { .image-gallery-header {
display: flex; display: flex;
justify-content: end;
align-items: center; align-items: center;
column-gap: 0.5rem; column-gap: 0.5rem;
justify-content: space-between;
div {
display: flex;
column-gap: 0.5rem;
column-gap: 0.5rem;
}
.image-gallery-icon-btn { .image-gallery-icon-btn {
background-color: var(--btn-load-more) !important; background-color: var(--btn-load-more) !important;

View File

@ -15,6 +15,7 @@ import {
setGalleryImageMinimumWidth, setGalleryImageMinimumWidth,
setGalleryImageObjectFit, setGalleryImageObjectFit,
setGalleryScrollPosition, setGalleryScrollPosition,
setGalleryWidth,
setShouldAutoSwitchToNewImages, setShouldAutoSwitchToNewImages,
setShouldHoldGalleryOpen, setShouldHoldGalleryOpen,
setShouldPinGallery, setShouldPinGallery,
@ -33,6 +34,8 @@ import IAICheckbox from '../../common/components/IAICheckbox';
import { setNeedsCache } from '../tabs/Inpainting/inpaintingSlice'; import { setNeedsCache } from '../tabs/Inpainting/inpaintingSlice';
import _ from 'lodash'; import _ from 'lodash';
const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 320;
export default function ImageGallery() { export default function ImageGallery() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const toast = useToast(); const toast = useToast();
@ -51,71 +54,39 @@ export default function ImageGallery() {
shouldHoldGalleryOpen, shouldHoldGalleryOpen,
shouldAutoSwitchToNewImages, shouldAutoSwitchToNewImages,
areMoreImagesAvailable, areMoreImagesAvailable,
galleryWidth,
} = useAppSelector(imageGallerySelector); } = useAppSelector(imageGallerySelector);
const [gallerySize, setGallerySize] = useState<Size>({ const [galleryMinWidth, setGalleryMinWidth] = useState<number>(300);
width: '300', const [galleryMaxWidth, setGalleryMaxWidth] = useState<number>(590);
height: '100%',
});
const [galleryMaxSize, setGalleryMaxSize] = useState<Size>({ const [shouldShowButtons, setShouldShowButtons] = useState<boolean>(
width: '590', // keep max at 590 for any tab galleryWidth >= GALLERY_SHOW_BUTTONS_MIN_WIDTH
height: '100%', );
});
const [galleryMinSize, setGalleryMinSize] = useState<Size>({
width: '300', // keep max at 590 for any tab
height: '100%',
});
console.log(gallerySize, galleryMaxSize, galleryMinSize);
useEffect(() => { useEffect(() => {
if (activeTabName === 'inpainting' && shouldPinGallery) { if (!shouldPinGallery) return;
setGalleryMinSize((prevSize) => {
return { ...prevSize, width: 220 }; if (activeTabName === 'inpainting') {
}); dispatch(setGalleryWidth(220));
setGalleryMaxSize((prevSize) => { setGalleryMinWidth(220);
return { ...prevSize, width: 220 }; setGalleryMaxWidth(220);
}); } else if (activeTabName === 'img2img') {
setGallerySize((prevSize) => { dispatch(
return { setGalleryWidth(Math.min(Math.max(Number(galleryWidth), 0), 490))
...prevSize, );
width: Math.min(Math.max(Number(prevSize.width), 0), 220), setGalleryMaxWidth(490);
};
});
} else if (activeTabName === 'img2img' && shouldPinGallery) {
setGalleryMaxSize((prevSize) => {
return { ...prevSize, width: 490, height: '100%' };
});
setGallerySize((prevSize) => {
return {
...prevSize,
width: Math.min(Math.max(Number(prevSize.width), 0), 490),
};
});
} else { } else {
setGalleryMaxSize((prevSize) => { dispatch(
return { ...prevSize, width: 590, height: '100%' }; setGalleryWidth(Math.min(Math.max(Number(galleryWidth), 0), 590))
}); );
setGallerySize((prevSize) => { setGalleryMaxWidth(590);
return {
...prevSize,
width: Math.min(Math.max(Number(prevSize.width), 0), 590),
};
});
} }
}, [activeTabName, shouldPinGallery]); }, [dispatch, activeTabName, shouldPinGallery, galleryWidth]);
useEffect(() => { useEffect(() => {
if (!shouldPinGallery) { if (!shouldPinGallery) {
setGalleryMaxSize((prevSize) => { setGalleryMaxWidth(window.innerWidth);
// calculate vh in px
return {
...prevSize,
width: window.innerWidth,
};
});
} }
}, [shouldPinGallery]); }, [shouldPinGallery]);
@ -126,10 +97,6 @@ export default function ImageGallery() {
const handleSetShouldPinGallery = () => { const handleSetShouldPinGallery = () => {
dispatch(setNeedsCache(true)); dispatch(setNeedsCache(true));
dispatch(setShouldPinGallery(!shouldPinGallery)); dispatch(setShouldPinGallery(!shouldPinGallery));
setGallerySize({
...gallerySize,
height: shouldPinGallery ? '100vh' : '100%',
});
}; };
const handleToggleGallery = () => { const handleToggleGallery = () => {
@ -300,9 +267,9 @@ export default function ImageGallery() {
onMouseOver={!shouldPinGallery ? cancelCloseGalleryTimer : undefined} onMouseOver={!shouldPinGallery ? cancelCloseGalleryTimer : undefined}
> >
<Resizable <Resizable
minWidth={galleryMinSize.width} minWidth={galleryMinWidth}
maxWidth={galleryMaxSize.width} maxWidth={galleryMaxWidth}
maxHeight={'100%'} // maxHeight={'100%'}
className={'image-gallery-popup'} className={'image-gallery-popup'}
handleStyles={{ left: { width: '15px' } }} handleStyles={{ left: { width: '15px' } }}
enable={{ enable={{
@ -315,17 +282,25 @@ export default function ImageGallery() {
bottomLeft: false, bottomLeft: false,
topLeft: false, topLeft: false,
}} }}
size={gallerySize} size={{
width: galleryWidth,
height: shouldPinGallery ? '100%' : '100vh',
}}
onResizeStop={( onResizeStop={(
_event: MouseEvent | TouchEvent, _event: MouseEvent | TouchEvent,
_direction: Direction, _direction: Direction,
elementRef: HTMLElement, elementRef: HTMLElement,
delta: NumberSize delta: NumberSize
) => { ) => {
setGallerySize({ dispatch(
width: _.clamp(Number(gallerySize.width) + delta.width, 0, Number(galleryMaxSize.width)), setGalleryWidth(
height: '100%', _.clamp(
}); Number(galleryWidth) + delta.width,
0,
Number(galleryMaxWidth)
)
)
);
elementRef.removeAttribute('data-resize-alert'); elementRef.removeAttribute('data-resize-alert');
}} }}
onResize={( onResize={(
@ -335,18 +310,21 @@ export default function ImageGallery() {
delta: NumberSize delta: NumberSize
) => { ) => {
const newWidth = _.clamp( const newWidth = _.clamp(
Number(gallerySize.width) + delta.width, Number(galleryWidth) + delta.width,
0, 0,
Number(galleryMaxSize.width) Number(galleryMaxWidth)
); );
if (newWidth >= galleryMaxSize.width) {
if (newWidth >= 320 && !shouldShowButtons) {
setShouldShowButtons(true);
} else if (newWidth < 320 && shouldShowButtons) {
setShouldShowButtons(false);
}
if (newWidth >= galleryMaxWidth) {
elementRef.setAttribute('data-resize-alert', 'true'); elementRef.setAttribute('data-resize-alert', 'true');
} else { } else {
elementRef.removeAttribute('data-resize-alert'); elementRef.removeAttribute('data-resize-alert');
setGallerySize({
width: newWidth,
height: '100%',
});
} }
}} }}
> >
@ -358,7 +336,7 @@ export default function ImageGallery() {
variant="solid" variant="solid"
className="image-gallery-category-btn-group" className="image-gallery-category-btn-group"
> >
{gallerySize.width > 320 ? ( {shouldShowButtons ? (
<> <>
<Button <Button
data-selected={currentCategory === 'result'} data-selected={currentCategory === 'result'}
@ -393,88 +371,92 @@ export default function ImageGallery() {
)} )}
</ButtonGroup> </ButtonGroup>
</div> </div>
<IAIPopover <div>
trigger="hover" <IAIPopover
hasArrow={activeTabName === 'inpainting' ? false : true} trigger="hover"
placement={'left'} hasArrow={activeTabName === 'inpainting' ? false : true}
triggerComponent={ placement={'left'}
<IAIIconButton triggerComponent={
size={'sm'}
aria-label={'Gallery Settings'}
icon={<FaWrench />}
className="image-gallery-icon-btn"
cursor={'pointer'}
/>
}
>
<div className="image-gallery-settings-popover">
<div>
<IAISlider
value={galleryImageMinimumWidth}
onChange={handleChangeGalleryImageMinimumWidth}
min={32}
max={256}
width={100}
label={'Image Size'}
formLabelProps={{ style: { fontSize: '0.9rem' } }}
sliderThumbTooltipProps={{
label: `${galleryImageMinimumWidth}px`,
}}
/>
<IAIIconButton <IAIIconButton
size={'sm'} size={'sm'}
aria-label={'Reset'} aria-label={'Gallery Settings'}
tooltip={'Reset Size'} icon={<FaWrench />}
onClick={() => dispatch(setGalleryImageMinimumWidth(64))} className="image-gallery-icon-btn"
icon={<BiReset />} cursor={'pointer'}
data-selected={shouldPinGallery}
styleClass="image-gallery-icon-btn"
/> />
</div> }
<div> >
<IAICheckbox <div className="image-gallery-settings-popover">
label="Maintain Aspect Ratio" <div>
isChecked={galleryImageObjectFit === 'contain'} <IAISlider
onChange={() => value={galleryImageMinimumWidth}
dispatch( onChange={handleChangeGalleryImageMinimumWidth}
setGalleryImageObjectFit( min={32}
galleryImageObjectFit === 'contain' max={256}
? 'cover' width={100}
: 'contain' label={'Image Size'}
formLabelProps={{ style: { fontSize: '0.9rem' } }}
sliderThumbTooltipProps={{
label: `${galleryImageMinimumWidth}px`,
}}
/>
<IAIIconButton
size={'sm'}
aria-label={'Reset'}
tooltip={'Reset Size'}
onClick={() => dispatch(setGalleryImageMinimumWidth(64))}
icon={<BiReset />}
data-selected={shouldPinGallery}
styleClass="image-gallery-icon-btn"
/>
</div>
<div>
<IAICheckbox
label="Maintain Aspect Ratio"
isChecked={galleryImageObjectFit === 'contain'}
onChange={() =>
dispatch(
setGalleryImageObjectFit(
galleryImageObjectFit === 'contain'
? 'cover'
: 'contain'
)
) )
) }
} />
/> </div>
<div>
<IAICheckbox
label="Auto-Switch to New Images"
isChecked={shouldAutoSwitchToNewImages}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
dispatch(
setShouldAutoSwitchToNewImages(e.target.checked)
)
}
/>
</div>
</div> </div>
<div> </IAIPopover>
<IAICheckbox
label="Auto-Switch to New Images"
isChecked={shouldAutoSwitchToNewImages}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
dispatch(setShouldAutoSwitchToNewImages(e.target.checked))
}
/>
</div>
</div>
</IAIPopover>
<IAIIconButton <IAIIconButton
size={'sm'} size={'sm'}
aria-label={'Pin Gallery'} aria-label={'Pin Gallery'}
tooltip={'Pin Gallery (Shift+P)'} tooltip={'Pin Gallery (Shift+P)'}
onClick={handleSetShouldPinGallery} onClick={handleSetShouldPinGallery}
icon={<BsPinAngleFill />} icon={<BsPinAngleFill />}
data-selected={shouldPinGallery} data-selected={shouldPinGallery}
/> />
<IAIIconButton <IAIIconButton
size={'sm'} size={'sm'}
aria-label={'Close Gallery'} aria-label={'Close Gallery'}
tooltip={'Close Gallery (G)'} tooltip={'Close Gallery (G)'}
onClick={handleCloseGallery} onClick={handleCloseGallery}
className="image-gallery-icon-btn" className="image-gallery-icon-btn"
icon={<MdClear />} icon={<MdClear />}
/> />
</div>
</div> </div>
<div className="image-gallery-container" ref={galleryContainerRef}> <div className="image-gallery-container" ref={galleryContainerRef}>
{images.length || areMoreImagesAvailable ? ( {images.length || areMoreImagesAvailable ? (

View File

@ -36,6 +36,7 @@ export interface GalleryState {
result: Gallery; result: Gallery;
}; };
currentCategory: GalleryCategory; currentCategory: GalleryCategory;
galleryWidth: number;
} }
const initialState: GalleryState = { const initialState: GalleryState = {
@ -62,6 +63,7 @@ const initialState: GalleryState = {
areMoreImagesAvailable: true, areMoreImagesAvailable: true,
}, },
}, },
galleryWidth: 300,
}; };
export const gallerySlice = createSlice({ export const gallerySlice = createSlice({
@ -248,6 +250,9 @@ export const gallerySlice = createSlice({
setCurrentCategory: (state, action: PayloadAction<GalleryCategory>) => { setCurrentCategory: (state, action: PayloadAction<GalleryCategory>) => {
state.currentCategory = action.payload; state.currentCategory = action.payload;
}, },
setGalleryWidth: (state, action: PayloadAction<number>) => {
state.galleryWidth = action.payload;
},
}, },
}); });
@ -268,6 +273,7 @@ export const {
setShouldHoldGalleryOpen, setShouldHoldGalleryOpen,
setShouldAutoSwitchToNewImages, setShouldAutoSwitchToNewImages,
setCurrentCategory, setCurrentCategory,
setGalleryWidth,
} = gallerySlice.actions; } = gallerySlice.actions;
export default gallerySlice.reducer; export default gallerySlice.reducer;

View File

@ -18,6 +18,7 @@ export const imageGallerySelector = createSelector(
galleryImageObjectFit, galleryImageObjectFit,
shouldHoldGalleryOpen, shouldHoldGalleryOpen,
shouldAutoSwitchToNewImages, shouldAutoSwitchToNewImages,
galleryWidth,
} = gallery; } = gallery;
const { activeTab } = options; const { activeTab } = options;
@ -37,6 +38,7 @@ export const imageGallerySelector = createSelector(
areMoreImagesAvailable: areMoreImagesAvailable:
categories[currentCategory].areMoreImagesAvailable, categories[currentCategory].areMoreImagesAvailable,
currentCategory, currentCategory,
galleryWidth,
}; };
} }
); );