mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Styling changes and settings modal minor refactor
This commit is contained in:
parent
1e51c39928
commit
cefe12f1df
1
frontend/dist/assets/index.14c578ee.css
vendored
1
frontend/dist/assets/index.14c578ee.css
vendored
File diff suppressed because one or more lines are too long
517
frontend/dist/assets/index.552c95d8.js
vendored
Normal file
517
frontend/dist/assets/index.552c95d8.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.67342d6d.css
vendored
Normal file
1
frontend/dist/assets/index.67342d6d.css
vendored
Normal file
File diff suppressed because one or more lines are too long
501
frontend/dist/assets/index.ae6d2a5e.js
vendored
501
frontend/dist/assets/index.ae6d2a5e.js
vendored
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" />
|
||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
||||
<script type="module" crossorigin src="./assets/index.ae6d2a5e.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.14c578ee.css">
|
||||
<script type="module" crossorigin src="./assets/index.552c95d8.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.67342d6d.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -3,11 +3,7 @@ import {
|
||||
IconButton,
|
||||
Tooltip,
|
||||
TooltipProps,
|
||||
ResponsiveValue,
|
||||
ThemingProps,
|
||||
isChakraTheme,
|
||||
} from '@chakra-ui/react';
|
||||
import { Variant } from 'framer-motion';
|
||||
|
||||
interface Props extends IconButtonProps {
|
||||
styleClass?: string;
|
||||
|
@ -1,8 +1,7 @@
|
||||
@use '../../styles/Mixins/' as *;
|
||||
|
||||
.invokeai__select {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, max-content);
|
||||
display: flex;
|
||||
column-gap: 1rem;
|
||||
align-items: center;
|
||||
width: max-content;
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { FormControl, FormLabel, Select, SelectProps } from '@chakra-ui/react';
|
||||
import { MouseEvent } from 'react';
|
||||
|
||||
interface Props extends SelectProps {
|
||||
type IAISelectProps = SelectProps & {
|
||||
label: string;
|
||||
styleClass?: string;
|
||||
validValues:
|
||||
| Array<number | string>
|
||||
| Array<{ key: string; value: string | number }>;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Customized Chakra FormControl + Select multi-part component.
|
||||
*/
|
||||
const IAISelect = (props: Props) => {
|
||||
const IAISelect = (props: IAISelectProps) => {
|
||||
const {
|
||||
label,
|
||||
isDisabled,
|
||||
@ -33,19 +33,19 @@ const IAISelect = (props: Props) => {
|
||||
}}
|
||||
>
|
||||
<FormLabel
|
||||
className="invokeai__select-label"
|
||||
fontSize={fontSize}
|
||||
marginBottom={1}
|
||||
flexGrow={2}
|
||||
whiteSpace="nowrap"
|
||||
className="invokeai__select-label"
|
||||
>
|
||||
{label}
|
||||
</FormLabel>
|
||||
<Select
|
||||
className="invokeai__select-picker"
|
||||
fontSize={fontSize}
|
||||
size={size}
|
||||
{...rest}
|
||||
className="invokeai__select-picker"
|
||||
>
|
||||
{validValues.map((opt) => {
|
||||
return typeof opt === 'string' || typeof opt === 'number' ? (
|
||||
@ -53,7 +53,11 @@ const IAISelect = (props: Props) => {
|
||||
{opt}
|
||||
</option>
|
||||
) : (
|
||||
<option key={opt.value} value={opt.value}>
|
||||
<option
|
||||
key={opt.value}
|
||||
value={opt.value}
|
||||
className="invokeai__select-option"
|
||||
>
|
||||
{opt.key}
|
||||
</option>
|
||||
);
|
||||
|
@ -22,8 +22,6 @@ const IAISwitch = (props: Props) => {
|
||||
const {
|
||||
label,
|
||||
isDisabled = false,
|
||||
// fontSize = 'md',
|
||||
// size = 'md',
|
||||
width = 'auto',
|
||||
formControlProps,
|
||||
formLabelProps,
|
||||
@ -39,17 +37,11 @@ const IAISwitch = (props: Props) => {
|
||||
>
|
||||
<FormLabel
|
||||
className="invokeai__switch-form-label"
|
||||
// fontSize={fontSize}
|
||||
whiteSpace="nowrap"
|
||||
{...formLabelProps}
|
||||
>
|
||||
{label}
|
||||
<Switch
|
||||
className="invokeai__switch-root"
|
||||
// size={size}
|
||||
// className="switch-button"
|
||||
{...rest}
|
||||
/>
|
||||
<Switch className="invokeai__switch-root" {...rest} />
|
||||
</FormLabel>
|
||||
</FormControl>
|
||||
);
|
||||
|
@ -16,6 +16,7 @@
|
||||
row-gap: 1rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--background-color);
|
||||
|
||||
&.is-drag-accept {
|
||||
box-shadow: inset 0 0 20rem 1rem var(--accent-color);
|
||||
|
@ -6,6 +6,7 @@ import { uploadImage } from '../../app/socketio/actions';
|
||||
import { ImageUploadDestination, UploadImagePayload } from '../../app/invokeai';
|
||||
import { ImageUploaderTriggerContext } from '../../app/contexts/ImageUploaderTriggerContext';
|
||||
import { activeTabNameSelector } from '../../features/options/optionsSelectors';
|
||||
import { tabDict } from '../../features/tabs/InvokeTabs';
|
||||
|
||||
type ImageUploaderProps = {
|
||||
children: ReactNode;
|
||||
@ -128,6 +129,12 @@ const ImageUploader = (props: ImageUploaderProps) => {
|
||||
};
|
||||
}, [dispatch, toast, activeTabName]);
|
||||
|
||||
const overlaySecondaryText = ['img2img', 'inpainting'].includes(
|
||||
activeTabName
|
||||
)
|
||||
? ` to ${tabDict[activeTabName as keyof typeof tabDict].tooltip}`
|
||||
: ``;
|
||||
|
||||
return (
|
||||
<ImageUploaderTriggerContext.Provider value={open}>
|
||||
<div {...getRootProps({ style: {} })}>
|
||||
@ -137,7 +144,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
|
||||
<div className="dropzone-container">
|
||||
{isDragAccept && (
|
||||
<div className="dropzone-overlay is-drag-accept">
|
||||
<Heading size={'lg'}>Drop Images</Heading>
|
||||
<Heading size={'lg'}>Upload Image{overlaySecondaryText}</Heading>
|
||||
</div>
|
||||
)}
|
||||
{isDragReject && (
|
||||
|
@ -26,6 +26,9 @@ export const imagesSelector = createSelector(
|
||||
isOnLastImage:
|
||||
!isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1,
|
||||
shouldShowImageDetails,
|
||||
shouldShowPrevImageButton: currentImageIndex === 0,
|
||||
shouldShowNextImageButton:
|
||||
!isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
@ -19,8 +19,6 @@
|
||||
}
|
||||
|
||||
.image-gallery-wrapper {
|
||||
z-index: 100;
|
||||
|
||||
&[data-pinned='false'] {
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
|
@ -261,6 +261,7 @@ export default function ImageGallery() {
|
||||
>
|
||||
<div
|
||||
className="image-gallery-wrapper"
|
||||
style={{ zIndex: shouldPinGallery ? 1 : 100 }}
|
||||
data-pinned={shouldPinGallery}
|
||||
ref={galleryRef}
|
||||
onMouseLeave={!shouldPinGallery ? setCloseGalleryTimer : undefined}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
.main-option-block {
|
||||
border-radius: 0.5rem;
|
||||
display: grid !important;
|
||||
grid-template-columns: auto !important;
|
||||
row-gap: 0.4rem;
|
||||
|
||||
|
@ -1,24 +1,37 @@
|
||||
.model-list {
|
||||
.chakra-accordion {
|
||||
display: grid;
|
||||
row-gap: 0.5rem;
|
||||
}
|
||||
// .chakra-accordion {
|
||||
// display: grid;
|
||||
// row-gap: 0.5rem;
|
||||
// }
|
||||
|
||||
.chakra-accordion__item {
|
||||
border: none;
|
||||
border-radius: 0.3rem;
|
||||
background-color: var(--tab-hover-color);
|
||||
}
|
||||
// .chakra-accordion__item {
|
||||
// border: none;
|
||||
// }
|
||||
|
||||
// button {
|
||||
// border-radius: 0.3rem !important;
|
||||
|
||||
// &[aria-expanded='true'] {
|
||||
// // background-color: var(--tab-hover-color);
|
||||
// border-radius: 0.3rem;
|
||||
// }
|
||||
// }
|
||||
|
||||
.model-list-accordion {
|
||||
outline: none;
|
||||
padding: 0.25rem;
|
||||
|
||||
button {
|
||||
border-radius: 0.3rem !important;
|
||||
|
||||
&[aria-expanded='true'] {
|
||||
background-color: var(--tab-hover-color);
|
||||
border-radius: 0.3rem;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
&:hover {
|
||||
background-color: unset;
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.model-list-button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -64,6 +77,9 @@
|
||||
}
|
||||
}
|
||||
.model-list-item-load-btn {
|
||||
button {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,31 +73,33 @@ const ModelList = () => {
|
||||
const { models } = useAppSelector(modelListSelector);
|
||||
|
||||
return (
|
||||
<div className="model-list">
|
||||
<Accordion allowToggle>
|
||||
<AccordionItem>
|
||||
<AccordionButton>
|
||||
<div className="model-list-button">
|
||||
<h2>Models</h2>
|
||||
<AccordionIcon />
|
||||
</div>
|
||||
</AccordionButton>
|
||||
<Accordion
|
||||
allowToggle
|
||||
className="model-list-accordion"
|
||||
variant={'unstyled'}
|
||||
>
|
||||
<AccordionItem>
|
||||
<AccordionButton>
|
||||
<div className="model-list-button">
|
||||
<h2>Models</h2>
|
||||
<AccordionIcon />
|
||||
</div>
|
||||
</AccordionButton>
|
||||
|
||||
<AccordionPanel>
|
||||
<div className="model-list-list">
|
||||
{models.map((model, i) => (
|
||||
<ModelListItem
|
||||
key={i}
|
||||
name={model.name}
|
||||
status={model.status}
|
||||
description={model.description}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
<AccordionPanel>
|
||||
<div className="model-list-list">
|
||||
{models.map((model, i) => (
|
||||
<ModelListItem
|
||||
key={i}
|
||||
name={model.name}
|
||||
status={model.status}
|
||||
description={model.description}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -14,18 +14,18 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import _, { isEqual } from 'lodash';
|
||||
import { cloneElement, ReactElement } from 'react';
|
||||
import { RootState, useAppSelector } from '../../../app/store';
|
||||
import { ChangeEvent, cloneElement, ReactElement } from 'react';
|
||||
import { RootState, useAppDispatch, useAppSelector } from '../../../app/store';
|
||||
import { persistor } from '../../../main';
|
||||
import {
|
||||
setShouldConfirmOnDelete,
|
||||
setShouldDisplayGuides,
|
||||
setShouldDisplayInProgressType,
|
||||
SystemState,
|
||||
} from '../systemSlice';
|
||||
import ModelList from './ModelList';
|
||||
import { SettingsModalItem, SettingsModalSelectItem } from './SettingsModalItem';
|
||||
import { IN_PROGRESS_IMAGE_TYPES } from '../../../app/constants';
|
||||
import IAISwitch from '../../../common/components/IAISwitch';
|
||||
import IAISelect from '../../../common/components/IAISelect';
|
||||
|
||||
const systemSelector = createSelector(
|
||||
(state: RootState) => state.system,
|
||||
@ -60,6 +60,8 @@ type SettingsModalProps = {
|
||||
* Secondary post-reset modal is included here.
|
||||
*/
|
||||
const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const {
|
||||
isOpen: isSettingsModalOpen,
|
||||
onOpen: onSettingsModalOpen,
|
||||
@ -101,26 +103,32 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
<ModalHeader className="settings-modal-header">Settings</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody className="settings-modal-content">
|
||||
<ModelList />
|
||||
<div className="settings-modal-items">
|
||||
|
||||
<SettingsModalSelectItem
|
||||
settingTitle="Display In-Progress Images"
|
||||
<div className="settings-modal-item">
|
||||
<ModelList />
|
||||
</div>
|
||||
<IAISelect
|
||||
styleClass="settings-modal-item"
|
||||
label={'Display In-Progress Images'}
|
||||
validValues={IN_PROGRESS_IMAGE_TYPES}
|
||||
defaultValue={shouldDisplayInProgressType}
|
||||
dispatcher={setShouldDisplayInProgressType}
|
||||
value={shouldDisplayInProgressType}
|
||||
/>
|
||||
|
||||
<SettingsModalItem
|
||||
settingTitle="Confirm on Delete"
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={'Confirm on Delete'}
|
||||
isChecked={shouldConfirmOnDelete}
|
||||
dispatcher={setShouldConfirmOnDelete}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldConfirmOnDelete(e.target.checked))
|
||||
}
|
||||
/>
|
||||
|
||||
<SettingsModalItem
|
||||
settingTitle="Display Help Icons"
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={'Display Help Icons'}
|
||||
isChecked={shouldDisplayGuides}
|
||||
dispatcher={setShouldDisplayGuides}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldDisplayGuides(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -1,50 +0,0 @@
|
||||
import { useAppDispatch } from '../../../app/store';
|
||||
import IAISelect from '../../../common/components/IAISelect';
|
||||
import IAISwitch from '../../../common/components/IAISwitch';
|
||||
|
||||
export function SettingsModalItem({
|
||||
settingTitle,
|
||||
isChecked,
|
||||
dispatcher,
|
||||
}: {
|
||||
settingTitle: string;
|
||||
isChecked: boolean;
|
||||
dispatcher: any;
|
||||
}) {
|
||||
const dispatch = useAppDispatch();
|
||||
return (
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={settingTitle}
|
||||
isChecked={isChecked}
|
||||
onChange={(e) => dispatch(dispatcher(e.target.checked))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export function SettingsModalSelectItem({
|
||||
settingTitle,
|
||||
validValues,
|
||||
defaultValue,
|
||||
dispatcher,
|
||||
}: {
|
||||
settingTitle: string;
|
||||
validValues:
|
||||
Array<number | string>
|
||||
| Array<{ key: string; value: string | number }>;
|
||||
defaultValue: string;
|
||||
dispatcher: any;
|
||||
}) {
|
||||
const dispatch = useAppDispatch();
|
||||
return (
|
||||
<IAISelect
|
||||
styleClass="settings-modal-item"
|
||||
label={settingTitle}
|
||||
validValues={validValues}
|
||||
defaultValue={defaultValue}
|
||||
onChange={(e) => dispatch(dispatcher(e.target.value))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { IconButton, Link, Tooltip, useColorMode } from '@chakra-ui/react';
|
||||
import { Link, useColorMode } from '@chakra-ui/react';
|
||||
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
import { FaSun, FaMoon, FaGithub, FaDiscord, FaBug } from 'react-icons/fa';
|
||||
import { MdHelp, MdKeyboard, MdSettings } from 'react-icons/md';
|
||||
import { MdKeyboard, MdSettings } from 'react-icons/md';
|
||||
|
||||
import InvokeAILogo from '../../assets/images/logo.png';
|
||||
import IAIIconButton from '../../common/components/IAIIconButton';
|
||||
@ -91,18 +91,18 @@ const SiteHeader = () => {
|
||||
}
|
||||
/>
|
||||
|
||||
<IAIIconButton
|
||||
aria-label="Link to Discord Server"
|
||||
tooltip="Discord"
|
||||
variant="link"
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
icon={
|
||||
<Link isExternal href="https://discord.gg/ZmtBAhwWhy">
|
||||
<FaDiscord />
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label="Link to Discord Server"
|
||||
tooltip="Discord"
|
||||
variant="link"
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
icon={
|
||||
<Link isExternal href="https://discord.gg/ZmtBAhwWhy">
|
||||
<FaDiscord />
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
|
||||
<SettingsModal>
|
||||
<IAIIconButton
|
||||
|
@ -17,7 +17,7 @@ import ImageToImageWorkarea from './ImageToImage';
|
||||
import InpaintingWorkarea from './Inpainting';
|
||||
import TextToImageWorkarea from './TextToImage';
|
||||
|
||||
export const tab_dict = {
|
||||
export const tabDict = {
|
||||
txt2img: {
|
||||
title: <TextToImageIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
workarea: <TextToImageWorkarea />,
|
||||
@ -50,8 +50,8 @@ export const tab_dict = {
|
||||
},
|
||||
};
|
||||
|
||||
// Array where index maps to the key of tab_dict
|
||||
export const tabMap = _.map(tab_dict, (tab, key) => key);
|
||||
// Array where index maps to the key of tabDict
|
||||
export const tabMap = _.map(tabDict, (tab, key) => key);
|
||||
|
||||
// Use tabMap to generate a union type of tab names
|
||||
const tabMapTypes = [...tabMap] as const;
|
||||
@ -89,15 +89,15 @@ export default function InvokeTabs() {
|
||||
|
||||
const renderTabs = () => {
|
||||
const tabsToRender: ReactElement[] = [];
|
||||
Object.keys(tab_dict).forEach((key) => {
|
||||
Object.keys(tabDict).forEach((key) => {
|
||||
tabsToRender.push(
|
||||
<Tooltip
|
||||
key={key}
|
||||
hasArrow
|
||||
label={tab_dict[key as keyof typeof tab_dict].tooltip}
|
||||
label={tabDict[key as keyof typeof tabDict].tooltip}
|
||||
placement={'right'}
|
||||
>
|
||||
<Tab>{tab_dict[key as keyof typeof tab_dict].title}</Tab>
|
||||
<Tab>{tabDict[key as keyof typeof tabDict].title}</Tab>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
@ -106,10 +106,10 @@ export default function InvokeTabs() {
|
||||
|
||||
const renderTabPanels = () => {
|
||||
const tabPanelsToRender: ReactElement[] = [];
|
||||
Object.keys(tab_dict).forEach((key) => {
|
||||
Object.keys(tabDict).forEach((key) => {
|
||||
tabPanelsToRender.push(
|
||||
<TabPanel className="app-tabs-panel" key={key}>
|
||||
{tab_dict[key as keyof typeof tab_dict].workarea}
|
||||
{tabDict[key as keyof typeof tabDict].workarea}
|
||||
</TabPanel>
|
||||
);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user