mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Add Image Gallery Drawer
This commit is contained in:
parent
2b1aaf4ee7
commit
578d8b0cb4
@ -15,3 +15,7 @@
|
|||||||
width: $app-width;
|
width: $app-width;
|
||||||
height: $app-height;
|
height: $app-height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-console {
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
@ -26,7 +26,9 @@ const App = () => {
|
|||||||
<SiteHeader />
|
<SiteHeader />
|
||||||
<InvokeTabs />
|
<InvokeTabs />
|
||||||
</div>
|
</div>
|
||||||
<Console />
|
<div className="app-console">
|
||||||
|
<Console />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Loading />
|
<Loading />
|
||||||
|
@ -11,21 +11,6 @@
|
|||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-image-display-placeholder {
|
|
||||||
background-color: var(--background-color-secondary);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 10rem;
|
|
||||||
height: 10rem;
|
|
||||||
color: var(--svg-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-image-tools {
|
.current-image-tools {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -106,3 +91,20 @@
|
|||||||
filter: drop-shadow(0 0 1rem var(--text-color-secondary));
|
filter: drop-shadow(0 0 1rem var(--text-color-secondary));
|
||||||
opacity: 70%;
|
opacity: 70%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.current-image-display-placeholder {
|
||||||
|
background-color: var(--background-color-secondary);
|
||||||
|
display: grid;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 10rem;
|
||||||
|
height: 10rem;
|
||||||
|
color: var(--svg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,43 +1,67 @@
|
|||||||
@use '../../styles/Mixins/' as *;
|
@use '../../styles/Mixins/' as *;
|
||||||
|
|
||||||
|
.image-gallery-area {
|
||||||
|
.image-gallery-popup-btn {
|
||||||
|
@include Button(
|
||||||
|
$btn-width: 3rem,
|
||||||
|
$btn-height: 3rem,
|
||||||
|
$icon-size: 22px,
|
||||||
|
$btn-color: var(--btn-grey),
|
||||||
|
$btn-color-hover: var(--btn-grey-hover)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-gallery-popup {
|
||||||
|
background-color: var(--tab-color);
|
||||||
|
position: fixed !important;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
animation: slideOut 0.3s ease-out;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-rows: max-content;
|
||||||
|
row-gap: 1rem;
|
||||||
|
border-left-width: 0.2rem;
|
||||||
|
border-color: var(--gallery-resizeable-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-gallery-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto max-content;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-gallery-close-btn {
|
||||||
|
background-color: var(--btn-load-more) !important;
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--btn-load-more-hover) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.image-gallery-container {
|
.image-gallery-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
row-gap: 1rem;
|
gap: 1rem;
|
||||||
grid-auto-rows: max-content;
|
max-height: $app-gallery-popover-height;
|
||||||
min-width: 16rem;
|
overflow-y: scroll;
|
||||||
}
|
@include HideScrollbar;
|
||||||
|
|
||||||
.image-gallery-container-placeholder {
|
|
||||||
display: grid;
|
|
||||||
background-color: var(--background-color-secondary);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
place-items: center;
|
|
||||||
padding: 2rem 0;
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: var(--subtext-color-bright);
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 5rem;
|
|
||||||
height: 5rem;
|
|
||||||
color: var(--svg-color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-gallery {
|
.image-gallery {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, max-content);
|
grid-template-columns: repeat(auto-fill, minmax(120px, auto));
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
max-height: $app-gallery-height;
|
|
||||||
overflow-y: scroll;
|
|
||||||
@include HideScrollbar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-gallery-load-more-btn {
|
.image-gallery-load-more-btn {
|
||||||
background-color: var(--btn-load-more) !important;
|
background-color: var(--btn-load-more) !important;
|
||||||
font-size: 0.85rem !important;
|
font-size: 0.85rem !important;
|
||||||
|
font-family: Inter;
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -49,3 +73,22 @@
|
|||||||
background-color: var(--btn-load-more-hover) !important;
|
background-color: var(--btn-load-more-hover) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-gallery-container-placeholder {
|
||||||
|
display: grid;
|
||||||
|
background-color: var(--background-color-secondary);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
place-items: center;
|
||||||
|
padding: 2rem 0;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: var(--subtext-color-bright);
|
||||||
|
font-family: Inter;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
color: var(--svg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,32 +1,47 @@
|
|||||||
import { Button } from '@chakra-ui/react';
|
import { Button, IconButton } from '@chakra-ui/button';
|
||||||
|
import { Resizable } from 're-resizable';
|
||||||
|
import React from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { MdPhotoLibrary } from 'react-icons/md';
|
import { MdClear, MdPhotoLibrary } from 'react-icons/md';
|
||||||
import { requestImages } from '../../app/socketio/actions';
|
import { requestImages } from '../../app/socketio/actions';
|
||||||
import { RootState, useAppDispatch } from '../../app/store';
|
import { RootState, useAppDispatch, useAppSelector } from '../../app/store';
|
||||||
import { useAppSelector } from '../../app/store';
|
import {
|
||||||
import { selectNextImage, selectPrevImage } from './gallerySlice';
|
selectNextImage,
|
||||||
|
selectPrevImage,
|
||||||
|
setShouldShowGallery,
|
||||||
|
} from './gallerySlice';
|
||||||
import HoverableImage from './HoverableImage';
|
import HoverableImage from './HoverableImage';
|
||||||
|
|
||||||
/**
|
export default function ImageGallery() {
|
||||||
* Simple image gallery.
|
const {
|
||||||
*/
|
images,
|
||||||
const ImageGallery = () => {
|
currentImageUuid,
|
||||||
const { images, currentImageUuid, areMoreImagesAvailable } = useAppSelector(
|
areMoreImagesAvailable,
|
||||||
(state: RootState) => state.gallery
|
shouldShowGallery,
|
||||||
);
|
} = useAppSelector((state: RootState) => state.gallery);
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
/**
|
|
||||||
* I don't like that this needs to rerender whenever the current image is changed.
|
const handleShowGalleryToggle = () => {
|
||||||
* What if we have a large number of images? I suppose pagination (planned) will
|
dispatch(setShouldShowGallery(!shouldShowGallery));
|
||||||
* mitigate this issue.
|
};
|
||||||
*
|
|
||||||
* TODO: Refactor if performance complaints, or after migrating to new API which supports pagination.
|
const handleGalleryClose = () => {
|
||||||
*/
|
dispatch(setShouldShowGallery(false));
|
||||||
|
};
|
||||||
|
|
||||||
const handleClickLoadMore = () => {
|
const handleClickLoadMore = () => {
|
||||||
dispatch(requestImages());
|
dispatch(requestImages());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
'g',
|
||||||
|
() => {
|
||||||
|
handleShowGalleryToggle();
|
||||||
|
},
|
||||||
|
[shouldShowGallery]
|
||||||
|
);
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
'left',
|
'left',
|
||||||
() => {
|
() => {
|
||||||
@ -44,41 +59,64 @@ const ImageGallery = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="image-gallery-container">
|
<div className="image-gallery-area">
|
||||||
{images.length ? (
|
{!shouldShowGallery && (
|
||||||
<>
|
<Button
|
||||||
<p>
|
colorScheme="teal"
|
||||||
<strong>Your Invocations</strong>
|
onClick={handleShowGalleryToggle}
|
||||||
</p>
|
className="image-gallery-popup-btn"
|
||||||
<div className="image-gallery">
|
>
|
||||||
{images.map((image) => {
|
|
||||||
const { uuid } = image;
|
|
||||||
const isSelected = currentImageUuid === uuid;
|
|
||||||
return (
|
|
||||||
<HoverableImage
|
|
||||||
key={uuid}
|
|
||||||
image={image}
|
|
||||||
isSelected={isSelected}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="image-gallery-container-placeholder">
|
|
||||||
<MdPhotoLibrary />
|
<MdPhotoLibrary />
|
||||||
<p>No Images In Gallery</p>
|
</Button>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
|
{shouldShowGallery && (
|
||||||
|
<Resizable
|
||||||
|
defaultSize={{ width: 'auto', height: '100%' }}
|
||||||
|
minWidth={'18%'}
|
||||||
|
className="image-gallery-popup"
|
||||||
|
>
|
||||||
|
<div className="image-gallery-header">
|
||||||
|
<h1>Your Invocations</h1>
|
||||||
|
<IconButton
|
||||||
|
size={'sm'}
|
||||||
|
aria-label={'Close Gallery'}
|
||||||
|
onClick={handleGalleryClose}
|
||||||
|
className="image-gallery-close-btn"
|
||||||
|
icon={<MdClear />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="image-gallery-container">
|
||||||
|
{images.length ? (
|
||||||
|
<div className="image-gallery">
|
||||||
|
{images.map((image) => {
|
||||||
|
const { uuid } = image;
|
||||||
|
const isSelected = currentImageUuid === uuid;
|
||||||
|
return (
|
||||||
|
<HoverableImage
|
||||||
|
key={uuid}
|
||||||
|
image={image}
|
||||||
|
isSelected={isSelected}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="image-gallery-container-placeholder">
|
||||||
|
<MdPhotoLibrary />
|
||||||
|
<p>No Images In Gallery</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
onClick={handleClickLoadMore}
|
||||||
|
isDisabled={!areMoreImagesAvailable}
|
||||||
|
className="image-gallery-load-more-btn"
|
||||||
|
>
|
||||||
|
{areMoreImagesAvailable ? 'Load More' : 'All Images Loaded'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Resizable>
|
||||||
)}
|
)}
|
||||||
<Button
|
|
||||||
onClick={handleClickLoadMore}
|
|
||||||
isDisabled={!areMoreImagesAvailable}
|
|
||||||
className="image-gallery-load-more-btn"
|
|
||||||
>
|
|
||||||
{areMoreImagesAvailable ? 'Load More' : 'All Images Loaded'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ImageGallery;
|
|
||||||
|
129
frontend/src/features/gallery/ImageGalleryOld.tsx
Normal file
129
frontend/src/features/gallery/ImageGalleryOld.tsx
Normal file
@ -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 (
|
||||||
|
<div className="image-gallery-area">
|
||||||
|
<Button
|
||||||
|
colorScheme="teal"
|
||||||
|
onClick={onOpen}
|
||||||
|
className="image-gallery-popup-btn"
|
||||||
|
>
|
||||||
|
<MdPhotoLibrary />
|
||||||
|
</Button>
|
||||||
|
<Drawer
|
||||||
|
isOpen={isOpen}
|
||||||
|
placement="right"
|
||||||
|
onClose={onClose}
|
||||||
|
autoFocus={false}
|
||||||
|
trapFocus={false}
|
||||||
|
closeOnOverlayClick={false}
|
||||||
|
>
|
||||||
|
<DrawerContent className="image-gallery-popup">
|
||||||
|
<div className="image-gallery-header">
|
||||||
|
<DrawerHeader>Your Invocations</DrawerHeader>
|
||||||
|
<DrawerCloseButton />
|
||||||
|
</div>
|
||||||
|
<DrawerBody className="image-gallery-body">
|
||||||
|
<div className="image-gallery-container">
|
||||||
|
{images.length ? (
|
||||||
|
<div className="image-gallery">
|
||||||
|
{images.map((image) => {
|
||||||
|
const { uuid } = image;
|
||||||
|
const isSelected = currentImageUuid === uuid;
|
||||||
|
return (
|
||||||
|
<HoverableImage
|
||||||
|
key={uuid}
|
||||||
|
image={image}
|
||||||
|
isSelected={isSelected}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="image-gallery-container-placeholder">
|
||||||
|
<MdPhotoLibrary />
|
||||||
|
<p>No Images In Gallery</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
onClick={handleClickLoadMore}
|
||||||
|
isDisabled={!areMoreImagesAvailable}
|
||||||
|
className="image-gallery-load-more-btn"
|
||||||
|
>
|
||||||
|
{areMoreImagesAvailable ? 'Load More' : 'All Images Loaded'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DrawerBody>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImageGallery;
|
@ -6,8 +6,8 @@
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-color: var(--metadata-bg-color);
|
background-color: var(--metadata-bg-color);
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
max-height: calc($app-content-height - 4rem);
|
max-height: $app-metadata-height;
|
||||||
z-index: 1;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-json-viewer {
|
.image-json-viewer {
|
||||||
|
@ -11,12 +11,14 @@ export interface GalleryState {
|
|||||||
areMoreImagesAvailable: boolean;
|
areMoreImagesAvailable: boolean;
|
||||||
latest_mtime?: number;
|
latest_mtime?: number;
|
||||||
earliest_mtime?: number;
|
earliest_mtime?: number;
|
||||||
|
shouldShowGallery: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: GalleryState = {
|
const initialState: GalleryState = {
|
||||||
currentImageUuid: '',
|
currentImageUuid: '',
|
||||||
images: [],
|
images: [],
|
||||||
areMoreImagesAvailable: true,
|
areMoreImagesAvailable: true,
|
||||||
|
shouldShowGallery: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const gallerySlice = createSlice({
|
export const gallerySlice = createSlice({
|
||||||
@ -138,6 +140,9 @@ export const gallerySlice = createSlice({
|
|||||||
state.areMoreImagesAvailable = areMoreImagesAvailable;
|
state.areMoreImagesAvailable = areMoreImagesAvailable;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setShouldShowGallery: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.shouldShowGallery = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,6 +155,7 @@ export const {
|
|||||||
setIntermediateImage,
|
setIntermediateImage,
|
||||||
selectNextImage,
|
selectNextImage,
|
||||||
selectPrevImage,
|
selectPrevImage,
|
||||||
|
setShouldShowGallery,
|
||||||
} = gallerySlice.actions;
|
} = gallerySlice.actions;
|
||||||
|
|
||||||
export default gallerySlice.reducer;
|
export default gallerySlice.reducer;
|
||||||
|
@ -7,6 +7,7 @@ import { FaAngleDoubleDown, FaCode, FaMinus } from 'react-icons/fa';
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import { Resizable } from 're-resizable';
|
import { Resizable } from 're-resizable';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
|
||||||
const logSelector = createSelector(
|
const logSelector = createSelector(
|
||||||
(state: RootState) => state.system,
|
(state: RootState) => state.system,
|
||||||
@ -66,6 +67,14 @@ const Console = () => {
|
|||||||
dispatch(setShouldShowLogViewer(!shouldShowLogViewer));
|
dispatch(setShouldShowLogViewer(!shouldShowLogViewer));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
'`',
|
||||||
|
() => {
|
||||||
|
dispatch(setShouldShowLogViewer(!shouldShowLogViewer));
|
||||||
|
},
|
||||||
|
[shouldShowLogViewer]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{shouldShowLogViewer && (
|
{shouldShowLogViewer && (
|
||||||
|
@ -23,6 +23,11 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
|||||||
const hotkeys = [
|
const hotkeys = [
|
||||||
{ title: 'Invoke', desc: 'Generate an image', hotkey: 'Ctrl+Enter' },
|
{ title: 'Invoke', desc: 'Generate an image', hotkey: 'Ctrl+Enter' },
|
||||||
{ title: 'Cancel', desc: 'Cancel image generation', hotkey: 'Shift+X' },
|
{ title: 'Cancel', desc: 'Cancel image generation', hotkey: 'Shift+X' },
|
||||||
|
{
|
||||||
|
title: 'Toggle Gallery',
|
||||||
|
desc: 'Open and close the gallery drawer',
|
||||||
|
hotkey: 'G',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Set Seed',
|
title: 'Set Seed',
|
||||||
desc: 'Use the seed of the current image',
|
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',
|
desc: 'Switch between dark and light modes',
|
||||||
hotkey: 'Shift+D',
|
hotkey: 'Shift+D',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Console Toggle',
|
||||||
|
desc: 'Open and close console',
|
||||||
|
hotkey: '`',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const renderHotkeyModalItems = () => {
|
const renderHotkeyModalItems = () => {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.image-to-image-workarea {
|
.image-to-image-workarea {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: max-content auto max-content;
|
grid-template-columns: max-content auto;
|
||||||
column-gap: 1rem;
|
column-gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,6 +16,22 @@
|
|||||||
@include HideScrollbar;
|
@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 {
|
.image-to-image-strength-main-option {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: none !important;
|
grid-template-columns: none !important;
|
||||||
@ -52,7 +68,7 @@
|
|||||||
.image-to-image-dual-preview {
|
.image-to-image-dual-preview {
|
||||||
grid-area: img2img-preview;
|
grid-area: img2img-preview;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: max-content max-content;
|
||||||
column-gap: 0.5rem;
|
column-gap: 0.5rem;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
place-content: center;
|
place-content: center;
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ImageGallery from '../../gallery/ImageGallery';
|
|
||||||
import ImageToImageDisplay from './ImageToImageDisplay';
|
|
||||||
|
|
||||||
import ImageToImagePanel from './ImageToImagePanel';
|
import ImageToImagePanel from './ImageToImagePanel';
|
||||||
|
import ImageToImageDisplay from './ImageToImageDisplay';
|
||||||
|
import ImageGallery from '../../gallery/ImageGallery';
|
||||||
|
|
||||||
export default function ImageToImage() {
|
export default function ImageToImage() {
|
||||||
return (
|
return (
|
||||||
<div className="image-to-image-workarea">
|
<div className="image-to-image-workarea">
|
||||||
<ImageToImagePanel />
|
<ImageToImagePanel />
|
||||||
<ImageToImageDisplay />
|
<div className="image-to-image-display-area">
|
||||||
<ImageGallery />
|
<ImageToImageDisplay />
|
||||||
|
<ImageGallery />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.text-to-image-workarea {
|
.text-to-image-workarea {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: max-content auto max-content;
|
grid-template-columns: max-content auto;
|
||||||
column-gap: 1rem;
|
column-gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,3 +14,20 @@
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@include HideScrollbar;
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import TextToImagePanel from './TextToImagePanel';
|
||||||
import CurrentImageDisplay from '../../gallery/CurrentImageDisplay';
|
import CurrentImageDisplay from '../../gallery/CurrentImageDisplay';
|
||||||
import ImageGallery from '../../gallery/ImageGallery';
|
import ImageGallery from '../../gallery/ImageGallery';
|
||||||
import TextToImagePanel from './TextToImagePanel';
|
|
||||||
|
|
||||||
export default function TextToImage() {
|
export default function TextToImage() {
|
||||||
return (
|
return (
|
||||||
<div className="text-to-image-workarea">
|
<div className="text-to-image-workarea">
|
||||||
<TextToImagePanel />
|
<TextToImagePanel />
|
||||||
<CurrentImageDisplay />
|
<div className="text-to-image-display">
|
||||||
<ImageGallery />
|
<CurrentImageDisplay />
|
||||||
|
<ImageGallery />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ $app-width: calc(100vw - $app-cutoff);
|
|||||||
$app-height: calc(100vh - $app-cutoff);
|
$app-height: calc(100vh - $app-cutoff);
|
||||||
$app-content-height: calc(100vh - $app-content-height-cutoff);
|
$app-content-height: calc(100vh - $app-content-height-cutoff);
|
||||||
$app-gallery-height: calc(100vh - ($app-content-height-cutoff + 6rem));
|
$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));
|
$app-metadata-height: calc(100vh - ($app-content-height-cutoff + 4.4rem));
|
||||||
|
|
||||||
// option bar
|
// option bar
|
||||||
|
8
frontend/src/styles/_Animations.scss
Normal file
8
frontend/src/styles/_Animations.scss
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@keyframes slideOut {
|
||||||
|
from {
|
||||||
|
transform: translateX(10rem);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
@ -46,7 +46,7 @@
|
|||||||
--btn-red-hover: rgb(255, 75, 75);
|
--btn-red-hover: rgb(255, 75, 75);
|
||||||
|
|
||||||
--btn-load-more: rgb(30, 32, 42);
|
--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
|
||||||
--switch-bg-color: rgb(100, 102, 110);
|
--switch-bg-color: rgb(100, 102, 110);
|
||||||
@ -92,4 +92,7 @@
|
|||||||
|
|
||||||
// Img2Img
|
// Img2Img
|
||||||
--img2img-img-bg-color: rgb(30, 32, 42);
|
--img2img-img-bg-color: rgb(30, 32, 42);
|
||||||
|
|
||||||
|
// Gallery
|
||||||
|
--gallery-resizeable-color: rgb(36, 38, 48);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
--btn-red-hover: rgb(255, 55, 55);
|
--btn-red-hover: rgb(255, 55, 55);
|
||||||
|
|
||||||
--btn-load-more: rgb(202, 204, 206);
|
--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
|
||||||
--switch-bg-color: rgb(178, 180, 182);
|
--switch-bg-color: rgb(178, 180, 182);
|
||||||
@ -91,4 +91,7 @@
|
|||||||
|
|
||||||
// Img2Img
|
// Img2Img
|
||||||
--img2img-img-bg-color: rgb(180, 182, 184);
|
--img2img-img-bg-color: rgb(180, 182, 184);
|
||||||
|
|
||||||
|
// Gallery
|
||||||
|
--gallery-resizeable-color: rgb(192, 194, 196);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@use 'Colors_Dark';
|
@use 'Colors_Dark';
|
||||||
@use 'Colors_Light';
|
@use 'Colors_Light';
|
||||||
@use 'Fonts';
|
@use 'Fonts';
|
||||||
|
@use 'Animations';
|
||||||
|
|
||||||
// Component Styles
|
// Component Styles
|
||||||
//app
|
//app
|
||||||
|
Loading…
x
Reference in New Issue
Block a user