mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Reworks CurrentImageButtons.tsx
- Change all icons to FA iconset for consistency - Refactors IAIIconButton, IAIButton, IAIPopover to handle ref forwarding - Redesigns buttons into group
This commit is contained in:
parent
cfe567c62a
commit
620cf84d3d
1
frontend/dist/assets/index.28b80602.css
vendored
Normal file
1
frontend/dist/assets/index.28b80602.css
vendored
Normal file
File diff suppressed because one or more lines are too long
517
frontend/dist/assets/index.552c95d8.js
vendored
517
frontend/dist/assets/index.552c95d8.js
vendored
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.67342d6d.css
vendored
1
frontend/dist/assets/index.67342d6d.css
vendored
File diff suppressed because one or more lines are too long
517
frontend/dist/assets/index.adcf8963.js
vendored
Normal file
517
frontend/dist/assets/index.adcf8963.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
frontend/dist/index.html
vendored
4
frontend/dist/index.html
vendored
@ -6,8 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||||
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
||||||
<script type="module" crossorigin src="./assets/index.552c95d8.js"></script>
|
<script type="module" crossorigin src="./assets/index.adcf8963.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index.67342d6d.css">
|
<link rel="stylesheet" href="./assets/index.28b80602.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
3
frontend/src/common/components/IAIButton.scss
Normal file
3
frontend/src/common/components/IAIButton.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.invokeai__button {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
@ -1,23 +1,32 @@
|
|||||||
import { Button, ButtonProps, Tooltip } from '@chakra-ui/react';
|
import {
|
||||||
|
Button,
|
||||||
|
ButtonProps,
|
||||||
|
forwardRef,
|
||||||
|
Tooltip,
|
||||||
|
TooltipProps,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
export interface IAIButtonProps extends ButtonProps {
|
export interface IAIButtonProps extends ButtonProps {
|
||||||
label: string;
|
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
|
tooltipProps?: Omit<TooltipProps, 'children'>;
|
||||||
styleClass?: string;
|
styleClass?: string;
|
||||||
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const IAIButton = forwardRef((props: IAIButtonProps, forwardedRef) => {
|
||||||
* Reusable customized button component.
|
const { children, tooltip = '', tooltipProps, styleClass, ...rest } = props;
|
||||||
*/
|
|
||||||
const IAIButton = (props: IAIButtonProps) => {
|
|
||||||
const { label, tooltip = '', styleClass, ...rest } = props;
|
|
||||||
return (
|
return (
|
||||||
<Tooltip label={tooltip}>
|
<Tooltip label={tooltip} {...tooltipProps}>
|
||||||
<Button className={styleClass ? styleClass : ''} {...rest}>
|
<Button
|
||||||
{label}
|
ref={forwardedRef}
|
||||||
|
className={['invokeai__button', styleClass].join(' ')}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default IAIButton;
|
export default IAIButton;
|
||||||
|
@ -3,17 +3,18 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipProps,
|
TooltipProps,
|
||||||
|
forwardRef,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
interface Props extends IconButtonProps {
|
export type IAIIconButtonProps = IconButtonProps & {
|
||||||
styleClass?: string;
|
styleClass?: string;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
tooltipProps?: Omit<TooltipProps, 'children'>;
|
tooltipProps?: Omit<TooltipProps, 'children'>;
|
||||||
asCheckbox?: boolean;
|
asCheckbox?: boolean;
|
||||||
isChecked?: boolean;
|
isChecked?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
const IAIIconButton = (props: Props) => {
|
const IAIIconButton = forwardRef((props: IAIIconButtonProps, forwardedRef) => {
|
||||||
const {
|
const {
|
||||||
tooltip = '',
|
tooltip = '',
|
||||||
styleClass,
|
styleClass,
|
||||||
@ -26,6 +27,7 @@ const IAIIconButton = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Tooltip label={tooltip} hasArrow {...tooltipProps}>
|
<Tooltip label={tooltip} hasArrow {...tooltipProps}>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
ref={forwardedRef}
|
||||||
className={`invokeai__icon-button ${styleClass}`}
|
className={`invokeai__icon-button ${styleClass}`}
|
||||||
data-as-checkbox={asCheckbox}
|
data-as-checkbox={asCheckbox}
|
||||||
data-selected={isChecked !== undefined ? isChecked : undefined}
|
data-selected={isChecked !== undefined ? isChecked : undefined}
|
||||||
@ -34,6 +36,6 @@ const IAIIconButton = (props: Props) => {
|
|||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default IAIIconButton;
|
export default IAIIconButton;
|
||||||
|
@ -3,7 +3,6 @@ import {
|
|||||||
PopoverArrow,
|
PopoverArrow,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
Box,
|
|
||||||
BoxProps,
|
BoxProps,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { PopoverProps } from '@chakra-ui/react';
|
import { PopoverProps } from '@chakra-ui/react';
|
||||||
@ -20,7 +19,6 @@ type IAIPopoverProps = PopoverProps & {
|
|||||||
const IAIPopover = (props: IAIPopoverProps) => {
|
const IAIPopover = (props: IAIPopoverProps) => {
|
||||||
const {
|
const {
|
||||||
triggerComponent,
|
triggerComponent,
|
||||||
triggerContainerProps,
|
|
||||||
children,
|
children,
|
||||||
styleClass,
|
styleClass,
|
||||||
hasArrow = true,
|
hasArrow = true,
|
||||||
@ -29,9 +27,7 @@ const IAIPopover = (props: IAIPopoverProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover {...rest}>
|
<Popover {...rest}>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>{triggerComponent}</PopoverTrigger>
|
||||||
<Box {...triggerContainerProps}>{triggerComponent}</Box>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className={`invokeai__popover-content ${styleClass}`}>
|
<PopoverContent className={`invokeai__popover-content ${styleClass}`}>
|
||||||
{hasArrow && <PopoverArrow className={'invokeai__popover-arrow'} />}
|
{hasArrow && <PopoverArrow className={'invokeai__popover-arrow'} />}
|
||||||
{children}
|
{children}
|
||||||
|
19
frontend/src/features/gallery/CurrentImageButtons.scss
Normal file
19
frontend/src/features/gallery/CurrentImageButtons.scss
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
.current-image-options {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 0.5rem;
|
||||||
|
|
||||||
|
.current-image-send-to-popover,
|
||||||
|
.current-image-postprocessing-popover {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 0.5rem;
|
||||||
|
max-width: 25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chakra-popover__popper {
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import {
|
|||||||
setActiveTab,
|
setActiveTab,
|
||||||
setAllParameters,
|
setAllParameters,
|
||||||
setInitialImage,
|
setInitialImage,
|
||||||
|
setPrompt,
|
||||||
setSeed,
|
setSeed,
|
||||||
setShouldShowImageDetails,
|
setShouldShowImageDetails,
|
||||||
} from '../options/optionsSlice';
|
} from '../options/optionsSlice';
|
||||||
@ -18,27 +19,27 @@ import { SystemState } from '../system/systemSlice';
|
|||||||
import IAIButton from '../../common/components/IAIButton';
|
import IAIButton from '../../common/components/IAIButton';
|
||||||
import { runESRGAN, runFacetool } from '../../app/socketio/actions';
|
import { runESRGAN, runFacetool } from '../../app/socketio/actions';
|
||||||
import IAIIconButton from '../../common/components/IAIIconButton';
|
import IAIIconButton from '../../common/components/IAIIconButton';
|
||||||
import { MdDelete, MdFace, MdHd, MdImage, MdInfo } from 'react-icons/md';
|
|
||||||
import InvokePopover from './InvokePopover';
|
|
||||||
import UpscaleOptions from '../options/AdvancedOptions/Upscale/UpscaleOptions';
|
import UpscaleOptions from '../options/AdvancedOptions/Upscale/UpscaleOptions';
|
||||||
import FaceRestoreOptions from '../options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
|
import FaceRestoreOptions from '../options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useToast } from '@chakra-ui/react';
|
import { ButtonGroup, Link, useClipboard, useToast } from '@chakra-ui/react';
|
||||||
import { FaCopy, FaPaintBrush, FaSeedling } from 'react-icons/fa';
|
import {
|
||||||
|
FaAsterisk,
|
||||||
|
FaCode,
|
||||||
|
FaCopy,
|
||||||
|
FaDownload,
|
||||||
|
FaExpandArrowsAlt,
|
||||||
|
FaGrinStars,
|
||||||
|
FaQuoteRight,
|
||||||
|
FaSeedling,
|
||||||
|
FaShare,
|
||||||
|
FaShareAlt,
|
||||||
|
FaTrash,
|
||||||
|
} from 'react-icons/fa';
|
||||||
import { setImageToInpaint } from '../tabs/Inpainting/inpaintingSlice';
|
import { setImageToInpaint } from '../tabs/Inpainting/inpaintingSlice';
|
||||||
import { GalleryState } from './gallerySlice';
|
import { GalleryState } from './gallerySlice';
|
||||||
import { activeTabNameSelector } from '../options/optionsSelectors';
|
import { activeTabNameSelector } from '../options/optionsSelectors';
|
||||||
|
import IAIPopover from '../../common/components/IAIPopover';
|
||||||
const intermediateImageSelector = createSelector(
|
|
||||||
(state: RootState) => state.gallery,
|
|
||||||
(gallery: GalleryState) => gallery.intermediateImage,
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: (a, b) =>
|
|
||||||
(a === undefined && b === undefined) || a.uuid === b.uuid,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const systemSelector = createSelector(
|
const systemSelector = createSelector(
|
||||||
[
|
[
|
||||||
@ -102,6 +103,8 @@ const CurrentImageButtons = ({ image }: CurrentImageButtonsProps) => {
|
|||||||
activeTabName,
|
activeTabName,
|
||||||
} = useAppSelector(systemSelector);
|
} = useAppSelector(systemSelector);
|
||||||
|
|
||||||
|
const { onCopy } = useClipboard(window.location.toString() + image.url);
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const handleClickUseAsInitialImage = () => {
|
const handleClickUseAsInitialImage = () => {
|
||||||
@ -109,6 +112,16 @@ const CurrentImageButtons = ({ image }: CurrentImageButtonsProps) => {
|
|||||||
dispatch(setActiveTab(1));
|
dispatch(setActiveTab(1));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCopyImageLink = () => {
|
||||||
|
onCopy();
|
||||||
|
toast({
|
||||||
|
title: 'Image Link Copied',
|
||||||
|
status: 'success',
|
||||||
|
duration: 2500,
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
'shift+i',
|
'shift+i',
|
||||||
() => {
|
() => {
|
||||||
@ -186,6 +199,34 @@ const CurrentImageButtons = ({ image }: CurrentImageButtonsProps) => {
|
|||||||
[image]
|
[image]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleClickUsePrompt = () =>
|
||||||
|
image?.metadata?.image?.prompt &&
|
||||||
|
dispatch(setPrompt(image.metadata.image.prompt));
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
'p',
|
||||||
|
() => {
|
||||||
|
if (image?.metadata?.image?.prompt) {
|
||||||
|
handleClickUsePrompt();
|
||||||
|
toast({
|
||||||
|
title: 'Prompt Set',
|
||||||
|
status: 'success',
|
||||||
|
duration: 2500,
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: 'Prompt Not Set',
|
||||||
|
description: 'Could not find prompt for this image.',
|
||||||
|
status: 'error',
|
||||||
|
duration: 2500,
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[image]
|
||||||
|
);
|
||||||
|
|
||||||
const handleClickUpscale = () => dispatch(runESRGAN(image));
|
const handleClickUpscale = () => dispatch(runESRGAN(image));
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
'u',
|
'u',
|
||||||
@ -284,108 +325,133 @@ const CurrentImageButtons = ({ image }: CurrentImageButtonsProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="current-image-options">
|
<div className="current-image-options">
|
||||||
<IAIIconButton
|
<ButtonGroup isAttached={true}>
|
||||||
icon={<MdImage />}
|
<IAIPopover
|
||||||
tooltip="Send To Image To Image"
|
trigger="hover"
|
||||||
aria-label="Send To Image To Image"
|
triggerComponent={
|
||||||
onClick={handleClickUseAsInitialImage}
|
<IAIIconButton aria-label="Send to..." icon={<FaShareAlt />} />
|
||||||
/>
|
|
||||||
|
|
||||||
<IAIIconButton
|
|
||||||
icon={<FaPaintBrush />}
|
|
||||||
tooltip="Send To Inpainting"
|
|
||||||
aria-label="Send To Inpainting"
|
|
||||||
onClick={handleSendToInpainting}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IAIIconButton
|
|
||||||
icon={<FaCopy />}
|
|
||||||
tooltip="Use All"
|
|
||||||
aria-label="Use All"
|
|
||||||
isDisabled={
|
|
||||||
!['txt2img', 'img2img'].includes(image?.metadata?.image?.type)
|
|
||||||
}
|
|
||||||
onClick={handleClickUseAllParameters}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IAIIconButton
|
|
||||||
icon={<FaSeedling />}
|
|
||||||
tooltip="Use Seed"
|
|
||||||
aria-label="Use Seed"
|
|
||||||
isDisabled={!image?.metadata?.image?.seed}
|
|
||||||
onClick={handleClickUseSeed}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* <IAIButton
|
|
||||||
label="Use All"
|
|
||||||
isDisabled={
|
|
||||||
!['txt2img', 'img2img'].includes(image?.metadata?.image?.type)
|
|
||||||
}
|
|
||||||
onClick={handleClickUseAllParameters}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IAIButton
|
|
||||||
label="Use Seed"
|
|
||||||
isDisabled={!image?.metadata?.image?.seed}
|
|
||||||
onClick={handleClickUseSeed}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
<InvokePopover
|
|
||||||
title="Restore Faces"
|
|
||||||
popoverOptions={<FaceRestoreOptions />}
|
|
||||||
actionButton={
|
|
||||||
<IAIButton
|
|
||||||
label={'Restore Faces'}
|
|
||||||
isDisabled={
|
|
||||||
!isGFPGANAvailable ||
|
|
||||||
Boolean(intermediateImage) ||
|
|
||||||
!(isConnected && !isProcessing) ||
|
|
||||||
!facetoolStrength
|
|
||||||
}
|
|
||||||
onClick={handleClickFixFaces}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<IAIIconButton icon={<MdFace />} aria-label="Restore Faces" />
|
|
||||||
</InvokePopover>
|
|
||||||
|
|
||||||
<InvokePopover
|
|
||||||
title="Upscale"
|
|
||||||
styleClass="upscale-popover"
|
|
||||||
popoverOptions={<UpscaleOptions />}
|
|
||||||
actionButton={
|
|
||||||
<IAIButton
|
|
||||||
label={'Upscale Image'}
|
|
||||||
isDisabled={
|
|
||||||
!isESRGANAvailable ||
|
|
||||||
Boolean(intermediateImage) ||
|
|
||||||
!(isConnected && !isProcessing) ||
|
|
||||||
!upscalingLevel
|
|
||||||
}
|
|
||||||
onClick={handleClickUpscale}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<IAIIconButton icon={<MdHd />} aria-label="Upscale" />
|
|
||||||
</InvokePopover>
|
|
||||||
|
|
||||||
<IAIIconButton
|
|
||||||
icon={<MdInfo />}
|
|
||||||
tooltip="Details"
|
|
||||||
aria-label="Details"
|
|
||||||
onClick={handleClickShowImageDetails}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DeleteImageModal image={image}>
|
|
||||||
<IAIIconButton
|
|
||||||
icon={<MdDelete />}
|
|
||||||
tooltip="Delete Image"
|
|
||||||
aria-label="Delete Image"
|
|
||||||
isDisabled={
|
|
||||||
Boolean(intermediateImage) || !isConnected || isProcessing
|
|
||||||
}
|
}
|
||||||
|
>
|
||||||
|
<div className="current-image-send-to-popover">
|
||||||
|
<IAIButton
|
||||||
|
size={'sm'}
|
||||||
|
onClick={handleClickUseAsInitialImage}
|
||||||
|
leftIcon={<FaShare />}
|
||||||
|
>
|
||||||
|
Send to Image to Image
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
size={'sm'}
|
||||||
|
onClick={handleSendToInpainting}
|
||||||
|
leftIcon={<FaShare />}
|
||||||
|
>
|
||||||
|
Send to Inpainting
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
size={'sm'}
|
||||||
|
onClick={handleCopyImageLink}
|
||||||
|
leftIcon={<FaCopy />}
|
||||||
|
>
|
||||||
|
Copy Link to Image
|
||||||
|
</IAIButton>
|
||||||
|
|
||||||
|
<IAIButton leftIcon={<FaDownload />} size={'sm'}>
|
||||||
|
<Link download={true} href={image.url}>
|
||||||
|
Download Image
|
||||||
|
</Link>
|
||||||
|
</IAIButton>
|
||||||
|
</div>
|
||||||
|
</IAIPopover>
|
||||||
|
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaQuoteRight />}
|
||||||
|
tooltip="Use Prompt"
|
||||||
|
aria-label="Use Prompt"
|
||||||
|
isDisabled={!image?.metadata?.image?.prompt}
|
||||||
|
onClick={handleClickUsePrompt}
|
||||||
/>
|
/>
|
||||||
</DeleteImageModal>
|
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaSeedling />}
|
||||||
|
tooltip="Use Seed"
|
||||||
|
aria-label="Use Seed"
|
||||||
|
isDisabled={!image?.metadata?.image?.seed}
|
||||||
|
onClick={handleClickUseSeed}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaAsterisk />}
|
||||||
|
tooltip="Use All"
|
||||||
|
aria-label="Use All"
|
||||||
|
isDisabled={
|
||||||
|
!['txt2img', 'img2img'].includes(image?.metadata?.image?.type)
|
||||||
|
}
|
||||||
|
onClick={handleClickUseAllParameters}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IAIPopover
|
||||||
|
trigger="hover"
|
||||||
|
triggerComponent={
|
||||||
|
<IAIIconButton icon={<FaGrinStars />} aria-label="Restore Faces" />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="current-image-postprocessing-popover">
|
||||||
|
<FaceRestoreOptions />
|
||||||
|
<IAIButton
|
||||||
|
isDisabled={
|
||||||
|
!isGFPGANAvailable ||
|
||||||
|
Boolean(intermediateImage) ||
|
||||||
|
!(isConnected && !isProcessing) ||
|
||||||
|
!facetoolStrength
|
||||||
|
}
|
||||||
|
onClick={handleClickFixFaces}
|
||||||
|
>
|
||||||
|
Restore Faces
|
||||||
|
</IAIButton>
|
||||||
|
</div>
|
||||||
|
</IAIPopover>
|
||||||
|
|
||||||
|
<IAIPopover
|
||||||
|
trigger="hover"
|
||||||
|
triggerComponent={
|
||||||
|
<IAIIconButton icon={<FaExpandArrowsAlt />} aria-label="Upscale" />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="current-image-postprocessing-popover">
|
||||||
|
<UpscaleOptions />
|
||||||
|
<IAIButton
|
||||||
|
isDisabled={
|
||||||
|
!isESRGANAvailable ||
|
||||||
|
Boolean(intermediateImage) ||
|
||||||
|
!(isConnected && !isProcessing) ||
|
||||||
|
!upscalingLevel
|
||||||
|
}
|
||||||
|
onClick={handleClickUpscale}
|
||||||
|
>
|
||||||
|
Upscale Image
|
||||||
|
</IAIButton>
|
||||||
|
</div>
|
||||||
|
</IAIPopover>
|
||||||
|
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaCode />}
|
||||||
|
tooltip="Details"
|
||||||
|
aria-label="Details"
|
||||||
|
data-selected={shouldShowImageDetails}
|
||||||
|
onClick={handleClickShowImageDetails}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DeleteImageModal image={image}>
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaTrash />}
|
||||||
|
tooltip="Delete Image"
|
||||||
|
aria-label="Delete Image"
|
||||||
|
isDisabled={
|
||||||
|
Boolean(intermediateImage) || !isConnected || isProcessing
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</DeleteImageModal>
|
||||||
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -9,18 +9,6 @@
|
|||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-image-options {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
column-gap: 0.5rem;
|
|
||||||
|
|
||||||
.chakra-popover__popper {
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-image-preview {
|
.current-image-preview {
|
||||||
position: relative;
|
position: relative;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
.popover-content {
|
|
||||||
background-color: var(--background-color-secondary) !important;
|
|
||||||
border: none !important;
|
|
||||||
border-top: 0px;
|
|
||||||
background-color: var(--tab-hover-color);
|
|
||||||
border-radius: 0 0 0.4rem 0.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-arrow {
|
|
||||||
background: var(--tab-hover-color) !important;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-options {
|
|
||||||
background: var(--tab-panel-bg);
|
|
||||||
border-radius: 0 0 0.4rem 0.4rem;
|
|
||||||
border: 2px solid var(--tab-hover-color);
|
|
||||||
padding: 0.75rem 1rem 0.75rem 1rem;
|
|
||||||
display: grid;
|
|
||||||
grid-auto-rows: max-content;
|
|
||||||
grid-row-gap: 0.5rem;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-header {
|
|
||||||
background: var(--tab-hover-color);
|
|
||||||
border-radius: 0.4rem 0.4rem 0 0;
|
|
||||||
font-weight: bold;
|
|
||||||
border: none;
|
|
||||||
padding-left: 1rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upscale-popover {
|
|
||||||
width: 23rem !important;
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
Popover,
|
|
||||||
PopoverArrow,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverHeader,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import React, { ReactNode } from 'react';
|
|
||||||
|
|
||||||
type PopoverProps = {
|
|
||||||
title?: string;
|
|
||||||
delay?: number;
|
|
||||||
styleClass?: string;
|
|
||||||
popoverOptions?: ReactNode;
|
|
||||||
actionButton?: ReactNode;
|
|
||||||
children: ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
const InvokePopover = ({
|
|
||||||
title = 'Popup',
|
|
||||||
styleClass,
|
|
||||||
delay = 50,
|
|
||||||
popoverOptions,
|
|
||||||
actionButton,
|
|
||||||
children,
|
|
||||||
}: PopoverProps) => {
|
|
||||||
return (
|
|
||||||
<Popover trigger={'hover'} closeDelay={delay}>
|
|
||||||
<PopoverTrigger>
|
|
||||||
<Box>{children}</Box>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className={`popover-content ${styleClass}`}>
|
|
||||||
<PopoverArrow className="popover-arrow" />
|
|
||||||
<PopoverHeader className="popover-header">{title}</PopoverHeader>
|
|
||||||
<div className="popover-options">
|
|
||||||
{popoverOptions ? popoverOptions : null}
|
|
||||||
{actionButton}
|
|
||||||
</div>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default InvokePopover;
|
|
@ -17,7 +17,8 @@ const clearBrushHistorySelector = createSelector(
|
|||||||
(inpainting: InpaintingState) => {
|
(inpainting: InpaintingState) => {
|
||||||
const { pastLines, futureLines } = inpainting;
|
const { pastLines, futureLines } = inpainting;
|
||||||
return {
|
return {
|
||||||
mayClearBrushHistory: futureLines.length > 0 || pastLines.length > 0 ? false : true
|
mayClearBrushHistory:
|
||||||
|
futureLines.length > 0 || pastLines.length > 0 ? false : true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -44,11 +45,12 @@ export default function ClearBrushHistory() {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<IAIButton
|
<IAIButton
|
||||||
label="Clear Brush History"
|
|
||||||
onClick={handleClearBrushHistory}
|
onClick={handleClearBrushHistory}
|
||||||
tooltip="Clears brush stroke history"
|
tooltip="Clears brush stroke history"
|
||||||
disabled={mayClearBrushHistory}
|
disabled={mayClearBrushHistory}
|
||||||
styleClass="inpainting-options-btn"
|
styleClass="inpainting-options-btn"
|
||||||
/>
|
>
|
||||||
|
Clear Brush History
|
||||||
|
</IAIButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { MdCancel } from 'react-icons/md';
|
import { MdCancel } from 'react-icons/md';
|
||||||
import { cancelProcessing } from '../../../app/socketio/actions';
|
import { cancelProcessing } from '../../../app/socketio/actions';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from '../../../app/store';
|
import { RootState, useAppDispatch, useAppSelector } from '../../../app/store';
|
||||||
import IAIIconButton from '../../../common/components/IAIIconButton';
|
import IAIIconButton, {
|
||||||
|
IAIIconButtonProps,
|
||||||
|
} from '../../../common/components/IAIIconButton';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { SystemState } from '../../system/systemSlice';
|
import { SystemState } from '../../system/systemSlice';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { IAIButtonProps } from '../../../common/components/IAIButton';
|
|
||||||
|
|
||||||
const cancelButtonSelector = createSelector(
|
const cancelButtonSelector = createSelector(
|
||||||
(state: RootState) => state.system,
|
(state: RootState) => state.system,
|
||||||
@ -24,7 +25,9 @@ const cancelButtonSelector = createSelector(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function CancelButton(props: Omit<IAIButtonProps, 'label'>) {
|
export default function CancelButton(
|
||||||
|
props: Omit<IAIIconButtonProps, 'aria-label'>
|
||||||
|
) {
|
||||||
const { ...rest } = props;
|
const { ...rest } = props;
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { isProcessing, isConnected, isCancelable } =
|
const { isProcessing, isConnected, isCancelable } =
|
||||||
|
@ -7,11 +7,14 @@ import { useAppDispatch, useAppSelector } from '../../../app/store';
|
|||||||
import IAIButton, {
|
import IAIButton, {
|
||||||
IAIButtonProps,
|
IAIButtonProps,
|
||||||
} from '../../../common/components/IAIButton';
|
} from '../../../common/components/IAIButton';
|
||||||
import IAIIconButton from '../../../common/components/IAIIconButton';
|
import IAIIconButton, {
|
||||||
|
IAIIconButtonProps,
|
||||||
|
} from '../../../common/components/IAIIconButton';
|
||||||
import IAIPopover from '../../../common/components/IAIPopover';
|
import IAIPopover from '../../../common/components/IAIPopover';
|
||||||
import { activeTabNameSelector } from '../optionsSelectors';
|
import { activeTabNameSelector } from '../optionsSelectors';
|
||||||
|
|
||||||
interface InvokeButton extends Omit<IAIButtonProps, 'label'> {
|
interface InvokeButton
|
||||||
|
extends Omit<IAIButtonProps | IAIIconButtonProps, 'aria-label'> {
|
||||||
iconButton?: boolean;
|
iconButton?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,38 +38,39 @@ export default function InvokeButton(props: InvokeButton) {
|
|||||||
[isReady, activeTabName]
|
[isReady, activeTabName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const buttonComponent = iconButton ? (
|
const buttonComponent = (
|
||||||
<IAIIconButton
|
<div style={{ flexGrow: 4 }}>
|
||||||
aria-label="Invoke"
|
{iconButton ? (
|
||||||
type="submit"
|
<IAIIconButton
|
||||||
icon={<FaPlay />}
|
aria-label="Invoke"
|
||||||
isDisabled={!isReady}
|
type="submit"
|
||||||
onClick={handleClickGenerate}
|
icon={<FaPlay />}
|
||||||
className="invoke-btn invoke"
|
isDisabled={!isReady}
|
||||||
tooltip="Invoke"
|
onClick={handleClickGenerate}
|
||||||
tooltipProps={{ placement: 'bottom' }}
|
className="invoke-btn invoke"
|
||||||
{...rest}
|
tooltip="Invoke"
|
||||||
/>
|
tooltipProps={{ placement: 'bottom' }}
|
||||||
) : (
|
{...rest}
|
||||||
<IAIButton
|
/>
|
||||||
label="Invoke"
|
) : (
|
||||||
aria-label="Invoke"
|
<IAIButton
|
||||||
type="submit"
|
aria-label="Invoke"
|
||||||
isDisabled={!isReady}
|
type="submit"
|
||||||
onClick={handleClickGenerate}
|
isDisabled={!isReady}
|
||||||
className="invoke-btn"
|
onClick={handleClickGenerate}
|
||||||
{...rest}
|
className="invoke-btn"
|
||||||
/>
|
{...rest}
|
||||||
|
>
|
||||||
|
Invoke
|
||||||
|
</IAIButton>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return isReady ? (
|
return isReady ? (
|
||||||
buttonComponent
|
buttonComponent
|
||||||
) : (
|
) : (
|
||||||
<IAIPopover
|
<IAIPopover trigger="hover" triggerComponent={buttonComponent}>
|
||||||
trigger="hover"
|
|
||||||
triggerContainerProps={{ style: { flexGrow: 4 } }}
|
|
||||||
triggerComponent={buttonComponent}
|
|
||||||
>
|
|
||||||
{reasonsWhyNotReady && (
|
{reasonsWhyNotReady && (
|
||||||
<UnorderedList>
|
<UnorderedList>
|
||||||
{reasonsWhyNotReady.map((reason, i) => (
|
{reasonsWhyNotReady.map((reason, i) => (
|
||||||
@ -76,4 +80,20 @@ export default function InvokeButton(props: InvokeButton) {
|
|||||||
)}
|
)}
|
||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// return isReady ? (
|
||||||
|
// buttonComponent
|
||||||
|
// ) : (
|
||||||
|
// <IAIPopover trigger="hover" triggerComponent={buttonComponent}>
|
||||||
|
// {reasonsWhyNotReady ? (
|
||||||
|
// <UnorderedList>
|
||||||
|
// {reasonsWhyNotReady.map((reason, i) => (
|
||||||
|
// <ListItem key={i}>{reason}</ListItem>
|
||||||
|
// ))}
|
||||||
|
// </UnorderedList>
|
||||||
|
// ) : (
|
||||||
|
// 'test'
|
||||||
|
// )}
|
||||||
|
// </IAIPopover>
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
@ -73,15 +73,20 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
|||||||
|
|
||||||
const generalHotkeys = [
|
const generalHotkeys = [
|
||||||
{
|
{
|
||||||
title: 'Set Parameters',
|
title: 'Set Prompt',
|
||||||
desc: 'Use all parameters of the current image',
|
desc: 'Use the prompt of the current image',
|
||||||
hotkey: 'A',
|
hotkey: 'P',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Set Seed',
|
title: 'Set Seed',
|
||||||
desc: 'Use the seed of the current image',
|
desc: 'Use the seed of the current image',
|
||||||
hotkey: 'S',
|
hotkey: 'S',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Set Parameters',
|
||||||
|
desc: 'Use all parameters of the current image',
|
||||||
|
hotkey: 'A',
|
||||||
|
},
|
||||||
{ title: 'Restore Faces', desc: 'Restore the current image', hotkey: 'R' },
|
{ title: 'Restore Faces', desc: 'Restore the current image', hotkey: 'R' },
|
||||||
{ title: 'Upscale', desc: 'Upscale the current image', hotkey: 'U' },
|
{ title: 'Upscale', desc: 'Upscale the current image', hotkey: 'U' },
|
||||||
{
|
{
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
// gallery
|
// gallery
|
||||||
@use '../features/gallery/CurrentImageDisplay.scss';
|
@use '../features/gallery/CurrentImageDisplay.scss';
|
||||||
|
@use '../features/gallery/CurrentImageButtons.scss';
|
||||||
@use '../features/gallery/ImageGallery.scss';
|
@use '../features/gallery/ImageGallery.scss';
|
||||||
@use '../features/gallery/HoverableImage.scss';
|
@use '../features/gallery/HoverableImage.scss';
|
||||||
@use '../features/gallery/InvokePopover.scss';
|
|
||||||
@use '../features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss';
|
@use '../features/gallery/ImageMetaDataViewer/ImageMetadataViewer.scss';
|
||||||
|
|
||||||
// Tabs
|
// Tabs
|
||||||
@ -47,6 +47,7 @@
|
|||||||
@use '../common/components/IAINumberInput.scss';
|
@use '../common/components/IAINumberInput.scss';
|
||||||
@use '../common/components/IAIInput.scss';
|
@use '../common/components/IAIInput.scss';
|
||||||
@use '../common/components/IAIIconButton.scss';
|
@use '../common/components/IAIIconButton.scss';
|
||||||
|
@use '../common/components/IAIButton.scss';
|
||||||
@use '../common/components/IAISwitch.scss';
|
@use '../common/components/IAISwitch.scss';
|
||||||
@use '../common/components/IAISelect.scss';
|
@use '../common/components/IAISelect.scss';
|
||||||
@use '../common/components/IAISlider.scss';
|
@use '../common/components/IAISlider.scss';
|
||||||
|
Loading…
Reference in New Issue
Block a user