Adds next/prev image buttons/hotkeys

This commit is contained in:
psychedelicious 2022-10-06 18:24:40 +08:00 committed by blessedcoolant
parent 0c1c220bb9
commit 58d73f5cae
4 changed files with 141 additions and 3 deletions

View File

@ -67,6 +67,44 @@
}
}
.current-image-next-prev-buttons {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: space-between;
width: calc(100% - 2rem);
padding: 0.5rem;
margin-left: 1rem;
z-index: 1;
height: calc($app-metadata-height - 1rem);
pointer-events: none;
}
.next-prev-button-trigger-area {
width: 7rem;
height: 100%;
display: flex;
align-items: center;
pointer-events: auto;
&.prev-button-trigger-area {
justify-content: flex-start;
}
&.next-button-trigger-area {
justify-content: flex-end;
}
}
.next-prev-button {
font-size: 5rem;
fill: var(--text-color-secondary);
filter: drop-shadow(0 0 1rem var(--text-color-secondary));
opacity: 70%;
}
.current-image-metadata-viewer {
border-radius: 0.5rem;
position: absolute;

View File

@ -1,15 +1,21 @@
import { Image } from '@chakra-ui/react';
import { useAppSelector } from '../../app/store';
import { IconButton, Image } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from '../../app/store';
import { RootState } from '../../app/store';
import { useState } from 'react';
import ImageMetadataViewer from './ImageMetadataViewer';
import CurrentImageButtons from './CurrentImageButtons';
import { MdPhoto } from 'react-icons/md';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
import { selectNextImage, selectPrevImage } from './gallerySlice';
/**
* Displays the current image if there is one, plus associated actions.
*/
const CurrentImageDisplay = () => {
const dispatch = useAppDispatch();
const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] =
useState<boolean>(false);
const { currentImage, intermediateImage } = useAppSelector(
(state: RootState) => state.gallery
);
@ -19,6 +25,22 @@ const CurrentImageDisplay = () => {
const imageToDisplay = intermediateImage || currentImage;
const handleCurrentImagePreviewMouseOver = () => {
setShouldShowNextPrevButtons(true);
};
const handleCurrentImagePreviewMouseOut = () => {
setShouldShowNextPrevButtons(false);
};
const handleClickPrevButton = () => {
dispatch(selectPrevImage());
};
const handleClickNextButton = () => {
dispatch(selectNextImage());
};
return imageToDisplay ? (
<div className="current-image-display">
<div className="current-image-tools">
@ -40,6 +62,38 @@ const CurrentImageDisplay = () => {
<ImageMetadataViewer image={imageToDisplay} />
</div>
)}
{!shouldShowImageDetails && (
<div className="current-image-next-prev-buttons">
<div
className="next-prev-button-trigger-area prev-button-trigger-area"
onMouseOver={handleCurrentImagePreviewMouseOver}
onMouseOut={handleCurrentImagePreviewMouseOut}
>
{shouldShowNextPrevButtons && (
<IconButton
aria-label="Previous image"
icon={<FaAngleLeft className="next-prev-button" />}
variant="unstyled"
onClick={handleClickPrevButton}
/>
)}
</div>
<div
className="next-prev-button-trigger-area next-button-trigger-area"
onMouseOver={handleCurrentImagePreviewMouseOver}
onMouseOut={handleCurrentImagePreviewMouseOut}
>
{shouldShowNextPrevButtons && (
<IconButton
aria-label="Next image"
icon={<FaAngleRight className="next-prev-button" />}
variant="unstyled"
onClick={handleClickNextButton}
/>
)}
</div>
</div>
)}
</div>
</div>
) : (

View File

@ -1,8 +1,10 @@
import { Button } from '@chakra-ui/react';
import { useHotkeys } from 'react-hotkeys-hook';
import { MdPhotoLibrary } from 'react-icons/md';
import { requestImages } from '../../app/socketio/actions';
import { RootState, useAppDispatch } from '../../app/store';
import { useAppSelector } from '../../app/store';
import { selectNextImage, selectPrevImage } from './gallerySlice';
import HoverableImage from './HoverableImage';
/**
@ -25,6 +27,22 @@ const ImageGallery = () => {
dispatch(requestImages());
};
useHotkeys(
'left',
() => {
dispatch(selectPrevImage());
},
[]
);
useHotkeys(
'right',
() => {
dispatch(selectNextImage());
},
[]
);
return (
<div className="image-gallery-container">
{images.length ? (

View File

@ -1,6 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import { clamp } from 'lodash';
import _, { clamp } from 'lodash';
import * as InvokeAI from '../../app/invokeai';
export interface GalleryState {
@ -85,6 +85,32 @@ export const gallerySlice = createSlice({
clearIntermediateImage: (state) => {
state.intermediateImage = undefined;
},
selectNextImage: (state) => {
const { images, currentImage } = state;
if (currentImage) {
const currentImageIndex = images.findIndex(
(i) => i.uuid === currentImage.uuid
);
if (_.inRange(currentImageIndex, 0, images.length)) {
const newCurrentImage = images[currentImageIndex + 1];
state.currentImage = newCurrentImage;
state.currentImageUuid = newCurrentImage.uuid;
}
}
},
selectPrevImage: (state) => {
const { images, currentImage } = state;
if (currentImage) {
const currentImageIndex = images.findIndex(
(i) => i.uuid === currentImage.uuid
);
if (_.inRange(currentImageIndex, 1, images.length + 1)) {
const newCurrentImage = images[currentImageIndex - 1];
state.currentImage = newCurrentImage;
state.currentImageUuid = newCurrentImage.uuid;
}
}
},
addGalleryImages: (
state,
action: PayloadAction<{
@ -122,6 +148,8 @@ export const {
setCurrentImage,
addGalleryImages,
setIntermediateImage,
selectNextImage,
selectPrevImage,
} = gallerySlice.actions;
export default gallerySlice.reducer;