mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
ui: support dark mode (#3592)
[feat(ui): remove themes, add hand-crafted dark and light modes](032c7e68d0
) [032c7e6
](032c7e68d0
) Themes are very fun but due to the differences in perceived saturation and lightness across the the color spectrum, it's impossible to have have multiple themes that look great without hand- crafting *every* shade for *every* theme. We've ended up with 4 OK themes (well, 3, because the light theme was pretty bad). I've removed the themes and added color mode support. There is now a single dark and light mode, each with their own color palette and the classic grey / purple / yellow invoke colors that @blessedcoolant first designed. I've re-styled almost everything except the model manager and lightbox, which I keep forgetting to work on. One new concept is the Chakra `layerStyle`. This lets us define "layers" - think body, first layer, second layer, etc - that can be applied on various components. By defining layers, we can be more consistent about the z-axis and its relationship to color and lightness.
This commit is contained in:
commit
877483093a
@ -24,16 +24,13 @@
|
||||
},
|
||||
"common": {
|
||||
"hotkeysLabel": "Hotkeys",
|
||||
"themeLabel": "Theme",
|
||||
"darkMode": "Dark Mode",
|
||||
"lightMode": "Light Mode",
|
||||
"languagePickerLabel": "Language",
|
||||
"reportBugLabel": "Report Bug",
|
||||
"githubLabel": "Github",
|
||||
"discordLabel": "Discord",
|
||||
"settingsLabel": "Settings",
|
||||
"darkTheme": "Dark",
|
||||
"lightTheme": "Light",
|
||||
"greenTheme": "Green",
|
||||
"oceanTheme": "Ocean",
|
||||
"langArabic": "العربية",
|
||||
"langEnglish": "English",
|
||||
"langDutch": "Nederlands",
|
||||
|
@ -3,17 +3,10 @@ import {
|
||||
createLocalStorageManager,
|
||||
extendTheme,
|
||||
} from '@chakra-ui/react';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { ReactNode, useEffect } from 'react';
|
||||
import { ReactNode, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { theme as invokeAITheme } from 'theme/theme';
|
||||
|
||||
import { greenTeaThemeColors } from 'theme/colors/greenTea';
|
||||
import { invokeAIThemeColors } from 'theme/colors/invokeAI';
|
||||
import { lightThemeColors } from 'theme/colors/lightTheme';
|
||||
import { oceanBlueColors } from 'theme/colors/oceanBlue';
|
||||
|
||||
import '@fontsource-variable/inter';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import { mantineTheme } from 'mantine-theme/theme';
|
||||
@ -24,29 +17,19 @@ type ThemeLocaleProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const THEMES = {
|
||||
dark: invokeAIThemeColors,
|
||||
light: lightThemeColors,
|
||||
green: greenTeaThemeColors,
|
||||
ocean: oceanBlueColors,
|
||||
};
|
||||
|
||||
const manager = createLocalStorageManager('@@invokeai-color-mode');
|
||||
|
||||
function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const currentTheme = useAppSelector(
|
||||
(state: RootState) => state.ui.currentTheme
|
||||
);
|
||||
|
||||
const direction = i18n.dir();
|
||||
|
||||
const theme = extendTheme({
|
||||
const theme = useMemo(() => {
|
||||
return extendTheme({
|
||||
...invokeAITheme,
|
||||
colors: THEMES[currentTheme as keyof typeof THEMES],
|
||||
direction,
|
||||
});
|
||||
}, [direction]);
|
||||
|
||||
useEffect(() => {
|
||||
document.body.dir = direction;
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import { Box, Collapse, Flex, Spacer, Switch } from '@chakra-ui/react';
|
||||
import {
|
||||
Box,
|
||||
Collapse,
|
||||
Flex,
|
||||
Spacer,
|
||||
Switch,
|
||||
useColorMode,
|
||||
} from '@chakra-ui/react';
|
||||
import { PropsWithChildren, memo } from 'react';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
export type IAIToggleCollapseProps = PropsWithChildren & {
|
||||
label: string;
|
||||
@ -11,6 +19,7 @@ export type IAIToggleCollapseProps = PropsWithChildren & {
|
||||
|
||||
const IAICollapse = (props: IAIToggleCollapseProps) => {
|
||||
const { label, isOpen, onToggle, children, withSwitch = false } = props;
|
||||
const { colorMode } = useColorMode();
|
||||
return (
|
||||
<Box>
|
||||
<Flex
|
||||
@ -21,10 +30,14 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
|
||||
px: 4,
|
||||
borderTopRadius: 'base',
|
||||
borderBottomRadius: isOpen ? 0 : 'base',
|
||||
bg: isOpen ? 'base.750' : 'base.800',
|
||||
color: 'base.100',
|
||||
bg: isOpen
|
||||
? mode('base.200', 'base.750')(colorMode)
|
||||
: mode('base.150', 'base.800')(colorMode),
|
||||
color: mode('base.900', 'base.100')(colorMode),
|
||||
_hover: {
|
||||
bg: isOpen ? 'base.700' : 'base.750',
|
||||
bg: isOpen
|
||||
? mode('base.250', 'base.700')(colorMode)
|
||||
: mode('base.200', 'base.750')(colorMode),
|
||||
},
|
||||
fontSize: 'sm',
|
||||
fontWeight: 600,
|
||||
@ -50,7 +63,13 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
|
||||
)}
|
||||
</Flex>
|
||||
<Collapse in={isOpen} animateOpacity style={{ overflow: 'unset' }}>
|
||||
<Box sx={{ p: 4, borderBottomRadius: 'base', bg: 'base.800' }}>
|
||||
<Box
|
||||
sx={{
|
||||
p: 4,
|
||||
borderBottomRadius: 'base',
|
||||
bg: mode('base.100', 'base.800')(colorMode),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
</Collapse>
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
Icon,
|
||||
IconButtonProps,
|
||||
Image,
|
||||
useColorMode,
|
||||
} from '@chakra-ui/react';
|
||||
import { useDraggable, useDroppable } from '@dnd-kit/core';
|
||||
import { useCombinedRefs } from '@dnd-kit/utilities';
|
||||
@ -20,6 +21,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import IAIDropOverlay from './IAIDropOverlay';
|
||||
import { PostUploadAction } from 'services/api/thunks/image';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
type IAIDndImageProps = {
|
||||
image: ImageDTO | null | undefined;
|
||||
@ -62,6 +64,7 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
} = props;
|
||||
|
||||
const dndId = useRef(uuidv4());
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
const {
|
||||
isOver,
|
||||
@ -99,10 +102,10 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
? {}
|
||||
: {
|
||||
cursor: 'pointer',
|
||||
bg: 'base.800',
|
||||
bg: mode('base.200', 'base.800')(colorMode),
|
||||
_hover: {
|
||||
bg: 'base.750',
|
||||
color: 'base.300',
|
||||
bg: mode('base.300', 'base.650')(colorMode),
|
||||
color: mode('base.500', 'base.300')(colorMode),
|
||||
},
|
||||
};
|
||||
|
||||
@ -181,7 +184,7 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
borderRadius: 'base',
|
||||
transitionProperty: 'common',
|
||||
transitionDuration: '0.1s',
|
||||
color: 'base.500',
|
||||
color: mode('base.500', 'base.500')(colorMode),
|
||||
...uploadButtonStyles,
|
||||
}}
|
||||
{...getUploadButtonProps()}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Flex, Text } from '@chakra-ui/react';
|
||||
import { Flex, Text, useColorMode } from '@chakra-ui/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { memo, useRef } from 'react';
|
||||
import { mode } from 'theme/util/mode';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
type Props = {
|
||||
@ -11,6 +12,7 @@ type Props = {
|
||||
export const IAIDropOverlay = (props: Props) => {
|
||||
const { isOver, label = 'Drop' } = props;
|
||||
const motionId = useRef(uuidv4());
|
||||
const { colorMode } = useColorMode();
|
||||
return (
|
||||
<motion.div
|
||||
key={motionId.current}
|
||||
@ -42,7 +44,7 @@ export const IAIDropOverlay = (props: Props) => {
|
||||
insetInlineStart: 0,
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
bg: 'base.900',
|
||||
bg: mode('base.700', 'base.900')(colorMode),
|
||||
opacity: 0.7,
|
||||
borderRadius: 'base',
|
||||
alignItems: 'center',
|
||||
@ -61,7 +63,9 @@ export const IAIDropOverlay = (props: Props) => {
|
||||
h: 'full',
|
||||
opacity: 1,
|
||||
borderWidth: 2,
|
||||
borderColor: isOver ? 'base.200' : 'base.500',
|
||||
borderColor: isOver
|
||||
? mode('base.50', 'base.200')(colorMode)
|
||||
: mode('base.100', 'base.500')(colorMode),
|
||||
borderRadius: 'base',
|
||||
borderStyle: 'dashed',
|
||||
transitionProperty: 'common',
|
||||
@ -75,7 +79,9 @@ export const IAIDropOverlay = (props: Props) => {
|
||||
fontSize: '2xl',
|
||||
fontWeight: 600,
|
||||
transform: isOver ? 'scale(1.1)' : 'scale(1)',
|
||||
color: isOver ? 'base.100' : 'base.500',
|
||||
color: isOver
|
||||
? mode('base.100', 'base.100')(colorMode)
|
||||
: mode('base.200', 'base.500')(colorMode),
|
||||
transitionProperty: 'common',
|
||||
transitionDuration: '0.1s',
|
||||
}}
|
||||
|
@ -6,9 +6,10 @@ import {
|
||||
IconProps,
|
||||
Spinner,
|
||||
SpinnerProps,
|
||||
useColorMode,
|
||||
} from '@chakra-ui/react';
|
||||
import { ReactElement } from 'react';
|
||||
import { FaImage } from 'react-icons/fa';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
type Props = FlexProps & {
|
||||
spinnerProps?: SpinnerProps;
|
||||
@ -17,10 +18,11 @@ type Props = FlexProps & {
|
||||
export const IAIImageLoadingFallback = (props: Props) => {
|
||||
const { spinnerProps, ...rest } = props;
|
||||
const { sx, ...restFlexProps } = rest;
|
||||
const { colorMode } = useColorMode();
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
bg: 'base.900',
|
||||
bg: mode('base.200', 'base.900')(colorMode),
|
||||
opacity: 0.7,
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
@ -45,10 +47,12 @@ type IAINoImageFallbackProps = {
|
||||
export const IAINoImageFallback = (props: IAINoImageFallbackProps) => {
|
||||
const { sx: flexSx, ...restFlexProps } = props.flexProps ?? { sx: {} };
|
||||
const { sx: iconSx, ...restIconProps } = props.iconProps ?? { sx: {} };
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
bg: 'base.900',
|
||||
bg: mode('base.200', 'base.900')(colorMode),
|
||||
opacity: 0.7,
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
@ -61,7 +65,7 @@ export const IAINoImageFallback = (props: IAINoImageFallbackProps) => {
|
||||
>
|
||||
<Icon
|
||||
as={props.as ?? FaImage}
|
||||
sx={{ color: 'base.700', ...iconSx }}
|
||||
sx={{ color: mode('base.700', 'base.500')(colorMode), ...iconSx }}
|
||||
{...restIconProps}
|
||||
/>
|
||||
</Flex>
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { Tooltip, useColorMode, useToken } from '@chakra-ui/react';
|
||||
import { MultiSelect, MultiSelectProps } from '@mantine/core';
|
||||
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
|
||||
import { memo } from 'react';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
type IAIMultiSelectProps = MultiSelectProps & {
|
||||
tooltip?: string;
|
||||
@ -8,71 +10,99 @@ type IAIMultiSelectProps = MultiSelectProps & {
|
||||
|
||||
const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
|
||||
const { searchable = true, tooltip, ...rest } = props;
|
||||
const {
|
||||
base50,
|
||||
base100,
|
||||
base200,
|
||||
base300,
|
||||
base400,
|
||||
base500,
|
||||
base600,
|
||||
base700,
|
||||
base800,
|
||||
base900,
|
||||
accent200,
|
||||
accent300,
|
||||
accent400,
|
||||
accent500,
|
||||
accent600,
|
||||
} = useChakraThemeTokens();
|
||||
const [boxShadow] = useToken('shadows', ['dark-lg']);
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
return (
|
||||
<Tooltip label={tooltip} placement="top" hasArrow>
|
||||
<MultiSelect
|
||||
searchable={searchable}
|
||||
styles={() => ({
|
||||
label: {
|
||||
color: 'var(--invokeai-colors-base-300)',
|
||||
color: mode(base700, base300)(colorMode),
|
||||
fontWeight: 'normal',
|
||||
},
|
||||
searchInput: {
|
||||
'::placeholder': {
|
||||
color: 'var(--invokeai-colors-base-700)',
|
||||
':placeholder': {
|
||||
color: mode(base300, base700)(colorMode),
|
||||
},
|
||||
},
|
||||
input: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-900)',
|
||||
backgroundColor: mode(base50, base900)(colorMode),
|
||||
borderWidth: '2px',
|
||||
borderColor: 'var(--invokeai-colors-base-800)',
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
borderColor: mode(base200, base800)(colorMode),
|
||||
color: mode(base900, base100)(colorMode),
|
||||
paddingRight: 24,
|
||||
fontWeight: 600,
|
||||
'&:hover': { borderColor: 'var(--invokeai-colors-base-700)' },
|
||||
'&:hover': { borderColor: mode(base300, base600)(colorMode) },
|
||||
'&:focus': {
|
||||
borderColor: 'var(--invokeai-colors-accent-600)',
|
||||
borderColor: mode(accent300, accent600)(colorMode),
|
||||
},
|
||||
'&:is(:focus, :hover)': {
|
||||
borderColor: mode(base400, base500)(colorMode),
|
||||
},
|
||||
'&:focus-within': {
|
||||
borderColor: 'var(--invokeai-colors-accent-600)',
|
||||
borderColor: mode(accent200, accent600)(colorMode),
|
||||
},
|
||||
'&:disabled': {
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
color: mode(base600, base400)(colorMode),
|
||||
},
|
||||
},
|
||||
value: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-800)',
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
backgroundColor: mode(base200, base800)(colorMode),
|
||||
color: mode(base900, base100)(colorMode),
|
||||
button: {
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
color: mode(base900, base100)(colorMode),
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--invokeai-colors-base-700)',
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
dropdown: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-800)',
|
||||
borderColor: 'var(--invokeai-colors-base-700)',
|
||||
backgroundColor: mode(base200, base800)(colorMode),
|
||||
borderColor: mode(base200, base800)(colorMode),
|
||||
boxShadow,
|
||||
},
|
||||
item: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-800)',
|
||||
color: 'var(--invokeai-colors-base-200)',
|
||||
backgroundColor: mode(base200, base800)(colorMode),
|
||||
color: mode(base800, base200)(colorMode),
|
||||
padding: 6,
|
||||
'&[data-hovered]': {
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
backgroundColor: 'var(--invokeai-colors-base-750)',
|
||||
color: mode(base900, base100)(colorMode),
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
},
|
||||
'&[data-active]': {
|
||||
backgroundColor: 'var(--invokeai-colors-base-750)',
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
'&:hover': {
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
backgroundColor: 'var(--invokeai-colors-base-750)',
|
||||
color: mode(base900, base100)(colorMode),
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
},
|
||||
},
|
||||
'&[data-selected]': {
|
||||
color: 'var(--invokeai-colors-base-50)',
|
||||
backgroundColor: 'var(--invokeai-colors-accent-650)',
|
||||
color: mode(base900, base50)(colorMode),
|
||||
backgroundColor: mode(accent300, accent600)(colorMode),
|
||||
fontWeight: 600,
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--invokeai-colors-accent-600)',
|
||||
backgroundColor: mode(accent400, accent500)(colorMode),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -80,7 +110,7 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
|
||||
width: 24,
|
||||
padding: 20,
|
||||
button: {
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
color: mode(base900, base100)(colorMode),
|
||||
},
|
||||
},
|
||||
})}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { Tooltip, useColorMode, useToken } from '@chakra-ui/react';
|
||||
import { Select, SelectProps } from '@mantine/core';
|
||||
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
|
||||
import { memo } from 'react';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
export type IAISelectDataType = {
|
||||
value: string;
|
||||
@ -14,61 +16,104 @@ type IAISelectProps = SelectProps & {
|
||||
|
||||
const IAIMantineSelect = (props: IAISelectProps) => {
|
||||
const { searchable = true, tooltip, ...rest } = props;
|
||||
const {
|
||||
base50,
|
||||
base100,
|
||||
base200,
|
||||
base300,
|
||||
base400,
|
||||
base500,
|
||||
base600,
|
||||
base700,
|
||||
base800,
|
||||
base900,
|
||||
accent200,
|
||||
accent300,
|
||||
accent400,
|
||||
accent500,
|
||||
accent600,
|
||||
} = useChakraThemeTokens();
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
const [boxShadow] = useToken('shadows', ['dark-lg']);
|
||||
|
||||
return (
|
||||
<Tooltip label={tooltip} placement="top" hasArrow>
|
||||
<Select
|
||||
searchable={searchable}
|
||||
styles={() => ({
|
||||
label: {
|
||||
color: 'var(--invokeai-colors-base-300)',
|
||||
color: mode(base700, base300)(colorMode),
|
||||
fontWeight: 'normal',
|
||||
},
|
||||
input: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-900)',
|
||||
backgroundColor: mode(base50, base900)(colorMode),
|
||||
borderWidth: '2px',
|
||||
borderColor: 'var(--invokeai-colors-base-800)',
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
borderColor: mode(base200, base800)(colorMode),
|
||||
color: mode(base900, base100)(colorMode),
|
||||
paddingRight: 24,
|
||||
fontWeight: 600,
|
||||
'&:hover': { borderColor: 'var(--invokeai-colors-base-700)' },
|
||||
'&:hover': { borderColor: mode(base300, base600)(colorMode) },
|
||||
'&:focus': {
|
||||
borderColor: 'var(--invokeai-colors-accent-600)',
|
||||
borderColor: mode(accent300, accent600)(colorMode),
|
||||
},
|
||||
'&:is(:focus, :hover)': {
|
||||
borderColor: mode(base400, base500)(colorMode),
|
||||
},
|
||||
'&:focus-within': {
|
||||
borderColor: mode(accent200, accent600)(colorMode),
|
||||
},
|
||||
'&:disabled': {
|
||||
backgroundColor: 'var(--invokeai-colors-base-700)',
|
||||
color: 'var(--invokeai-colors-base-400)',
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
color: mode(base600, base400)(colorMode),
|
||||
},
|
||||
},
|
||||
value: {
|
||||
backgroundColor: mode(base100, base900)(colorMode),
|
||||
color: mode(base900, base100)(colorMode),
|
||||
button: {
|
||||
color: mode(base900, base100)(colorMode),
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
dropdown: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-800)',
|
||||
borderColor: 'var(--invokeai-colors-base-700)',
|
||||
backgroundColor: mode(base200, base800)(colorMode),
|
||||
borderColor: mode(base200, base800)(colorMode),
|
||||
boxShadow,
|
||||
},
|
||||
item: {
|
||||
backgroundColor: 'var(--invokeai-colors-base-800)',
|
||||
color: 'var(--invokeai-colors-base-200)',
|
||||
backgroundColor: mode(base200, base800)(colorMode),
|
||||
color: mode(base800, base200)(colorMode),
|
||||
padding: 6,
|
||||
'&[data-hovered]': {
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
backgroundColor: 'var(--invokeai-colors-base-750)',
|
||||
color: mode(base900, base100)(colorMode),
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
},
|
||||
'&[data-active]': {
|
||||
backgroundColor: 'var(--invokeai-colors-base-750)',
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
'&:hover': {
|
||||
color: 'var(--invokeai-colors-base-100)',
|
||||
backgroundColor: 'var(--invokeai-colors-base-750)',
|
||||
color: mode(base900, base100)(colorMode),
|
||||
backgroundColor: mode(base300, base700)(colorMode),
|
||||
},
|
||||
},
|
||||
'&[data-selected]': {
|
||||
color: 'var(--invokeai-colors-base-50)',
|
||||
backgroundColor: 'var(--invokeai-colors-accent-650)',
|
||||
color: mode(base900, base50)(colorMode),
|
||||
backgroundColor: mode(accent300, accent600)(colorMode),
|
||||
fontWeight: 600,
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--invokeai-colors-accent-600)',
|
||||
backgroundColor: mode(accent400, accent500)(colorMode),
|
||||
},
|
||||
},
|
||||
},
|
||||
rightSection: {
|
||||
width: 32,
|
||||
button: {
|
||||
color: mode(base900, base100)(colorMode),
|
||||
},
|
||||
},
|
||||
})}
|
||||
{...rest}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Checkbox, CheckboxProps, Text } from '@chakra-ui/react';
|
||||
import { Checkbox, CheckboxProps, Text, useColorMode } from '@chakra-ui/react';
|
||||
import { memo, ReactElement } from 'react';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
type IAISimpleCheckboxProps = CheckboxProps & {
|
||||
label: string | ReactElement;
|
||||
@ -7,9 +8,15 @@ type IAISimpleCheckboxProps = CheckboxProps & {
|
||||
|
||||
const IAISimpleCheckbox = (props: IAISimpleCheckboxProps) => {
|
||||
const { label, ...rest } = props;
|
||||
const { colorMode } = useColorMode();
|
||||
return (
|
||||
<Checkbox colorScheme="accent" {...rest}>
|
||||
<Text color="base.200" fontSize="md">
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: 'sm',
|
||||
color: mode('base.800', 'base.200')(colorMode),
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</Checkbox>
|
||||
|
124
invokeai/frontend/web/src/common/hooks/useChakraThemeTokens.ts
Normal file
124
invokeai/frontend/web/src/common/hooks/useChakraThemeTokens.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import { useToken } from '@chakra-ui/react';
|
||||
|
||||
export const useChakraThemeTokens = () => {
|
||||
const [
|
||||
base50,
|
||||
base100,
|
||||
base150,
|
||||
base200,
|
||||
base250,
|
||||
base300,
|
||||
base350,
|
||||
base400,
|
||||
base450,
|
||||
base500,
|
||||
base550,
|
||||
base600,
|
||||
base650,
|
||||
base700,
|
||||
base750,
|
||||
base800,
|
||||
base850,
|
||||
base900,
|
||||
base950,
|
||||
accent50,
|
||||
accent100,
|
||||
accent150,
|
||||
accent200,
|
||||
accent250,
|
||||
accent300,
|
||||
accent350,
|
||||
accent400,
|
||||
accent450,
|
||||
accent500,
|
||||
accent550,
|
||||
accent600,
|
||||
accent650,
|
||||
accent700,
|
||||
accent750,
|
||||
accent800,
|
||||
accent850,
|
||||
accent900,
|
||||
accent950,
|
||||
] = useToken('colors', [
|
||||
'base.50',
|
||||
'base.100',
|
||||
'base.150',
|
||||
'base.200',
|
||||
'base.250',
|
||||
'base.300',
|
||||
'base.350',
|
||||
'base.400',
|
||||
'base.450',
|
||||
'base.500',
|
||||
'base.550',
|
||||
'base.600',
|
||||
'base.650',
|
||||
'base.700',
|
||||
'base.750',
|
||||
'base.800',
|
||||
'base.850',
|
||||
'base.900',
|
||||
'base.950',
|
||||
'accent.50',
|
||||
'accent.100',
|
||||
'accent.150',
|
||||
'accent.200',
|
||||
'accent.250',
|
||||
'accent.300',
|
||||
'accent.350',
|
||||
'accent.400',
|
||||
'accent.450',
|
||||
'accent.500',
|
||||
'accent.550',
|
||||
'accent.600',
|
||||
'accent.650',
|
||||
'accent.700',
|
||||
'accent.750',
|
||||
'accent.800',
|
||||
'accent.850',
|
||||
'accent.900',
|
||||
'accent.950',
|
||||
]);
|
||||
|
||||
return {
|
||||
base50,
|
||||
base100,
|
||||
base150,
|
||||
base200,
|
||||
base250,
|
||||
base300,
|
||||
base350,
|
||||
base400,
|
||||
base450,
|
||||
base500,
|
||||
base550,
|
||||
base600,
|
||||
base650,
|
||||
base700,
|
||||
base750,
|
||||
base800,
|
||||
base850,
|
||||
base900,
|
||||
base950,
|
||||
accent50,
|
||||
accent100,
|
||||
accent150,
|
||||
accent200,
|
||||
accent250,
|
||||
accent300,
|
||||
accent350,
|
||||
accent400,
|
||||
accent450,
|
||||
accent500,
|
||||
accent550,
|
||||
accent600,
|
||||
accent650,
|
||||
accent700,
|
||||
accent750,
|
||||
accent800,
|
||||
accent850,
|
||||
accent900,
|
||||
accent950,
|
||||
};
|
||||
};
|
@ -1,8 +1,7 @@
|
||||
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
|
||||
|
||||
import { useToken } from '@chakra-ui/react';
|
||||
import { useColorMode, useToken } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { isEqual, range } from 'lodash-es';
|
||||
@ -24,14 +23,14 @@ const selector = createSelector(
|
||||
);
|
||||
|
||||
const IAICanvasGrid = () => {
|
||||
const currentTheme = useAppSelector(
|
||||
(state: RootState) => state.ui.currentTheme
|
||||
);
|
||||
const { stageScale, stageCoordinates, stageDimensions } =
|
||||
useAppSelector(selector);
|
||||
const { colorMode } = useColorMode();
|
||||
const [gridLines, setGridLines] = useState<ReactNode[]>([]);
|
||||
|
||||
const [gridLineColor] = useToken('colors', ['gridLineColor']);
|
||||
const [darkGridLineColor, lightGridLineColor] = useToken('colors', [
|
||||
'base.800',
|
||||
'base.200',
|
||||
]);
|
||||
|
||||
const unscale = useCallback(
|
||||
(value: number) => {
|
||||
@ -89,7 +88,7 @@ const IAICanvasGrid = () => {
|
||||
x={fullRect.x1 + i * 64}
|
||||
y={fullRect.y1}
|
||||
points={[0, 0, 0, ySize]}
|
||||
stroke={gridLineColor}
|
||||
stroke={colorMode === 'dark' ? darkGridLineColor : lightGridLineColor}
|
||||
strokeWidth={1}
|
||||
/>
|
||||
));
|
||||
@ -99,7 +98,7 @@ const IAICanvasGrid = () => {
|
||||
x={fullRect.x1}
|
||||
y={fullRect.y1 + i * 64}
|
||||
points={[0, 0, xSize, 0]}
|
||||
stroke={gridLineColor}
|
||||
stroke={colorMode === 'dark' ? darkGridLineColor : lightGridLineColor}
|
||||
strokeWidth={1}
|
||||
/>
|
||||
));
|
||||
@ -109,9 +108,10 @@ const IAICanvasGrid = () => {
|
||||
stageScale,
|
||||
stageCoordinates,
|
||||
stageDimensions,
|
||||
currentTheme,
|
||||
unscale,
|
||||
gridLineColor,
|
||||
colorMode,
|
||||
darkGridLineColor,
|
||||
lightGridLineColor,
|
||||
]);
|
||||
|
||||
return <Group>{gridLines}</Group>;
|
||||
|
@ -104,7 +104,10 @@ const IAICanvasStatusText = () => {
|
||||
margin: 1,
|
||||
borderRadius: 'base',
|
||||
pointerEvents: 'none',
|
||||
bg: 'base.200',
|
||||
_dark: {
|
||||
bg: 'base.800',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Box, ChakraProps, Flex } from '@chakra-ui/react';
|
||||
import { Box, ChakraProps, Flex, useColorMode } from '@chakra-ui/react';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { FaCopy, FaTrash } from 'react-icons/fa';
|
||||
@ -22,6 +22,7 @@ import ParamControlNetShouldAutoConfig from './ParamControlNetShouldAutoConfig';
|
||||
import ParamControlNetBeginEnd from './parameters/ParamControlNetBeginEnd';
|
||||
import ParamControlNetControlMode from './parameters/ParamControlNetControlMode';
|
||||
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
const expandedControlImageSx: ChakraProps['sx'] = { maxH: 96 };
|
||||
|
||||
@ -46,7 +47,7 @@ const ControlNet = (props: ControlNetProps) => {
|
||||
} = props.controlNet;
|
||||
const dispatch = useAppDispatch();
|
||||
const [isExpanded, toggleIsExpanded] = useToggle(false);
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
const handleDelete = useCallback(() => {
|
||||
dispatch(controlNetRemoved({ controlNetId }));
|
||||
}, [controlNetId, dispatch]);
|
||||
@ -67,7 +68,7 @@ const ControlNet = (props: ControlNetProps) => {
|
||||
flexDir: 'column',
|
||||
gap: 2,
|
||||
p: 3,
|
||||
bg: 'base.850',
|
||||
bg: mode('base.200', 'base.850')(colorMode),
|
||||
borderRadius: 'base',
|
||||
position: 'relative',
|
||||
}}
|
||||
@ -115,7 +116,7 @@ const ControlNet = (props: ControlNetProps) => {
|
||||
<ChevronUpIcon
|
||||
sx={{
|
||||
boxSize: 4,
|
||||
color: 'base.300',
|
||||
color: mode('base.700', 'base.300')(colorMode),
|
||||
transform: isExpanded ? 'rotate(0deg)' : 'rotate(180deg)',
|
||||
transitionProperty: 'common',
|
||||
transitionDuration: 'normal',
|
||||
@ -130,7 +131,7 @@ const ControlNet = (props: ControlNetProps) => {
|
||||
w: 1.5,
|
||||
h: 1.5,
|
||||
borderRadius: 'full',
|
||||
bg: 'error.200',
|
||||
bg: mode('error.700', 'error.200')(colorMode),
|
||||
top: 4,
|
||||
insetInlineEnd: 4,
|
||||
}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Flex, Text } from '@chakra-ui/react';
|
||||
import { Flex, Text, useColorMode } from '@chakra-ui/react';
|
||||
import { FaImages } from 'react-icons/fa';
|
||||
import { boardIdSelected } from '../../store/boardSlice';
|
||||
import { useDispatch } from 'react-redux';
|
||||
@ -10,9 +10,11 @@ import { ImageDTO } from 'services/api/types';
|
||||
import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
const AllImagesBoard = ({ isSelected }: { isSelected: boolean }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
const handleAllImagesBoardClick = () => {
|
||||
dispatch(boardIdSelected());
|
||||
@ -79,7 +81,9 @@ const AllImagesBoard = ({ isSelected }: { isSelected: boolean }) => {
|
||||
</Flex>
|
||||
<Text
|
||||
sx={{
|
||||
color: isSelected ? 'base.50' : 'base.200',
|
||||
color: isSelected
|
||||
? mode('base.900', 'base.50')(colorMode)
|
||||
: mode('base.700', 'base.200')(colorMode),
|
||||
fontWeight: isSelected ? 600 : undefined,
|
||||
fontSize: 'xs',
|
||||
}}
|
||||
|
@ -62,13 +62,13 @@ const BoardsList = (props: Props) => {
|
||||
return (
|
||||
<Collapse in={isOpen} animateOpacity>
|
||||
<Flex
|
||||
layerStyle={'first'}
|
||||
sx={{
|
||||
flexDir: 'column',
|
||||
gap: 2,
|
||||
bg: 'base.800',
|
||||
borderRadius: 'base',
|
||||
p: 2,
|
||||
mt: 2,
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
<Flex sx={{ gap: 2, alignItems: 'center' }}>
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
Image,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
useColorMode,
|
||||
} from '@chakra-ui/react';
|
||||
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
@ -30,6 +31,7 @@ import { AnimatePresence } from 'framer-motion';
|
||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
||||
import { SelectedItemOverlay } from '../SelectedItemOverlay';
|
||||
import { DeleteBoardImagesContext } from '../../../../app/contexts/DeleteBoardImagesContext';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
interface HoverableBoardProps {
|
||||
board: BoardDTO;
|
||||
@ -43,6 +45,8 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||
board.cover_image_name ?? skipToken
|
||||
);
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
const { board_name, board_id } = board;
|
||||
|
||||
const { onClickDeleteBoardImages } = useContext(DeleteBoardImagesContext);
|
||||
@ -110,7 +114,7 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
sx={{ color: 'error.300' }}
|
||||
sx={{ color: mode('error.700', 'error.300')(colorMode) }}
|
||||
icon={<FaTrash />}
|
||||
onClickCapture={handleDeleteBoard}
|
||||
>
|
||||
@ -180,7 +184,9 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||
>
|
||||
<EditablePreview
|
||||
sx={{
|
||||
color: isSelected ? 'base.50' : 'base.200',
|
||||
color: isSelected
|
||||
? mode('base.900', 'base.50')(colorMode)
|
||||
: mode('base.700', 'base.200')(colorMode),
|
||||
fontWeight: isSelected ? 600 : undefined,
|
||||
fontSize: 'xs',
|
||||
textAlign: 'center',
|
||||
@ -190,9 +196,9 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||
/>
|
||||
<EditableInput
|
||||
sx={{
|
||||
color: 'base.50',
|
||||
color: mode('base.900', 'base.50')(colorMode),
|
||||
fontSize: 'xs',
|
||||
borderColor: 'base.500',
|
||||
borderColor: mode('base.500', 'base.500')(colorMode),
|
||||
p: 0,
|
||||
outline: 0,
|
||||
}}
|
||||
|
@ -32,7 +32,6 @@ const CurrentImageDisplay = () => {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
rowGap: 4,
|
||||
borderRadius: 'base',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
Text,
|
||||
VStack,
|
||||
forwardRef,
|
||||
useColorMode,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
@ -61,6 +62,7 @@ import BoardsList from './Boards/BoardsList';
|
||||
import { boardsSelector } from '../store/boardSlice';
|
||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
const itemSelector = createSelector(
|
||||
[(state: RootState) => state],
|
||||
@ -135,6 +137,8 @@ const ImageGalleryContent = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
const {
|
||||
shouldPinGallery,
|
||||
galleryImageMinimumWidth,
|
||||
@ -267,13 +271,17 @@ const ImageGalleryContent = () => {
|
||||
alignItems: 'center',
|
||||
px: 2,
|
||||
_hover: {
|
||||
bg: 'base.800',
|
||||
bg: mode('base.100', 'base.800')(colorMode),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
noOfLines={1}
|
||||
sx={{ w: 'full', color: 'base.200', fontWeight: 600 }}
|
||||
sx={{
|
||||
w: 'full',
|
||||
color: mode('base.800', 'base.200')(colorMode),
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{selectedBoard ? selectedBoard.board_name : 'All Images'}
|
||||
</Text>
|
||||
|
@ -1,6 +1,16 @@
|
||||
import { useColorMode, useToken } from '@chakra-ui/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
export const SelectedItemOverlay = () => (
|
||||
export const SelectedItemOverlay = () => {
|
||||
const [accent400, accent500] = useToken('colors', [
|
||||
'accent.400',
|
||||
'accent.500',
|
||||
]);
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{
|
||||
opacity: 0,
|
||||
@ -19,8 +29,12 @@ export const SelectedItemOverlay = () => (
|
||||
insetInlineStart: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
boxShadow: 'inset 0px 0px 0px 2px var(--invokeai-colors-accent-300)',
|
||||
boxShadow: `inset 0px 0px 0px 2px ${mode(
|
||||
accent400,
|
||||
accent500
|
||||
)(colorMode)}`,
|
||||
borderRadius: 'var(--invokeai-radii-base)',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -12,15 +12,25 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => {
|
||||
const { nodeId, template } = props;
|
||||
return (
|
||||
<Flex
|
||||
borderTopRadius="md"
|
||||
justifyContent="space-between"
|
||||
background="base.700"
|
||||
px={2}
|
||||
py={1}
|
||||
alignItems="center"
|
||||
sx={{
|
||||
borderTopRadius: 'md',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
px: 2,
|
||||
py: 1,
|
||||
bg: 'base.300',
|
||||
_dark: { bg: 'base.700' },
|
||||
}}
|
||||
>
|
||||
<Tooltip label={nodeId}>
|
||||
<Heading size="xs" fontWeight={600} color="base.100">
|
||||
<Heading
|
||||
size="xs"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
color: 'base.900',
|
||||
_dark: { color: 'base.100' },
|
||||
}}
|
||||
>
|
||||
{template.title}
|
||||
</Heading>
|
||||
</Tooltip>
|
||||
@ -30,7 +40,16 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => {
|
||||
hasArrow
|
||||
shouldWrapChildren
|
||||
>
|
||||
<Icon color="base.300" as={FaInfoCircle} h="min-content" />
|
||||
<Icon
|
||||
sx={{
|
||||
h: 'min-content',
|
||||
color: 'base.700',
|
||||
_dark: {
|
||||
color: 'base.300',
|
||||
},
|
||||
}}
|
||||
as={FaInfoCircle}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
);
|
||||
|
@ -72,7 +72,14 @@ export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
|
||||
return (
|
||||
<InvocationComponentWrapper selected={selected}>
|
||||
<Flex sx={{ alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Icon color="base.400" boxSize={32} as={FaExclamationCircle}></Icon>
|
||||
<Icon
|
||||
as={FaExclamationCircle}
|
||||
sx={{
|
||||
boxSize: 32,
|
||||
color: 'base.600',
|
||||
_dark: { color: 'base.400' },
|
||||
}}
|
||||
></Icon>
|
||||
<IAINodeResizer />
|
||||
</Flex>
|
||||
</InvocationComponentWrapper>
|
||||
@ -86,8 +93,9 @@ export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
|
||||
sx={{
|
||||
flexDirection: 'column',
|
||||
borderBottomRadius: 'md',
|
||||
bg: 'base.800',
|
||||
py: 2,
|
||||
bg: 'base.200',
|
||||
_dark: { bg: 'base.800' },
|
||||
}}
|
||||
>
|
||||
<IAINodeOutputs nodeId={nodeId} outputs={outputs} template={template} />
|
||||
|
@ -8,12 +8,12 @@ import { memo } from 'react';
|
||||
const NodeEditor = () => {
|
||||
return (
|
||||
<Box
|
||||
layerStyle={'first'}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
width: 'full',
|
||||
height: 'full',
|
||||
borderRadius: 'md',
|
||||
bg: 'base.850',
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
<ReactFlowProvider>
|
||||
|
@ -11,17 +11,20 @@ const NodeGraphOverlay = () => {
|
||||
return (
|
||||
<Box
|
||||
as="pre"
|
||||
fontFamily="monospace"
|
||||
position="absolute"
|
||||
top={2}
|
||||
right={2}
|
||||
opacity={0.7}
|
||||
background="base.800"
|
||||
p={2}
|
||||
maxHeight={500}
|
||||
maxWidth={500}
|
||||
overflowY="scroll"
|
||||
borderRadius="md"
|
||||
sx={{
|
||||
fontFamily: 'monospace',
|
||||
position: 'absolute',
|
||||
top: 2,
|
||||
right: 2,
|
||||
opacity: 0.7,
|
||||
p: 2,
|
||||
maxHeight: 500,
|
||||
maxWidth: 500,
|
||||
overflowY: 'scroll',
|
||||
borderRadius: 'base',
|
||||
bg: 'base.200',
|
||||
_dark: { bg: 'base.800' },
|
||||
}}
|
||||
>
|
||||
{JSON.stringify(graph, null, 2)}
|
||||
</Box>
|
||||
|
@ -1,15 +1,25 @@
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { CSSProperties, memo } from 'react';
|
||||
import { useColorModeValue } from '@chakra-ui/react';
|
||||
import { memo } from 'react';
|
||||
import { MiniMap } from 'reactflow';
|
||||
|
||||
const MinimapStyle: CSSProperties = {
|
||||
background: 'var(--invokeai-colors-base-500)',
|
||||
};
|
||||
|
||||
const MinimapPanel = () => {
|
||||
const currentTheme = useAppSelector(
|
||||
(state: RootState) => state.ui.currentTheme
|
||||
const miniMapStyle = useColorModeValue(
|
||||
{
|
||||
background: 'var(--invokeai-colors-base-200)',
|
||||
},
|
||||
{
|
||||
background: 'var(--invokeai-colors-base-500)',
|
||||
}
|
||||
);
|
||||
|
||||
const nodeColor = useColorModeValue(
|
||||
'var(--invokeai-colors-accent-300)',
|
||||
'var(--invokeai-colors-accent-700)'
|
||||
);
|
||||
|
||||
const maskColor = useColorModeValue(
|
||||
'var(--invokeai-colors-blackAlpha-300)',
|
||||
'var(--invokeai-colors-blackAlpha-600)'
|
||||
);
|
||||
|
||||
return (
|
||||
@ -18,15 +28,9 @@ const MinimapPanel = () => {
|
||||
pannable
|
||||
zoomable
|
||||
nodeBorderRadius={30}
|
||||
style={MinimapStyle}
|
||||
nodeColor={
|
||||
currentTheme === 'light'
|
||||
? 'var(--invokeai-colors-accent-700)'
|
||||
: currentTheme === 'green'
|
||||
? 'var(--invokeai-colors-accent-600)'
|
||||
: 'var(--invokeai-colors-accent-700)'
|
||||
}
|
||||
maskColor="var(--invokeai-colors-base-700)"
|
||||
style={miniMapStyle}
|
||||
nodeColor={nodeColor}
|
||||
maskColor={maskColor}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -4,17 +4,17 @@ import InitialImagePreview from './InitialImagePreview';
|
||||
const InitialImageDisplay = () => {
|
||||
return (
|
||||
<Flex
|
||||
layerStyle={'first'}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
rowGap: 4,
|
||||
borderRadius: 'base',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bg: 'base.850',
|
||||
p: 4,
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
|
@ -1,33 +1,32 @@
|
||||
import {
|
||||
ButtonGroup,
|
||||
ButtonProps,
|
||||
ButtonSpinner,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItemOption,
|
||||
MenuList,
|
||||
MenuOptionGroup,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIIconButton, {
|
||||
IAIIconButtonProps,
|
||||
} from 'common/components/IAIIconButton';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import {
|
||||
CancelStrategy,
|
||||
SystemState,
|
||||
cancelScheduled,
|
||||
cancelTypeChanged,
|
||||
CancelStrategy,
|
||||
} from 'features/system/store/systemSlice';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { useCallback, memo, useMemo } from 'react';
|
||||
import {
|
||||
ButtonSpinner,
|
||||
ButtonGroup,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
MenuOptionGroup,
|
||||
MenuItemOption,
|
||||
} from '@chakra-ui/react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
|
||||
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
|
||||
const cancelButtonSelector = createSelector(
|
||||
systemSelector,
|
||||
@ -55,7 +54,7 @@ interface CancelButtonProps {
|
||||
}
|
||||
|
||||
const CancelButton = (
|
||||
props: CancelButtonProps & Omit<IAIIconButtonProps, 'aria-label'>
|
||||
props: CancelButtonProps & Omit<ButtonProps, 'aria-label'>
|
||||
) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { btnGroupWidth = 'auto', ...rest } = props;
|
||||
@ -145,6 +144,7 @@ const CancelButton = (
|
||||
paddingY={0}
|
||||
colorScheme="error"
|
||||
minWidth={5}
|
||||
{...rest}
|
||||
/>
|
||||
<MenuList minWidth="240px">
|
||||
<MenuOptionGroup
|
||||
|
@ -71,7 +71,7 @@ export default function InvokeButton(props: InvokeButton) {
|
||||
flexGrow={1}
|
||||
w="100%"
|
||||
tooltip={t('parameters.invoke')}
|
||||
tooltipProps={{ placement: 'bottom' }}
|
||||
tooltipProps={{ placement: 'top' }}
|
||||
colorScheme="accent"
|
||||
id="invoke-button"
|
||||
{...rest}
|
||||
|
@ -0,0 +1,32 @@
|
||||
import { useColorMode } from '@chakra-ui/react';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaMoon, FaSun } from 'react-icons/fa';
|
||||
|
||||
const ColorModeButton = () => {
|
||||
const { colorMode, toggleColorMode } = useColorMode();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<IAIIconButton
|
||||
aria-label={
|
||||
colorMode === 'dark' ? t('common.lightMode') : t('common.darkMode')
|
||||
}
|
||||
tooltip={
|
||||
colorMode === 'dark' ? t('common.lightMode') : t('common.darkMode')
|
||||
}
|
||||
size="sm"
|
||||
icon={
|
||||
colorMode === 'dark' ? (
|
||||
<FaSun fontSize={19} />
|
||||
) : (
|
||||
<FaMoon fontSize={18} />
|
||||
)
|
||||
}
|
||||
onClick={toggleColorMode}
|
||||
variant="link"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorModeButton;
|
@ -1,5 +1,4 @@
|
||||
import {
|
||||
ChakraProps,
|
||||
Flex,
|
||||
Heading,
|
||||
Modal,
|
||||
@ -39,6 +38,7 @@ import { UIState } from 'features/ui/store/uiTypes';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import {
|
||||
ChangeEvent,
|
||||
PropsWithChildren,
|
||||
ReactElement,
|
||||
cloneElement,
|
||||
useCallback,
|
||||
@ -83,14 +83,6 @@ const selector = createSelector(
|
||||
}
|
||||
);
|
||||
|
||||
const modalSectionStyles: ChakraProps['sx'] = {
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
p: 4,
|
||||
bg: 'base.900',
|
||||
borderRadius: 'base',
|
||||
};
|
||||
|
||||
type ConfigOptions = {
|
||||
shouldShowDeveloperSettings: boolean;
|
||||
shouldShowResetWebUiText: boolean;
|
||||
@ -183,12 +175,12 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
isCentered
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent paddingInlineEnd={4}>
|
||||
<ModalContent>
|
||||
<ModalHeader>{t('common.settingsLabel')}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex sx={{ gap: 4, flexDirection: 'column' }}>
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<StyledFlex>
|
||||
<Heading size="sm">{t('settings.general')}</Heading>
|
||||
<IAISwitch
|
||||
label={t('settings.confirmOnDelete')}
|
||||
@ -197,14 +189,14 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
dispatch(setShouldConfirmOnDelete(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</StyledFlex>
|
||||
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<StyledFlex>
|
||||
<Heading size="sm">{t('settings.generation')}</Heading>
|
||||
<SettingsSchedulers />
|
||||
</Flex>
|
||||
</StyledFlex>
|
||||
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<StyledFlex>
|
||||
<Heading size="sm">{t('settings.ui')}</Heading>
|
||||
<IAISwitch
|
||||
label={t('settings.displayHelpIcons')}
|
||||
@ -245,10 +237,10 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</StyledFlex>
|
||||
|
||||
{shouldShowDeveloperSettings && (
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<StyledFlex>
|
||||
<Heading size="sm">{t('settings.developer')}</Heading>
|
||||
<IAISwitch
|
||||
label={t('settings.shouldLogToConsole')}
|
||||
@ -269,10 +261,10 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
dispatch(setEnableImageDebugging(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</StyledFlex>
|
||||
)}
|
||||
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<StyledFlex>
|
||||
<Heading size="sm">{t('settings.resetWebUI')}</Heading>
|
||||
<IAIButton colorScheme="error" onClick={handleClickResetWebUI}>
|
||||
{t('settings.resetWebUI')}
|
||||
@ -283,7 +275,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
<Text>{t('settings.resetWebUIDesc2')}</Text>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</StyledFlex>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
|
||||
@ -319,3 +311,19 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
};
|
||||
|
||||
export default SettingsModal;
|
||||
|
||||
const StyledFlex = (props: PropsWithChildren) => {
|
||||
return (
|
||||
<Flex
|
||||
layerStyle="second"
|
||||
sx={{
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
p: 4,
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -12,8 +12,8 @@ import InvokeAILogoComponent from './InvokeAILogoComponent';
|
||||
import LanguagePicker from './LanguagePicker';
|
||||
import ModelManagerModal from './ModelManager/ModelManagerModal';
|
||||
import SettingsModal from './SettingsModal/SettingsModal';
|
||||
import ThemeChanger from './ThemeChanger';
|
||||
import { useFeatureStatus } from '../hooks/useFeatureStatus';
|
||||
import ColorModeButton from './ColorModeButton';
|
||||
|
||||
const SiteHeader = () => {
|
||||
const { t } = useTranslation();
|
||||
@ -63,8 +63,6 @@ const SiteHeader = () => {
|
||||
/>
|
||||
</HotkeysModal>
|
||||
|
||||
<ThemeChanger />
|
||||
|
||||
{isLocalizationEnabled && <LanguagePicker />}
|
||||
|
||||
{isBugLinkEnabled && (
|
||||
@ -121,6 +119,8 @@ const SiteHeader = () => {
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<ColorModeButton />
|
||||
|
||||
<SettingsModal>
|
||||
<IAIIconButton
|
||||
aria-label={t('common.settingsLabel')}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Flex, Link } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaCube, FaKeyboard, FaBug, FaGithub, FaDiscord } from 'react-icons/fa';
|
||||
import { FaBug, FaCube, FaDiscord, FaGithub, FaKeyboard } from 'react-icons/fa';
|
||||
import { MdSettings } from 'react-icons/md';
|
||||
import HotkeysModal from './HotkeysModal/HotkeysModal';
|
||||
import LanguagePicker from './LanguagePicker';
|
||||
import ModelManagerModal from './ModelManager/ModelManagerModal';
|
||||
import SettingsModal from './SettingsModal/SettingsModal';
|
||||
import ThemeChanger from './ThemeChanger';
|
||||
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { useFeatureStatus } from '../hooks/useFeatureStatus';
|
||||
|
||||
@ -53,8 +53,6 @@ const SiteHeaderMenu = () => {
|
||||
/>
|
||||
</HotkeysModal>
|
||||
|
||||
<ThemeChanger />
|
||||
|
||||
{isLocalizationEnabled && <LanguagePicker />}
|
||||
|
||||
{isBugLinkEnabled && (
|
||||
|
@ -35,6 +35,18 @@ const statusIndicatorSelector = createSelector(
|
||||
defaultSelectorOptions
|
||||
);
|
||||
|
||||
const DARK_COLOR_MAP = {
|
||||
ok: 'green.400',
|
||||
working: 'yellow.400',
|
||||
error: 'red.400',
|
||||
};
|
||||
|
||||
const LIGHT_COLOR_MAP = {
|
||||
ok: 'green.600',
|
||||
working: 'yellow.500',
|
||||
error: 'red.500',
|
||||
};
|
||||
|
||||
const StatusIndicator = () => {
|
||||
const {
|
||||
isConnected,
|
||||
@ -46,7 +58,7 @@ const StatusIndicator = () => {
|
||||
const { t } = useTranslation();
|
||||
const ref = useRef(null);
|
||||
|
||||
const statusColorScheme = useMemo(() => {
|
||||
const statusString = useMemo(() => {
|
||||
if (isProcessing) {
|
||||
return 'working';
|
||||
}
|
||||
@ -90,9 +102,10 @@ const StatusIndicator = () => {
|
||||
sx={{
|
||||
fontSize: 'sm',
|
||||
fontWeight: '600',
|
||||
color: `${statusColorScheme}.400`,
|
||||
pb: '1px',
|
||||
userSelect: 'none',
|
||||
color: LIGHT_COLOR_MAP[statusString],
|
||||
_dark: { color: DARK_COLOR_MAP[statusString] },
|
||||
}}
|
||||
>
|
||||
{t(statusTranslationKey as ResourceKey)}
|
||||
@ -101,7 +114,14 @@ const StatusIndicator = () => {
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<Icon as={FaCircle} boxSize="0.5rem" color={`${statusColorScheme}.400`} />
|
||||
<Icon
|
||||
as={FaCircle}
|
||||
sx={{
|
||||
boxSize: '0.5rem',
|
||||
color: LIGHT_COLOR_MAP[statusString],
|
||||
_dark: { color: DARK_COLOR_MAP[statusString] },
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -1,60 +0,0 @@
|
||||
import {
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItemOption,
|
||||
MenuList,
|
||||
MenuOptionGroup,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setCurrentTheme } from 'features/ui/store/uiSlice';
|
||||
import i18n from 'i18n';
|
||||
import { map } from 'lodash-es';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaPalette } from 'react-icons/fa';
|
||||
|
||||
export const THEMES = {
|
||||
dark: i18n.t('common.darkTheme'),
|
||||
light: i18n.t('common.lightTheme'),
|
||||
green: i18n.t('common.greenTheme'),
|
||||
ocean: i18n.t('common.oceanTheme'),
|
||||
};
|
||||
|
||||
export default function ThemeChanger() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const currentTheme = useAppSelector(
|
||||
(state: RootState) => state.ui.currentTheme
|
||||
);
|
||||
|
||||
return (
|
||||
<Menu closeOnSelect={false}>
|
||||
<Tooltip label={t('common.themeLabel')} hasArrow>
|
||||
<MenuButton
|
||||
as={IconButton}
|
||||
icon={<FaPalette />}
|
||||
variant="link"
|
||||
aria-label={t('common.themeLabel')}
|
||||
fontSize={20}
|
||||
minWidth={8}
|
||||
/>
|
||||
</Tooltip>
|
||||
<MenuList>
|
||||
<MenuOptionGroup value={currentTheme}>
|
||||
{map(THEMES, (themeName, themeKey: keyof typeof THEMES) => (
|
||||
<MenuItemOption
|
||||
key={themeKey}
|
||||
value={themeKey}
|
||||
onClick={() => dispatch(setCurrentTheme(themeKey))}
|
||||
>
|
||||
{themeName}
|
||||
</MenuItemOption>
|
||||
))}
|
||||
</MenuOptionGroup>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
);
|
||||
}
|
@ -51,6 +51,7 @@ const FloatingGalleryButton = () => {
|
||||
w: 8,
|
||||
borderStartEndRadius: 0,
|
||||
borderEndEndRadius: 0,
|
||||
shadow: '2xl',
|
||||
}}
|
||||
>
|
||||
<MdPhotoLibrary />
|
||||
|
@ -19,6 +19,7 @@ import { FaSlidersH } from 'react-icons/fa';
|
||||
const floatingButtonStyles: ChakraProps['sx'] = {
|
||||
borderStartStartRadius: 0,
|
||||
borderEndStartRadius: 0,
|
||||
shadow: '2xl',
|
||||
};
|
||||
|
||||
export const floatingParametersPanelButtonSelector = createSelector(
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
useOutsideClick,
|
||||
useTheme,
|
||||
SlideDirection,
|
||||
useColorMode,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
Resizable,
|
||||
@ -21,6 +22,7 @@ import {
|
||||
getSlideDirection,
|
||||
getStyles,
|
||||
} from './util';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
type ResizableDrawerProps = ResizableProps & {
|
||||
children: ReactNode;
|
||||
@ -64,7 +66,7 @@ const ResizableDrawer = ({
|
||||
sx = {},
|
||||
}: ResizableDrawerProps) => {
|
||||
const langDirection = useTheme().direction as LangDirection;
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
const outsideClickRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const defaultWidth = useMemo(
|
||||
@ -160,11 +162,11 @@ const ResizableDrawer = ({
|
||||
handleStyles={handleStyles}
|
||||
{...minMaxDimensions}
|
||||
sx={{
|
||||
borderColor: 'base.800',
|
||||
borderColor: mode('base.200', 'base.800')(colorMode),
|
||||
p: 4,
|
||||
bg: 'base.900',
|
||||
bg: mode('base.100', 'base.900')(colorMode),
|
||||
height: 'full',
|
||||
boxShadow: '0 0 4rem 0 rgba(0, 0, 0, 0.8)',
|
||||
shadow: isOpen ? 'dark-lg' : undefined,
|
||||
...containerStyles,
|
||||
...sx,
|
||||
}}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Box, Flex, FlexProps } from '@chakra-ui/react';
|
||||
import { Box, Flex, FlexProps, useColorMode } from '@chakra-ui/react';
|
||||
import { memo } from 'react';
|
||||
import { PanelResizeHandle } from 'react-resizable-panels';
|
||||
import { mode } from 'theme/util/mode';
|
||||
|
||||
type ResizeHandleProps = FlexProps & {
|
||||
direction?: 'horizontal' | 'vertical';
|
||||
@ -8,6 +9,7 @@ type ResizeHandleProps = FlexProps & {
|
||||
|
||||
const ResizeHandle = (props: ResizeHandleProps) => {
|
||||
const { direction = 'horizontal', ...rest } = props;
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
if (direction === 'horizontal') {
|
||||
return (
|
||||
@ -21,7 +23,13 @@ const ResizeHandle = (props: ResizeHandleProps) => {
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<Box sx={{ w: 0.5, h: 'calc(100% - 4px)', bg: 'base.850' }} />
|
||||
<Box
|
||||
sx={{
|
||||
w: 0.5,
|
||||
h: 'calc(100% - 4px)',
|
||||
bg: mode('base.100', 'base.850')(colorMode),
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</PanelResizeHandle>
|
||||
);
|
||||
@ -38,7 +46,13 @@ const ResizeHandle = (props: ResizeHandleProps) => {
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<Box sx={{ w: 'calc(100% - 4px)', h: 0.5, bg: 'base.850' }} />
|
||||
<Box
|
||||
sx={{
|
||||
w: 'calc(100% - 4px)',
|
||||
h: 0.5,
|
||||
bg: mode('base.100', 'base.850')(colorMode),
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
</PanelResizeHandle>
|
||||
);
|
||||
|
@ -4,13 +4,13 @@ import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay
|
||||
const TextToImageTabMain = () => {
|
||||
return (
|
||||
<Box
|
||||
layerStyle={'first'}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: 'base',
|
||||
bg: 'base.850',
|
||||
p: 4,
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
|
@ -67,14 +67,14 @@ const UnifiedCanvasContent = () => {
|
||||
if (shouldUseCanvasBetaLayout) {
|
||||
return (
|
||||
<Box
|
||||
layerStyle="first"
|
||||
ref={setDroppableRef}
|
||||
tabIndex={0}
|
||||
sx={{
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
borderRadius: 'base',
|
||||
bg: 'base.850',
|
||||
p: 4,
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
@ -110,11 +110,11 @@ const UnifiedCanvasContent = () => {
|
||||
ref={setDroppableRef}
|
||||
tabIndex={-1}
|
||||
sx={{
|
||||
layerStyle: 'first',
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
borderRadius: 'base',
|
||||
bg: 'base.850',
|
||||
p: 4,
|
||||
borderRadius: 'base',
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
|
@ -8,7 +8,6 @@ import { SchedulerParam } from 'features/parameters/store/parameterZodSchemas';
|
||||
|
||||
export const initialUIState: UIState = {
|
||||
activeTab: 0,
|
||||
currentTheme: 'dark',
|
||||
shouldPinParametersPanel: true,
|
||||
shouldShowParametersPanel: true,
|
||||
shouldShowImageDetails: false,
|
||||
@ -30,9 +29,6 @@ export const uiSlice = createSlice({
|
||||
setActiveTab: (state, action: PayloadAction<number | InvokeTabName>) => {
|
||||
setActiveTabReducer(state, action.payload);
|
||||
},
|
||||
setCurrentTheme: (state, action: PayloadAction<string>) => {
|
||||
state.currentTheme = action.payload;
|
||||
},
|
||||
setShouldPinParametersPanel: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldPinParametersPanel = action.payload;
|
||||
state.shouldShowParametersPanel = true;
|
||||
@ -110,7 +106,6 @@ export const uiSlice = createSlice({
|
||||
|
||||
export const {
|
||||
setActiveTab,
|
||||
setCurrentTheme,
|
||||
setShouldPinParametersPanel,
|
||||
setShouldShowParametersPanel,
|
||||
setShouldShowImageDetails,
|
||||
|
@ -16,7 +16,6 @@ export type Rect = Coordinates & Dimensions;
|
||||
|
||||
export interface UIState {
|
||||
activeTab: number;
|
||||
currentTheme: string;
|
||||
shouldPinParametersPanel: boolean;
|
||||
shouldShowParametersPanel: boolean;
|
||||
shouldShowImageDetails: boolean;
|
||||
|
@ -1,9 +1,8 @@
|
||||
export { default as InvokeAiLogoComponent } from './features/system/components/InvokeAILogoComponent';
|
||||
export { default as ThemeChanger } from './features/system/components/ThemeChanger';
|
||||
export { default as IAIPopover } from './common/components/IAIPopover';
|
||||
export { default as IAIIconButton } from './common/components/IAIIconButton';
|
||||
export { default as SettingsModal } from './features/system/components/SettingsModal/SettingsModal';
|
||||
export { default as StatusIndicator } from './features/system/components/StatusIndicator';
|
||||
export { default as ModelSelect } from './features/system/components/ModelSelect';
|
||||
export { default as InvokeAIUI } from './app/components/InvokeAIUI';
|
||||
export type { PartialAppConfig } from './app/types/invokeai';
|
||||
export { default as IAIIconButton } from './common/components/IAIIconButton';
|
||||
export { default as IAIPopover } from './common/components/IAIPopover';
|
||||
export { default as InvokeAiLogoComponent } from './features/system/components/InvokeAILogoComponent';
|
||||
export { default as ModelSelect } from './features/system/components/ModelSelect';
|
||||
export { default as SettingsModal } from './features/system/components/SettingsModal/SettingsModal';
|
||||
export { default as StatusIndicator } from './features/system/components/StatusIndicator';
|
||||
|
24
invokeai/frontend/web/src/theme/colors/colors.ts
Normal file
24
invokeai/frontend/web/src/theme/colors/colors.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { InvokeAIThemeColors } from 'theme/themeTypes';
|
||||
import { generateColorPalette } from 'theme/util/generateColorPalette';
|
||||
|
||||
const BASE = { H: 220, S: 16 };
|
||||
const ACCENT = { H: 250, S: 52 };
|
||||
const WORKING = { H: 47, S: 50 };
|
||||
const WARNING = { H: 28, S: 50 };
|
||||
const OK = { H: 113, S: 50 };
|
||||
const ERROR = { H: 0, S: 50 };
|
||||
|
||||
export const InvokeAIColors: InvokeAIThemeColors = {
|
||||
base: generateColorPalette(BASE.H, BASE.S),
|
||||
baseAlpha: generateColorPalette(BASE.H, BASE.S, true),
|
||||
accent: generateColorPalette(ACCENT.H, ACCENT.S),
|
||||
accentAlpha: generateColorPalette(ACCENT.H, ACCENT.S, true),
|
||||
working: generateColorPalette(WORKING.H, WORKING.S),
|
||||
workingAlpha: generateColorPalette(WORKING.H, WORKING.S, true),
|
||||
warning: generateColorPalette(WARNING.H, WARNING.S),
|
||||
warningAlpha: generateColorPalette(WARNING.H, WARNING.S, true),
|
||||
ok: generateColorPalette(OK.H, OK.S),
|
||||
okAlpha: generateColorPalette(OK.H, OK.S, true),
|
||||
error: generateColorPalette(ERROR.H, ERROR.S),
|
||||
errorAlpha: generateColorPalette(ERROR.H, ERROR.S, true),
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import { InvokeAIThemeColors } from 'theme/themeTypes';
|
||||
import { generateColorPalette } from '../util/generateColorPalette';
|
||||
|
||||
export const greenTeaThemeColors: InvokeAIThemeColors = {
|
||||
base: generateColorPalette(223, 10),
|
||||
baseAlpha: generateColorPalette(223, 10, false, true),
|
||||
accent: generateColorPalette(160, 60),
|
||||
accentAlpha: generateColorPalette(160, 60, false, true),
|
||||
working: generateColorPalette(47, 68),
|
||||
workingAlpha: generateColorPalette(47, 68, false, true),
|
||||
warning: generateColorPalette(28, 75),
|
||||
warningAlpha: generateColorPalette(28, 75, false, true),
|
||||
ok: generateColorPalette(122, 49),
|
||||
okAlpha: generateColorPalette(122, 49, false, true),
|
||||
error: generateColorPalette(0, 50),
|
||||
errorAlpha: generateColorPalette(0, 50, false, true),
|
||||
gridLineColor: 'rgba(255, 255, 255, 0.15)',
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import { InvokeAIThemeColors } from 'theme/themeTypes';
|
||||
import { generateColorPalette } from 'theme/util/generateColorPalette';
|
||||
|
||||
export const invokeAIThemeColors: InvokeAIThemeColors = {
|
||||
base: generateColorPalette(220, 15),
|
||||
baseAlpha: generateColorPalette(220, 15, false, true),
|
||||
accent: generateColorPalette(250, 50),
|
||||
accentAlpha: generateColorPalette(250, 50, false, true),
|
||||
working: generateColorPalette(47, 67),
|
||||
workingAlpha: generateColorPalette(47, 67, false, true),
|
||||
warning: generateColorPalette(28, 75),
|
||||
warningAlpha: generateColorPalette(28, 75, false, true),
|
||||
ok: generateColorPalette(113, 70),
|
||||
okAlpha: generateColorPalette(113, 70, false, true),
|
||||
error: generateColorPalette(0, 76),
|
||||
errorAlpha: generateColorPalette(0, 76, false, true),
|
||||
gridLineColor: 'rgba(150, 150, 180, 0.15)',
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import { InvokeAIThemeColors } from 'theme/themeTypes';
|
||||
import { generateColorPalette } from '../util/generateColorPalette';
|
||||
|
||||
export const lightThemeColors: InvokeAIThemeColors = {
|
||||
base: generateColorPalette(223, 10, true),
|
||||
baseAlpha: generateColorPalette(223, 10, true, true),
|
||||
accent: generateColorPalette(40, 80, true),
|
||||
accentAlpha: generateColorPalette(40, 80, true, true),
|
||||
working: generateColorPalette(47, 68, true),
|
||||
workingAlpha: generateColorPalette(47, 68, true, true),
|
||||
warning: generateColorPalette(28, 75, true),
|
||||
warningAlpha: generateColorPalette(28, 75, true, true),
|
||||
ok: generateColorPalette(122, 49, true),
|
||||
okAlpha: generateColorPalette(122, 49, true, true),
|
||||
error: generateColorPalette(0, 50, true),
|
||||
errorAlpha: generateColorPalette(0, 50, true, true),
|
||||
gridLineColor: 'rgba(0, 0, 0, 0.15)',
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import { InvokeAIThemeColors } from 'theme/themeTypes';
|
||||
import { generateColorPalette } from '../util/generateColorPalette';
|
||||
|
||||
export const oceanBlueColors: InvokeAIThemeColors = {
|
||||
base: generateColorPalette(220, 30),
|
||||
baseAlpha: generateColorPalette(220, 30, false, true),
|
||||
accent: generateColorPalette(210, 80),
|
||||
accentAlpha: generateColorPalette(210, 80, false, true),
|
||||
working: generateColorPalette(47, 68),
|
||||
workingAlpha: generateColorPalette(47, 68, false, true),
|
||||
warning: generateColorPalette(28, 75),
|
||||
warningAlpha: generateColorPalette(28, 75, false, true),
|
||||
ok: generateColorPalette(122, 49),
|
||||
okAlpha: generateColorPalette(122, 49, false, true),
|
||||
error: generateColorPalette(0, 100),
|
||||
errorAlpha: generateColorPalette(0, 100, false, true),
|
||||
gridLineColor: 'rgba(136, 148, 184, 0.15)',
|
||||
};
|
@ -3,6 +3,7 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { definePartsStyle, defineMultiStyleConfig } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
@ -18,16 +19,16 @@ const invokeAIButton = defineStyle((props) => {
|
||||
fontSize: 'sm',
|
||||
border: 'none',
|
||||
borderRadius: 'base',
|
||||
bg: `${c}.800`,
|
||||
color: 'base.100',
|
||||
bg: mode(`${c}.200`, `${c}.700`)(props),
|
||||
color: mode(`${c}.900`, `${c}.100`)(props),
|
||||
_hover: {
|
||||
bg: `${c}.700`,
|
||||
bg: mode(`${c}.250`, `${c}.650`)(props),
|
||||
},
|
||||
_expanded: {
|
||||
bg: `${c}.750`,
|
||||
bg: mode(`${c}.250`, `${c}.650`)(props),
|
||||
borderBottomRadius: 'none',
|
||||
_hover: {
|
||||
bg: `${c}.700`,
|
||||
bg: mode(`${c}.300`, `${c}.600`)(props),
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -36,7 +37,7 @@ const invokeAIButton = defineStyle((props) => {
|
||||
const invokeAIPanel = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
return {
|
||||
bg: `${c}.800`,
|
||||
bg: mode(`${c}.100`, `${c}.800`)(props),
|
||||
borderRadius: 'base',
|
||||
borderTopRadius: 'none',
|
||||
};
|
||||
|
@ -1,44 +1,55 @@
|
||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const invokeAI = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
// must specify `_disabled` colors if we override `_hover`, else hover on disabled has no styles
|
||||
const _disabled = {
|
||||
bg: `${c}.600`,
|
||||
color: `${c}.100`,
|
||||
bg: mode(`${c}.350`, `${c}.700`)(props),
|
||||
color: mode(`${c}.750`, `${c}.150`)(props),
|
||||
svg: {
|
||||
fill: `${c}.100`,
|
||||
fill: mode(`${c}.750`, `${c}.150`)(props),
|
||||
},
|
||||
opacity: 1,
|
||||
filter: 'saturate(65%)',
|
||||
};
|
||||
|
||||
return {
|
||||
bg: `${c}.700`,
|
||||
color: `${c}.100`,
|
||||
bg: mode(`${c}.200`, `${c}.600`)(props),
|
||||
color: mode(`${c}.850`, `${c}.100`)(props),
|
||||
borderRadius: 'base',
|
||||
textShadow: mode(
|
||||
`0 0 0.3rem var(--invokeai-colors-${c}-50)`,
|
||||
`0 0 0.3rem var(--invokeai-colors-${c}-900)`
|
||||
)(props),
|
||||
svg: {
|
||||
fill: `${c}.100`,
|
||||
fill: mode(`${c}.850`, `${c}.100`)(props),
|
||||
filter: mode(
|
||||
`drop-shadow(0px 0px 0.3rem var(--invokeai-colors-${c}-100))`,
|
||||
`drop-shadow(0px 0px 0.3rem var(--invokeai-colors-${c}-800))`
|
||||
)(props),
|
||||
},
|
||||
_disabled,
|
||||
_hover: {
|
||||
bg: `${c}.650`,
|
||||
color: `${c}.50`,
|
||||
bg: mode(`${c}.300`, `${c}.500`)(props),
|
||||
color: mode(`${c}.900`, `${c}.50`)(props),
|
||||
svg: {
|
||||
fill: `${c}.50`,
|
||||
fill: mode(`${c}.900`, `${c}.50`)(props),
|
||||
},
|
||||
_disabled,
|
||||
},
|
||||
_checked: {
|
||||
bg: 'accent.700',
|
||||
color: 'accent.100',
|
||||
bg: mode('accent.200', 'accent.600')(props),
|
||||
color: mode('accent.800', 'accent.100')(props),
|
||||
svg: {
|
||||
fill: 'accent.100',
|
||||
fill: mode('accent.800', 'accent.100')(props),
|
||||
},
|
||||
_disabled,
|
||||
_hover: {
|
||||
bg: 'accent.600',
|
||||
color: 'accent.50',
|
||||
bg: mode('accent.300', 'accent.500')(props),
|
||||
color: mode('accent.900', 'accent.50')(props),
|
||||
svg: {
|
||||
fill: 'accent.50',
|
||||
fill: mode('accent.900', 'accent.50')(props),
|
||||
},
|
||||
_disabled,
|
||||
},
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { definePartsStyle, defineMultiStyleConfig } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
@ -11,14 +12,18 @@ const invokeAIControl = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
|
||||
return {
|
||||
bg: mode('base.200', 'base.700')(props),
|
||||
borderColor: mode('base.200', 'base.700')(props),
|
||||
color: mode('base.900', 'base.100')(props),
|
||||
|
||||
_checked: {
|
||||
bg: `${c}.200`,
|
||||
borderColor: `${c}.200`,
|
||||
color: 'base.900',
|
||||
bg: mode(`${c}.300`, `${c}.600`)(props),
|
||||
borderColor: mode(`${c}.300`, `${c}.600`)(props),
|
||||
color: mode(`${c}.900`, `${c}.100`)(props),
|
||||
|
||||
_hover: {
|
||||
bg: `${c}.300`,
|
||||
borderColor: `${c}.300`,
|
||||
bg: mode(`${c}.400`, `${c}.500`)(props),
|
||||
borderColor: mode(`${c}.400`, `${c}.500`)(props),
|
||||
},
|
||||
|
||||
_disabled: {
|
||||
@ -29,9 +34,9 @@ const invokeAIControl = defineStyle((props) => {
|
||||
},
|
||||
|
||||
_indeterminate: {
|
||||
bg: `${c}.200`,
|
||||
borderColor: `${c}.200`,
|
||||
color: 'base.900',
|
||||
bg: mode(`${c}.300`, `${c}.600`)(props),
|
||||
borderColor: mode(`${c}.300`, `${c}.600`)(props),
|
||||
color: mode(`${c}.900`, `${c}.100`)(props),
|
||||
},
|
||||
|
||||
_disabled: {
|
||||
@ -44,7 +49,7 @@ const invokeAIControl = defineStyle((props) => {
|
||||
},
|
||||
|
||||
_invalid: {
|
||||
borderColor: 'red.300',
|
||||
borderColor: mode('error.600', 'error.300')(props),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const invokeAI = defineStyle((_props) => {
|
||||
const invokeAI = defineStyle((props) => {
|
||||
return {
|
||||
fontSize: 'sm',
|
||||
marginEnd: 0,
|
||||
@ -12,7 +13,7 @@ const invokeAI = defineStyle((_props) => {
|
||||
_disabled: {
|
||||
opacity: 0.4,
|
||||
},
|
||||
color: 'base.300',
|
||||
color: mode('base.700', 'base.300')(props),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,38 +1,40 @@
|
||||
import { menuAnatomy } from '@chakra-ui/anatomy';
|
||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { definePartsStyle, defineMultiStyleConfig } =
|
||||
createMultiStyleConfigHelpers(menuAnatomy.keys);
|
||||
|
||||
// define the base component styles
|
||||
const invokeAI = definePartsStyle({
|
||||
const invokeAI = definePartsStyle((props) => ({
|
||||
// define the part you're going to style
|
||||
button: {
|
||||
// this will style the MenuButton component
|
||||
fontWeight: '600',
|
||||
bg: 'base.500',
|
||||
color: 'base.200',
|
||||
fontWeight: 500,
|
||||
bg: mode('base.300', 'base.500')(props),
|
||||
color: mode('base.900', 'base.100')(props),
|
||||
_hover: {
|
||||
bg: 'base.600',
|
||||
color: 'white',
|
||||
bg: mode('base.400', 'base.600')(props),
|
||||
color: mode('base.900', 'base.50')(props),
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
list: {
|
||||
zIndex: 9999,
|
||||
bg: 'base.800',
|
||||
bg: mode('base.200', 'base.800')(props),
|
||||
},
|
||||
item: {
|
||||
// this will style the MenuItem and MenuItemOption components
|
||||
fontSize: 'sm',
|
||||
bg: 'base.800',
|
||||
bg: mode('base.200', 'base.800')(props),
|
||||
_hover: {
|
||||
bg: 'base.750',
|
||||
bg: mode('base.300', 'base.700')(props),
|
||||
},
|
||||
_focus: {
|
||||
bg: 'base.700',
|
||||
bg: mode('base.400', 'base.600')(props),
|
||||
},
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
export const menuTheme = defineMultiStyleConfig({
|
||||
variants: {
|
||||
|
@ -3,28 +3,31 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { defineMultiStyleConfig, definePartsStyle } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
|
||||
const invokeAIOverlay = defineStyle({
|
||||
bg: 'blackAlpha.600',
|
||||
});
|
||||
const invokeAIOverlay = defineStyle((props) => ({
|
||||
bg: mode('blackAlpha.700', 'blackAlpha.700')(props),
|
||||
}));
|
||||
|
||||
const invokeAIDialogContainer = defineStyle({});
|
||||
|
||||
const invokeAIDialog = defineStyle((_props) => {
|
||||
const invokeAIDialog = defineStyle((props) => {
|
||||
return {
|
||||
bg: 'base.850',
|
||||
layerStyle: 'first',
|
||||
maxH: '80vh',
|
||||
};
|
||||
});
|
||||
|
||||
const invokeAIHeader = defineStyle((_props) => {
|
||||
const invokeAIHeader = defineStyle((props) => {
|
||||
return {
|
||||
fontWeight: '600',
|
||||
fontSize: 'lg',
|
||||
color: 'base.200',
|
||||
layerStyle: 'first',
|
||||
borderTopRadius: 'base',
|
||||
borderInlineEndRadius: 'base',
|
||||
};
|
||||
});
|
||||
|
||||
@ -37,7 +40,7 @@ const invokeAIBody = defineStyle({
|
||||
const invokeAIFooter = defineStyle({});
|
||||
|
||||
export const invokeAI = definePartsStyle((props) => ({
|
||||
overlay: invokeAIOverlay,
|
||||
overlay: invokeAIOverlay(props),
|
||||
dialogContainer: invokeAIDialogContainer,
|
||||
dialog: invokeAIDialog(props),
|
||||
header: invokeAIHeader(props),
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
} from '@chakra-ui/styled-system';
|
||||
|
||||
import { getInputOutlineStyles } from '../util/getInputOutlineStyles';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { defineMultiStyleConfig, definePartsStyle } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
@ -33,7 +34,7 @@ const invokeAIStepperGroup = defineStyle((_props) => {
|
||||
};
|
||||
});
|
||||
|
||||
const invokeAIStepper = defineStyle((_props) => {
|
||||
const invokeAIStepper = defineStyle((props) => {
|
||||
return {
|
||||
border: 'none',
|
||||
// expand arrow hitbox
|
||||
@ -43,11 +44,11 @@ const invokeAIStepper = defineStyle((_props) => {
|
||||
my: 0,
|
||||
|
||||
svg: {
|
||||
color: 'base.300',
|
||||
color: mode('base.700', 'base.300')(props),
|
||||
width: 2.5,
|
||||
height: 2.5,
|
||||
_hover: {
|
||||
color: 'base.50',
|
||||
color: mode('base.900', 'base.100')(props),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { cssVar } from '@chakra-ui/theme-tools';
|
||||
import { cssVar, mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { defineMultiStyleConfig, definePartsStyle } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
@ -12,15 +12,20 @@ const $popperBg = cssVar('popper-bg');
|
||||
const $arrowBg = cssVar('popper-arrow-bg');
|
||||
const $arrowShadowColor = cssVar('popper-arrow-shadow-color');
|
||||
|
||||
const invokeAIContent = defineStyle((_props) => {
|
||||
const invokeAIContent = defineStyle((props) => {
|
||||
return {
|
||||
[$arrowBg.variable]: `colors.base.800`,
|
||||
[$popperBg.variable]: `colors.base.800`,
|
||||
[$arrowShadowColor.variable]: `colors.base.600`,
|
||||
[$arrowBg.variable]: mode('colors.base.100', 'colors.base.800')(props),
|
||||
[$popperBg.variable]: mode('colors.base.100', 'colors.base.800')(props),
|
||||
[$arrowShadowColor.variable]: mode(
|
||||
'colors.base.400',
|
||||
'colors.base.600'
|
||||
)(props),
|
||||
minW: 'unset',
|
||||
width: 'unset',
|
||||
p: 4,
|
||||
bg: 'base.800',
|
||||
bg: mode('base.100', 'base.800')(props),
|
||||
border: 'none',
|
||||
shadow: 'dark-lg',
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { selectAnatomy as parts } from '@chakra-ui/anatomy';
|
||||
import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react';
|
||||
import { getInputOutlineStyles } from '../util/getInputOutlineStyles';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { definePartsStyle, defineMultiStyleConfig } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
|
||||
const invokeAIIcon = defineStyle((_props) => {
|
||||
const invokeAIIcon = defineStyle((props) => {
|
||||
return {
|
||||
color: 'base.300',
|
||||
color: mode('base.200', 'base.300')(props),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { sliderAnatomy as parts } from '@chakra-ui/anatomy';
|
||||
import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { definePartsStyle, defineMultiStyleConfig } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
|
||||
const invokeAITrack = defineStyle((_props) => {
|
||||
const invokeAITrack = defineStyle((props) => {
|
||||
return {
|
||||
bg: 'base.400',
|
||||
bg: mode('base.400', 'base.600')(props),
|
||||
h: 1.5,
|
||||
};
|
||||
});
|
||||
@ -14,23 +15,24 @@ const invokeAITrack = defineStyle((_props) => {
|
||||
const invokeAIFilledTrack = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
return {
|
||||
bg: `${c}.600`,
|
||||
bg: mode(`${c}.400`, `${c}.600`)(props),
|
||||
h: 1.5,
|
||||
};
|
||||
});
|
||||
|
||||
const invokeAIThumb = defineStyle((_props) => {
|
||||
const invokeAIThumb = defineStyle((props) => {
|
||||
return {
|
||||
w: 2,
|
||||
h: 4,
|
||||
bg: mode('base.50', 'base.100')(props),
|
||||
};
|
||||
});
|
||||
|
||||
const invokeAIMark = defineStyle((_props) => {
|
||||
const invokeAIMark = defineStyle((props) => {
|
||||
return {
|
||||
fontSize: 'xs',
|
||||
fontWeight: '500',
|
||||
color: 'base.400',
|
||||
color: mode('base.700', 'base.400')(props),
|
||||
mt: 2,
|
||||
insetInlineStart: 'unset',
|
||||
};
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { defineMultiStyleConfig, definePartsStyle } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
@ -11,13 +12,13 @@ const invokeAITrack = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
|
||||
return {
|
||||
bg: 'base.600',
|
||||
bg: mode('base.300', 'base.600')(props),
|
||||
|
||||
_focusVisible: {
|
||||
boxShadow: 'none',
|
||||
},
|
||||
_checked: {
|
||||
bg: `${c}.600`,
|
||||
bg: mode(`${c}.400`, `${c}.500`)(props),
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -26,7 +27,7 @@ const invokeAIThumb = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
|
||||
return {
|
||||
bg: `${c}.50`,
|
||||
bg: mode(`${c}.50`, `${c}.50`)(props),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const { defineMultiStyleConfig, definePartsStyle } =
|
||||
createMultiStyleConfigHelpers(parts.keys);
|
||||
@ -16,30 +17,51 @@ const invokeAIRoot = defineStyle((_props) => {
|
||||
|
||||
const invokeAITab = defineStyle((_props) => ({}));
|
||||
|
||||
const invokeAITablist = defineStyle((_props) => ({
|
||||
const invokeAITablist = defineStyle((props) => {
|
||||
const { colorScheme: c } = props;
|
||||
|
||||
return {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 1,
|
||||
color: 'base.700',
|
||||
color: mode('base.700', 'base.400')(props),
|
||||
button: {
|
||||
fontSize: 'sm',
|
||||
padding: 2,
|
||||
borderRadius: 'base',
|
||||
textShadow: mode(
|
||||
`0 0 0.3rem var(--invokeai-colors-accent-100)`,
|
||||
`0 0 0.3rem var(--invokeai-colors-accent-900)`
|
||||
)(props),
|
||||
svg: {
|
||||
fill: mode('base.700', 'base.300')(props),
|
||||
},
|
||||
_selected: {
|
||||
borderBottomColor: 'base.800',
|
||||
bg: 'accent.700',
|
||||
color: 'accent.100',
|
||||
bg: mode('accent.200', 'accent.600')(props),
|
||||
color: mode('accent.800', 'accent.100')(props),
|
||||
_hover: {
|
||||
bg: 'accent.600',
|
||||
color: 'accent.50',
|
||||
bg: mode('accent.300', 'accent.500')(props),
|
||||
color: mode('accent.900', 'accent.50')(props),
|
||||
},
|
||||
svg: {
|
||||
fill: mode('base.900', 'base.50')(props),
|
||||
filter: mode(
|
||||
`drop-shadow(0px 0px 0.3rem var(--invokeai-colors-accent-100))`,
|
||||
`drop-shadow(0px 0px 0.3rem var(--invokeai-colors-accent-900))`
|
||||
)(props),
|
||||
},
|
||||
},
|
||||
_hover: {
|
||||
bg: 'base.600',
|
||||
color: 'base.50',
|
||||
bg: mode('base.100', 'base.800')(props),
|
||||
color: mode('base.900', 'base.50')(props),
|
||||
svg: {
|
||||
fill: mode(`base.800`, `base.100`)(props),
|
||||
},
|
||||
},
|
||||
}));
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const invokeAITabpanel = defineStyle((_props) => ({
|
||||
padding: 0,
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
const subtext = defineStyle((_props) => ({
|
||||
color: 'base.400',
|
||||
const subtext = defineStyle((props) => ({
|
||||
color: mode('colors.base.500', 'colors.base.400')(props),
|
||||
}));
|
||||
|
||||
export const textTheme = defineStyleConfig({
|
||||
|
17
invokeai/frontend/web/src/theme/components/tooltip.ts
Normal file
17
invokeai/frontend/web/src/theme/components/tooltip.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { defineStyle, defineStyleConfig } from '@chakra-ui/react';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
import { cssVar } from '@chakra-ui/theme-tools';
|
||||
|
||||
const $arrowBg = cssVar('popper-arrow-bg');
|
||||
|
||||
// define the base component styles
|
||||
const baseStyle = defineStyle((props) => ({
|
||||
borderRadius: 'base',
|
||||
shadow: 'dark-lg',
|
||||
bg: mode('base.700', 'base.200')(props),
|
||||
[$arrowBg.variable]: mode('colors.base.700', 'colors.base.200')(props),
|
||||
pb: 1.5,
|
||||
}));
|
||||
|
||||
// export the component theme
|
||||
export const tooltipTheme = defineStyleConfig({ baseStyle });
|
@ -1,7 +1,6 @@
|
||||
import { ThemeOverride } from '@chakra-ui/react';
|
||||
import type { StyleFunctionProps } from '@chakra-ui/styled-system';
|
||||
|
||||
import { invokeAIThemeColors } from 'theme/colors/invokeAI';
|
||||
import { InvokeAIColors } from './colors/colors';
|
||||
import { accordionTheme } from './components/accordion';
|
||||
import { buttonTheme } from './components/button';
|
||||
import { checkboxTheme } from './components/checkbox';
|
||||
@ -12,13 +11,14 @@ import { modalTheme } from './components/modal';
|
||||
import { numberInputTheme } from './components/numberInput';
|
||||
import { popoverTheme } from './components/popover';
|
||||
import { progressTheme } from './components/progress';
|
||||
import { no_scrollbar, scrollbar as _scrollbar } from './components/scrollbar';
|
||||
import { no_scrollbar } from './components/scrollbar';
|
||||
import { selectTheme } from './components/select';
|
||||
import { sliderTheme } from './components/slider';
|
||||
import { switchTheme } from './components/switch';
|
||||
import { tabsTheme } from './components/tabs';
|
||||
import { textTheme } from './components/text';
|
||||
import { textareaTheme } from './components/textarea';
|
||||
import { tooltipTheme } from './components/tooltip';
|
||||
|
||||
export const theme: ThemeOverride = {
|
||||
config: {
|
||||
@ -26,16 +26,26 @@ export const theme: ThemeOverride = {
|
||||
initialColorMode: 'dark',
|
||||
useSystemColorMode: false,
|
||||
},
|
||||
styles: {
|
||||
global: (_props: StyleFunctionProps) => ({
|
||||
layerStyles: {
|
||||
body: {
|
||||
bg: 'base.900',
|
||||
color: 'base.50',
|
||||
overflow: {
|
||||
base: 'scroll',
|
||||
xl: 'hidden',
|
||||
bg: 'base.50',
|
||||
color: 'base.900',
|
||||
'.chakra-ui-dark &': { bg: 'base.900', color: 'base.50' },
|
||||
},
|
||||
first: {
|
||||
bg: 'base.100',
|
||||
color: 'base.900',
|
||||
'.chakra-ui-dark &': { bg: 'base.850', color: 'base.100' },
|
||||
},
|
||||
second: {
|
||||
bg: 'base.200',
|
||||
color: 'base.900',
|
||||
'.chakra-ui-dark &': { bg: 'base.800', color: 'base.100' },
|
||||
},
|
||||
},
|
||||
styles: {
|
||||
global: () => ({
|
||||
layerStyle: 'body',
|
||||
'*': { ...no_scrollbar },
|
||||
}),
|
||||
},
|
||||
@ -43,14 +53,6 @@ export const theme: ThemeOverride = {
|
||||
fonts: {
|
||||
body: `'Inter Variable', sans-serif`,
|
||||
},
|
||||
breakpoints: {
|
||||
base: '0em', // 0px and onwards
|
||||
sm: '30em', // 480px and onwards
|
||||
md: '48em', // 768px and onwards
|
||||
lg: '62em', // 992px and onwards
|
||||
xl: '80em', // 1280px and onwards
|
||||
'2xl': '96em', // 1536px and onwards
|
||||
},
|
||||
shadows: {
|
||||
light: {
|
||||
accent: `0 0 10px 0 var(--invokeai-colors-accent-300)`,
|
||||
@ -68,9 +70,7 @@ export const theme: ThemeOverride = {
|
||||
},
|
||||
nodeSelectedOutline: `0 0 0 2px var(--invokeai-colors-base-500)`,
|
||||
},
|
||||
colors: {
|
||||
...invokeAIThemeColors,
|
||||
},
|
||||
colors: InvokeAIColors,
|
||||
components: {
|
||||
Button: buttonTheme, // Button and IconButton
|
||||
Input: inputTheme,
|
||||
@ -88,5 +88,6 @@ export const theme: ThemeOverride = {
|
||||
Checkbox: checkboxTheme,
|
||||
Menu: menuTheme,
|
||||
Text: textTheme,
|
||||
Tooltip: tooltipTheme,
|
||||
},
|
||||
};
|
||||
|
@ -11,7 +11,6 @@ export type InvokeAIThemeColors = {
|
||||
okAlpha: Partial<InvokeAIPaletteSteps>;
|
||||
error: Partial<InvokeAIPaletteSteps>;
|
||||
errorAlpha: Partial<InvokeAIPaletteSteps>;
|
||||
gridLineColor: string;
|
||||
};
|
||||
|
||||
export type InvokeAIPaletteSteps = {
|
||||
|
@ -2,46 +2,35 @@ import { InvokeAIPaletteSteps } from 'theme/themeTypes';
|
||||
|
||||
/**
|
||||
* Add two numbers together
|
||||
* @param {String | Number} hue Hue of the color (0-360) - Reds 0, Greens 120, Blues 240
|
||||
* @param {String | Number} saturation Saturation of the color (0-100)
|
||||
* @param {boolean} light True to generate light color palette
|
||||
* @param {String | Number} H Hue of the color (0-360) - Reds 0, Greens 120, Blues 240
|
||||
* @param {String | Number} L Saturation of the color (0-100)
|
||||
* @param {Boolean} alpha Whether or not to generate this palette as a transparency palette
|
||||
*/
|
||||
export function generateColorPalette(
|
||||
hue: string | number,
|
||||
saturation: string | number,
|
||||
light = false,
|
||||
H: string | number,
|
||||
S: string | number,
|
||||
alpha = false
|
||||
) {
|
||||
hue = String(hue);
|
||||
saturation = String(saturation);
|
||||
H = String(H);
|
||||
S = String(S);
|
||||
|
||||
const colorSteps = Array.from({ length: 21 }, (_, i) => i * 50);
|
||||
|
||||
const lightnessSteps = [
|
||||
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 59, 64, 68, 73, 77, 82, 86,
|
||||
95, 100,
|
||||
];
|
||||
|
||||
const darkPalette: Partial<InvokeAIPaletteSteps> = {};
|
||||
const lightPalette: Partial<InvokeAIPaletteSteps> = {};
|
||||
|
||||
colorSteps.forEach((colorStep, index) => {
|
||||
const p = colorSteps.reduce((palette, step, index) => {
|
||||
const A = alpha ? lightnessSteps[index] / 100 : 1;
|
||||
|
||||
// Lightness should be 50% for alpha colors
|
||||
const darkPaletteLightness = alpha
|
||||
? 50
|
||||
: lightnessSteps[colorSteps.length - 1 - index];
|
||||
const L = alpha ? 50 : lightnessSteps[colorSteps.length - 1 - index];
|
||||
|
||||
darkPalette[
|
||||
colorStep as keyof typeof darkPalette
|
||||
] = `hsl(${hue} ${saturation}% ${darkPaletteLightness}% / ${A})`;
|
||||
palette[step as keyof typeof palette] = `hsl(${H} ${S}% ${L}% / ${A})`;
|
||||
|
||||
const lightPaletteLightness = alpha ? 50 : lightnessSteps[index];
|
||||
return palette;
|
||||
}, {} as InvokeAIPaletteSteps);
|
||||
|
||||
lightPalette[
|
||||
colorStep as keyof typeof lightPalette
|
||||
] = `hsl(${hue} ${saturation}% ${lightPaletteLightness}% / ${A})`;
|
||||
});
|
||||
|
||||
return light ? lightPalette : darkPalette;
|
||||
return p;
|
||||
}
|
||||
|
@ -1,40 +1,40 @@
|
||||
import { StyleFunctionProps } from '@chakra-ui/theme-tools';
|
||||
import { StyleFunctionProps, mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
export const getInputOutlineStyles = (_props?: StyleFunctionProps) => ({
|
||||
export const getInputOutlineStyles = (props: StyleFunctionProps) => ({
|
||||
outline: 'none',
|
||||
borderWidth: 2,
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'base.800',
|
||||
bg: 'base.900',
|
||||
borderColor: mode('base.200', 'base.800')(props),
|
||||
bg: mode('base.50', 'base.900')(props),
|
||||
borderRadius: 'base',
|
||||
color: 'base.100',
|
||||
color: mode('base.900', 'base.100')(props),
|
||||
boxShadow: 'none',
|
||||
_hover: {
|
||||
borderColor: 'base.600',
|
||||
borderColor: mode('base.300', 'base.600')(props),
|
||||
},
|
||||
_focus: {
|
||||
borderColor: 'accent.700',
|
||||
borderColor: mode('accent.200', 'accent.600')(props),
|
||||
boxShadow: 'none',
|
||||
_hover: {
|
||||
borderColor: 'accent.600',
|
||||
borderColor: mode('accent.300', 'accent.500')(props),
|
||||
},
|
||||
},
|
||||
_invalid: {
|
||||
borderColor: 'error.700',
|
||||
borderColor: mode('error.300', 'error.600')(props),
|
||||
boxShadow: 'none',
|
||||
_hover: {
|
||||
borderColor: 'error.600',
|
||||
borderColor: mode('error.400', 'error.500')(props),
|
||||
},
|
||||
},
|
||||
_disabled: {
|
||||
borderColor: 'base.700',
|
||||
bg: 'base.700',
|
||||
color: 'base.400',
|
||||
borderColor: mode('base.300', 'base.700')(props),
|
||||
bg: mode('base.300', 'base.700')(props),
|
||||
color: mode('base.600', 'base.400')(props),
|
||||
_hover: {
|
||||
borderColor: 'base.700',
|
||||
borderColor: mode('base.300', 'base.700')(props),
|
||||
},
|
||||
},
|
||||
_placeholder: {
|
||||
color: 'base.500',
|
||||
color: mode('base.700', 'base.400')(props),
|
||||
},
|
||||
});
|
||||
|
3
invokeai/frontend/web/src/theme/util/mode.ts
Normal file
3
invokeai/frontend/web/src/theme/util/mode.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const mode =
|
||||
(light: string, dark: string) => (colorMode: 'light' | 'dark') =>
|
||||
colorMode === 'light' ? light : dark;
|
Loading…
Reference in New Issue
Block a user