From 578d8b0cb4092e879bb171ac2f34297d9330223a Mon Sep 17 00:00:00 2001
From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com>
Date: Sat, 8 Oct 2022 13:15:30 +1300
Subject: [PATCH] Add Image Gallery Drawer
---
frontend/src/app/App.scss | 4 +
frontend/src/app/App.tsx | 4 +-
.../features/gallery/CurrentImageDisplay.scss | 32 ++--
.../src/features/gallery/ImageGallery.scss | 93 ++++++++---
.../src/features/gallery/ImageGallery.tsx | 144 +++++++++++-------
.../src/features/gallery/ImageGalleryOld.tsx | 129 ++++++++++++++++
.../ImageMetadataViewer.scss | 4 +-
frontend/src/features/gallery/gallerySlice.ts | 6 +
frontend/src/features/system/Console.tsx | 9 ++
.../system/HotkeysModal/HotkeysModal.tsx | 10 ++
.../tabs/ImageToImage/ImageToImage.scss | 20 ++-
.../tabs/ImageToImage/ImageToImage.tsx | 11 +-
.../tabs/TextToImage/TextToImage.scss | 19 ++-
.../features/tabs/TextToImage/TextToImage.tsx | 8 +-
frontend/src/styles/Mixins/_Variables.scss | 3 +
frontend/src/styles/_Animations.scss | 8 +
frontend/src/styles/_Colors_Dark.scss | 5 +-
frontend/src/styles/_Colors_Light.scss | 5 +-
frontend/src/styles/index.scss | 1 +
19 files changed, 406 insertions(+), 109 deletions(-)
create mode 100644 frontend/src/features/gallery/ImageGalleryOld.tsx
create mode 100644 frontend/src/styles/_Animations.scss
diff --git a/frontend/src/app/App.scss b/frontend/src/app/App.scss
index f9b1c9f54d..67aee81cdb 100644
--- a/frontend/src/app/App.scss
+++ b/frontend/src/app/App.scss
@@ -15,3 +15,7 @@
width: $app-width;
height: $app-height;
}
+
+.app-console {
+ z-index: 9999;
+}
diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx
index 18975e2ca9..f91bc24c51 100644
--- a/frontend/src/app/App.tsx
+++ b/frontend/src/app/App.tsx
@@ -26,7 +26,9 @@ const App = () => {
-
+
- {images.length ? (
- <>
-
- Your Invocations
-
-
- {images.map((image) => {
- const { uuid } = image;
- const isSelected = currentImageUuid === uuid;
- return (
-
- );
- })}
-
- >
- ) : (
-
+
+ {!shouldShowGallery && (
+
+
+ )}
+
+ {shouldShowGallery && (
+
+
+
Your Invocations
+ }
+ />
+
+
+ {images.length ? (
+
+ {images.map((image) => {
+ const { uuid } = image;
+ const isSelected = currentImageUuid === uuid;
+ return (
+
+ );
+ })}
+
+ ) : (
+
+
+
No Images In Gallery
+
+ )}
+
+
+
)}
-
);
-};
-
-export default ImageGallery;
+}
diff --git a/frontend/src/features/gallery/ImageGalleryOld.tsx b/frontend/src/features/gallery/ImageGalleryOld.tsx
new file mode 100644
index 0000000000..e1ff8e03bb
--- /dev/null
+++ b/frontend/src/features/gallery/ImageGalleryOld.tsx
@@ -0,0 +1,129 @@
+import {
+ Button,
+ Drawer,
+ DrawerBody,
+ DrawerCloseButton,
+ DrawerContent,
+ DrawerHeader,
+ useDisclosure,
+} from '@chakra-ui/react';
+import React from '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';
+
+/**
+ * Simple image gallery.
+ */
+const ImageGalleryOld = () => {
+ const { images, currentImageUuid, areMoreImagesAvailable } = useAppSelector(
+ (state: RootState) => state.gallery
+ );
+ const dispatch = useAppDispatch();
+
+ const { isOpen, onOpen, onClose } = useDisclosure();
+
+ /**
+ * I don't like that this needs to rerender whenever the current image is changed.
+ * What if we have a large number of images? I suppose pagination (planned) will
+ * mitigate this issue.
+ *
+ * TODO: Refactor if performance complaints, or after migrating to new API which supports pagination.
+ */
+
+ const handleClickLoadMore = () => {
+ dispatch(requestImages());
+ };
+
+ useHotkeys(
+ 'g',
+ () => {
+ if (isOpen) {
+ onClose();
+ } else {
+ onOpen();
+ }
+ },
+ [isOpen]
+ );
+
+ useHotkeys(
+ 'left',
+ () => {
+ dispatch(selectPrevImage());
+ },
+ []
+ );
+
+ useHotkeys(
+ 'right',
+ () => {
+ dispatch(selectNextImage());
+ },
+ []
+ );
+
+ return (
+
+
+
+
+
+ Your Invocations
+
+
+
+
+ {images.length ? (
+
+ {images.map((image) => {
+ const { uuid } = image;
+ const isSelected = currentImageUuid === uuid;
+ return (
+
+ );
+ })}
+
+ ) : (
+
+
+
No Images In Gallery
+
+ )}
+
+
+
+
+
+
+ );
+};
+
+export default ImageGallery;
diff --git a/frontend/src/features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss b/frontend/src/features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss
index 4eb3dc5fce..e5c33672ae 100644
--- a/frontend/src/features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss
+++ b/frontend/src/features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss
@@ -6,8 +6,8 @@
padding: 1rem;
background-color: var(--metadata-bg-color);
overflow: scroll;
- max-height: calc($app-content-height - 4rem);
- z-index: 1;
+ max-height: $app-metadata-height;
+ z-index: 10;
}
.image-json-viewer {
diff --git a/frontend/src/features/gallery/gallerySlice.ts b/frontend/src/features/gallery/gallerySlice.ts
index 415b80d326..02ec67bb20 100644
--- a/frontend/src/features/gallery/gallerySlice.ts
+++ b/frontend/src/features/gallery/gallerySlice.ts
@@ -11,12 +11,14 @@ export interface GalleryState {
areMoreImagesAvailable: boolean;
latest_mtime?: number;
earliest_mtime?: number;
+ shouldShowGallery: boolean;
}
const initialState: GalleryState = {
currentImageUuid: '',
images: [],
areMoreImagesAvailable: true,
+ shouldShowGallery: true,
};
export const gallerySlice = createSlice({
@@ -138,6 +140,9 @@ export const gallerySlice = createSlice({
state.areMoreImagesAvailable = areMoreImagesAvailable;
}
},
+ setShouldShowGallery: (state, action: PayloadAction
) => {
+ state.shouldShowGallery = action.payload;
+ },
},
});
@@ -150,6 +155,7 @@ export const {
setIntermediateImage,
selectNextImage,
selectPrevImage,
+ setShouldShowGallery,
} = gallerySlice.actions;
export default gallerySlice.reducer;
diff --git a/frontend/src/features/system/Console.tsx b/frontend/src/features/system/Console.tsx
index 799488f486..22a6632936 100644
--- a/frontend/src/features/system/Console.tsx
+++ b/frontend/src/features/system/Console.tsx
@@ -7,6 +7,7 @@ import { FaAngleDoubleDown, FaCode, FaMinus } from 'react-icons/fa';
import { createSelector } from '@reduxjs/toolkit';
import { isEqual } from 'lodash';
import { Resizable } from 're-resizable';
+import { useHotkeys } from 'react-hotkeys-hook';
const logSelector = createSelector(
(state: RootState) => state.system,
@@ -66,6 +67,14 @@ const Console = () => {
dispatch(setShouldShowLogViewer(!shouldShowLogViewer));
};
+ useHotkeys(
+ '`',
+ () => {
+ dispatch(setShouldShowLogViewer(!shouldShowLogViewer));
+ },
+ [shouldShowLogViewer]
+ );
+
return (
<>
{shouldShowLogViewer && (
diff --git a/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx b/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx
index 16fb7d6bf6..12004640ef 100644
--- a/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx
+++ b/frontend/src/features/system/HotkeysModal/HotkeysModal.tsx
@@ -23,6 +23,11 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
const hotkeys = [
{ title: 'Invoke', desc: 'Generate an image', hotkey: 'Ctrl+Enter' },
{ title: 'Cancel', desc: 'Cancel image generation', hotkey: 'Shift+X' },
+ {
+ title: 'Toggle Gallery',
+ desc: 'Open and close the gallery drawer',
+ hotkey: 'G',
+ },
{
title: 'Set Seed',
desc: 'Use the seed of the current image',
@@ -71,6 +76,11 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: 'Switch between dark and light modes',
hotkey: 'Shift+D',
},
+ {
+ title: 'Console Toggle',
+ desc: 'Open and close console',
+ hotkey: '`',
+ },
];
const renderHotkeyModalItems = () => {
diff --git a/frontend/src/features/tabs/ImageToImage/ImageToImage.scss b/frontend/src/features/tabs/ImageToImage/ImageToImage.scss
index d1c444d748..18fd97aeb2 100644
--- a/frontend/src/features/tabs/ImageToImage/ImageToImage.scss
+++ b/frontend/src/features/tabs/ImageToImage/ImageToImage.scss
@@ -2,7 +2,7 @@
.image-to-image-workarea {
display: grid;
- grid-template-columns: max-content auto max-content;
+ grid-template-columns: max-content auto;
column-gap: 1rem;
}
@@ -16,6 +16,22 @@
@include HideScrollbar;
}
+.image-to-image-display-area {
+ display: grid;
+ grid-template-areas: 'image-to-image-display-area';
+
+ .image-to-image-display {
+ grid-area: image-to-image-display-area;
+ }
+
+ .image-gallery-area {
+ grid-area: image-to-image-display-area;
+ z-index: 2;
+ place-self: end;
+ margin: 1rem;
+ }
+}
+
.image-to-image-strength-main-option {
display: grid;
grid-template-columns: none !important;
@@ -52,7 +68,7 @@
.image-to-image-dual-preview {
grid-area: img2img-preview;
display: grid;
- grid-template-columns: 1fr 1fr;
+ grid-template-columns: max-content max-content;
column-gap: 0.5rem;
padding: 0 1rem;
place-content: center;
diff --git a/frontend/src/features/tabs/ImageToImage/ImageToImage.tsx b/frontend/src/features/tabs/ImageToImage/ImageToImage.tsx
index 03a4d35d9a..585dc8f323 100644
--- a/frontend/src/features/tabs/ImageToImage/ImageToImage.tsx
+++ b/frontend/src/features/tabs/ImageToImage/ImageToImage.tsx
@@ -1,15 +1,16 @@
import React from 'react';
-import ImageGallery from '../../gallery/ImageGallery';
-import ImageToImageDisplay from './ImageToImageDisplay';
-
import ImageToImagePanel from './ImageToImagePanel';
+import ImageToImageDisplay from './ImageToImageDisplay';
+import ImageGallery from '../../gallery/ImageGallery';
export default function ImageToImage() {
return (
);
}
diff --git a/frontend/src/features/tabs/TextToImage/TextToImage.scss b/frontend/src/features/tabs/TextToImage/TextToImage.scss
index af67928b5b..843209d71b 100644
--- a/frontend/src/features/tabs/TextToImage/TextToImage.scss
+++ b/frontend/src/features/tabs/TextToImage/TextToImage.scss
@@ -2,7 +2,7 @@
.text-to-image-workarea {
display: grid;
- grid-template-columns: max-content auto max-content;
+ grid-template-columns: max-content auto;
column-gap: 1rem;
}
@@ -14,3 +14,20 @@
overflow-y: scroll;
@include HideScrollbar;
}
+
+.text-to-image-display {
+ display: grid;
+ grid-template-areas: 'text-to-image-display';
+
+ .current-image-display,
+ .current-image-display-placeholder {
+ grid-area: text-to-image-display;
+ }
+
+ .image-gallery-area {
+ grid-area: text-to-image-display;
+ z-index: 2;
+ place-self: end;
+ margin: 1rem;
+ }
+}
diff --git a/frontend/src/features/tabs/TextToImage/TextToImage.tsx b/frontend/src/features/tabs/TextToImage/TextToImage.tsx
index 476bed6e63..9b2b8f1988 100644
--- a/frontend/src/features/tabs/TextToImage/TextToImage.tsx
+++ b/frontend/src/features/tabs/TextToImage/TextToImage.tsx
@@ -1,14 +1,16 @@
import React from 'react';
+import TextToImagePanel from './TextToImagePanel';
import CurrentImageDisplay from '../../gallery/CurrentImageDisplay';
import ImageGallery from '../../gallery/ImageGallery';
-import TextToImagePanel from './TextToImagePanel';
export default function TextToImage() {
return (
);
}
diff --git a/frontend/src/styles/Mixins/_Variables.scss b/frontend/src/styles/Mixins/_Variables.scss
index cf7691669a..1f8b013e27 100644
--- a/frontend/src/styles/Mixins/_Variables.scss
+++ b/frontend/src/styles/Mixins/_Variables.scss
@@ -8,6 +8,9 @@ $app-width: calc(100vw - $app-cutoff);
$app-height: calc(100vh - $app-cutoff);
$app-content-height: calc(100vh - $app-content-height-cutoff);
$app-gallery-height: calc(100vh - ($app-content-height-cutoff + 6rem));
+$app-gallery-popover-height: calc(
+ 100vh - ($app-content-height-cutoff - 2.5rem)
+);
$app-metadata-height: calc(100vh - ($app-content-height-cutoff + 4.4rem));
// option bar
diff --git a/frontend/src/styles/_Animations.scss b/frontend/src/styles/_Animations.scss
new file mode 100644
index 0000000000..0794183a05
--- /dev/null
+++ b/frontend/src/styles/_Animations.scss
@@ -0,0 +1,8 @@
+@keyframes slideOut {
+ from {
+ transform: translateX(10rem);
+ }
+ to {
+ transform: translateX(0);
+ }
+}
diff --git a/frontend/src/styles/_Colors_Dark.scss b/frontend/src/styles/_Colors_Dark.scss
index 83e5f41678..b87fbb3fdf 100644
--- a/frontend/src/styles/_Colors_Dark.scss
+++ b/frontend/src/styles/_Colors_Dark.scss
@@ -46,7 +46,7 @@
--btn-red-hover: rgb(255, 75, 75);
--btn-load-more: rgb(30, 32, 42);
- --btn-load-more-hover: rgb(36, 38, 48);
+ --btn-load-more-hover: rgb(54, 56, 66);
// Switch
--switch-bg-color: rgb(100, 102, 110);
@@ -92,4 +92,7 @@
// Img2Img
--img2img-img-bg-color: rgb(30, 32, 42);
+
+ // Gallery
+ --gallery-resizeable-color: rgb(36, 38, 48);
}
diff --git a/frontend/src/styles/_Colors_Light.scss b/frontend/src/styles/_Colors_Light.scss
index 4d394cf601..370fabaa93 100644
--- a/frontend/src/styles/_Colors_Light.scss
+++ b/frontend/src/styles/_Colors_Light.scss
@@ -46,7 +46,7 @@
--btn-red-hover: rgb(255, 55, 55);
--btn-load-more: rgb(202, 204, 206);
- --btn-load-more-hover: rgb(206, 208, 210);
+ --btn-load-more-hover: rgb(178, 180, 182);
// Switch
--switch-bg-color: rgb(178, 180, 182);
@@ -91,4 +91,7 @@
// Img2Img
--img2img-img-bg-color: rgb(180, 182, 184);
+
+ // Gallery
+ --gallery-resizeable-color: rgb(192, 194, 196);
}
diff --git a/frontend/src/styles/index.scss b/frontend/src/styles/index.scss
index b18cc3101a..b16b8d60f4 100644
--- a/frontend/src/styles/index.scss
+++ b/frontend/src/styles/index.scss
@@ -2,6 +2,7 @@
@use 'Colors_Dark';
@use 'Colors_Light';
@use 'Fonts';
+@use 'Animations';
// Component Styles
//app