UI more pr feedback

This commit is contained in:
Mary Hipp 2024-08-12 11:59:25 -04:00
parent 41c3e73a3c
commit 1e547ef912
11 changed files with 95 additions and 96 deletions

View File

@ -1,11 +1,12 @@
import { Badge, ConfirmationAlertDialog, Flex, IconButton, Text, useDisclosure } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import {
isModalOpenChanged,
prefilledFormDataChanged,
updatingStylePresetIdChanged,
} from 'features/stylePresets/store/stylePresetModalSlice';
import { activeStylePresetIdChanged, isMenuOpenChanged } from 'features/stylePresets/store/stylePresetSlice';
import { activeStylePresetIdChanged } from 'features/stylePresets/store/stylePresetSlice';
import { toast } from 'features/toast/toast';
import type { MouseEvent } from 'react';
import { useCallback } from 'react';
@ -46,7 +47,7 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordWithI
const handleClickApply = useCallback(async () => {
dispatch(activeStylePresetIdChanged(preset.id));
dispatch(isMenuOpenChanged(false));
$isMenuOpen.set(false);
}, [dispatch, preset.id]);
const handleClickDelete = useCallback(

View File

@ -1,6 +1,6 @@
import { Flex, IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { isMenuOpenChanged } from 'features/stylePresets/store/stylePresetSlice';
import { useStore } from '@nanostores/react';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiCaretDownBold } from 'react-icons/pi';
@ -8,13 +8,12 @@ import { PiCaretDownBold } from 'react-icons/pi';
import { ActiveStylePreset } from './ActiveStylePreset';
export const StylePresetMenuTrigger = () => {
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
const dispatch = useAppDispatch();
const isMenuOpen = useStore($isMenuOpen);
const { t } = useTranslation();
const handleToggle = useCallback(() => {
dispatch(isMenuOpenChanged(!isMenuOpen));
}, [dispatch, isMenuOpen]);
$isMenuOpen.set(!isMenuOpen);
}, [isMenuOpen]);
return (
<Flex

View File

@ -5,7 +5,7 @@ export const PRESET_PLACEHOLDER = `[prompt]`;
export const buildPresetModifiedPrompt = (presetPrompt: string, currentPrompt: string) => {
return presetPrompt.includes(PRESET_PLACEHOLDER)
? presetPrompt.replace(new RegExp(PRESET_PLACEHOLDER), currentPrompt)
? presetPrompt.replace(PRESET_PLACEHOLDER, currentPrompt)
: `${currentPrompt} ${presetPrompt}`;
};

View File

@ -0,0 +1,6 @@
import { atom } from 'nanostores';
/**
* Tracks whether or not the style preset menu is open.
*/
export const $isMenuOpen = atom<boolean>(false);

View File

@ -5,7 +5,6 @@ import type { PersistConfig } from 'app/store/store';
import type { StylePresetState } from './types';
const initialState: StylePresetState = {
isMenuOpen: false,
activeStylePresetId: null,
searchTerm: '',
viewMode: false,
@ -15,9 +14,6 @@ export const stylePresetSlice = createSlice({
name: 'stylePreset',
initialState: initialState,
reducers: {
isMenuOpenChanged: (state, action: PayloadAction<boolean>) => {
state.isMenuOpen = action.payload;
},
activeStylePresetIdChanged: (state, action: PayloadAction<string | null>) => {
state.activeStylePresetId = action.payload;
},
@ -30,8 +26,7 @@ export const stylePresetSlice = createSlice({
},
});
export const { isMenuOpenChanged, activeStylePresetIdChanged, searchTermChanged, viewModeChanged } =
stylePresetSlice.actions;
export const { activeStylePresetIdChanged, searchTermChanged, viewModeChanged } = stylePresetSlice.actions;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
const migrateStylePresetState = (state: any): any => {

View File

@ -12,7 +12,6 @@ export type PrefilledFormData = {
};
export type StylePresetState = {
isMenuOpen: boolean;
activeStylePresetId: string | null;
searchTerm: string;
viewMode: boolean;

View File

@ -3,7 +3,8 @@ export const getViewModeChunks = (currentPrompt: string, presetPrompt?: string):
if (!presetPrompt || !presetPrompt.length) {
return ['', currentPrompt, ''];
}
const chunks = presetPrompt.split(PRESET_PLACEHOLDER);
const [firstPart, ...remainingParts] = presetPrompt.split(PRESET_PLACEHOLDER);
const chunks = [firstPart, remainingParts.join(PRESET_PLACEHOLDER)];
if (chunks.length === 1) {
return ['', currentPrompt, chunks[0] ?? ''];
} else {

View File

@ -1,4 +1,5 @@
import { Box, Flex } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { useAppSelector } from 'app/store/storeHooks';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
@ -11,6 +12,7 @@ import { ImageSettingsAccordion } from 'features/settingsAccordions/components/I
import { RefinerSettingsAccordion } from 'features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion';
import { StylePresetMenu } from 'features/stylePresets/components/StylePresetMenu';
import { StylePresetMenuTrigger } from 'features/stylePresets/components/StylePresetMenuTrigger';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import type { CSSProperties } from 'react';
import { memo } from 'react';
@ -22,7 +24,7 @@ const overlayScrollbarsStyles: CSSProperties = {
const ParametersPanelCanvas = () => {
const isSDXL = useAppSelector((s) => s.generation.model?.base === 'sdxl');
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
const isMenuOpen = useStore($isMenuOpen);
return (
<Flex w="full" h="full" flexDir="column" gap={2}>
@ -30,25 +32,24 @@ const ParametersPanelCanvas = () => {
<StylePresetMenuTrigger />
<Flex w="full" h="full" position="relative">
<Box position="absolute" top={0} left={0} right={0} bottom={0}>
{isMenuOpen ? (
{isMenuOpen && (
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<StylePresetMenu />
</Flex>
</OverlayScrollbarsComponent>
) : (
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<Prompts />
<ImageSettingsAccordion />
<GenerationSettingsAccordion />
<ControlSettingsAccordion />
<CompositingSettingsAccordion />
{isSDXL && <RefinerSettingsAccordion />}
<AdvancedSettingsAccordion />
</Flex>
</OverlayScrollbarsComponent>
)}
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<Prompts />
<ImageSettingsAccordion />
<GenerationSettingsAccordion />
<ControlSettingsAccordion />
<CompositingSettingsAccordion />
{isSDXL && <RefinerSettingsAccordion />}
<AdvancedSettingsAccordion />
</Flex>
</OverlayScrollbarsComponent>
</Box>
</Flex>
</Flex>

View File

@ -1,5 +1,6 @@
import type { ChakraProps } from '@invoke-ai/ui-library';
import { Box, Flex, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import { ControlLayersPanelContent } from 'features/controlLayers/components/ControlLayersPanelContent';
@ -15,6 +16,7 @@ import { ImageSettingsAccordion } from 'features/settingsAccordions/components/I
import { RefinerSettingsAccordion } from 'features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion';
import { StylePresetMenu } from 'features/stylePresets/components/StylePresetMenu';
import { StylePresetMenuTrigger } from 'features/stylePresets/components/StylePresetMenuTrigger';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import type { CSSProperties } from 'react';
@ -61,7 +63,7 @@ const ParametersPanelTextToImage = () => {
);
const ref = useRef<HTMLDivElement>(null);
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
const isMenuOpen = useStore($isMenuOpen);
return (
<Flex w="full" h="full" flexDir="column" gap={2}>
@ -69,57 +71,56 @@ const ParametersPanelTextToImage = () => {
<StylePresetMenuTrigger />
<Flex w="full" h="full" position="relative">
<Box position="absolute" top={0} left={0} right={0} bottom={0} ref={ref}>
{isMenuOpen ? (
{isMenuOpen && (
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<StylePresetMenu />
</Flex>
</OverlayScrollbarsComponent>
) : (
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<Prompts />
<Tabs
defaultIndex={0}
variant="enclosed"
display="flex"
flexDir="column"
w="full"
h="full"
gap={2}
onChange={onChangeTabs}
>
<TabList gap={2} fontSize="sm" borderColor="base.800">
<Tab sx={baseStyles} _selected={selectedStyles} data-testid="generation-tab-settings-tab-button">
{t('common.settingsLabel')}
</Tab>
<Tab
sx={baseStyles}
_selected={selectedStyles}
data-testid="generation-tab-control-layers-tab-button"
>
{controlLayersTitle}
</Tab>
</TabList>
<TabPanels w="full" h="full">
<TabPanel p={0} w="full" h="full">
<Flex gap={2} flexDirection="column" h="full" w="full">
<ImageSettingsAccordion />
<GenerationSettingsAccordion />
{activeTabName !== 'generation' && <ControlSettingsAccordion />}
{activeTabName === 'canvas' && <CompositingSettingsAccordion />}
{isSDXL && <RefinerSettingsAccordion />}
<AdvancedSettingsAccordion />
</Flex>
</TabPanel>
<TabPanel p={0} w="full" h="full">
<ControlLayersPanelContent />
</TabPanel>
</TabPanels>
</Tabs>
</Flex>
</OverlayScrollbarsComponent>
)}
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<Prompts />
<Tabs
defaultIndex={0}
variant="enclosed"
display="flex"
flexDir="column"
w="full"
h="full"
gap={2}
onChange={onChangeTabs}
>
<TabList gap={2} fontSize="sm" borderColor="base.800">
<Tab sx={baseStyles} _selected={selectedStyles} data-testid="generation-tab-settings-tab-button">
{t('common.settingsLabel')}
</Tab>
<Tab
sx={baseStyles}
_selected={selectedStyles}
data-testid="generation-tab-control-layers-tab-button"
>
{controlLayersTitle}
</Tab>
</TabList>
<TabPanels w="full" h="full">
<TabPanel p={0} w="full" h="full">
<Flex gap={2} flexDirection="column" h="full" w="full">
<ImageSettingsAccordion />
<GenerationSettingsAccordion />
{activeTabName !== 'generation' && <ControlSettingsAccordion />}
{activeTabName === 'canvas' && <CompositingSettingsAccordion />}
{isSDXL && <RefinerSettingsAccordion />}
<AdvancedSettingsAccordion />
</Flex>
</TabPanel>
<TabPanel p={0} w="full" h="full">
<ControlLayersPanelContent />
</TabPanel>
</TabPanels>
</Tabs>
</Flex>
</OverlayScrollbarsComponent>
</Box>
</Flex>
</Flex>

View File

@ -1,5 +1,5 @@
import { Box, Flex } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { useStore } from '@nanostores/react';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
import QueueControls from 'features/queue/components/QueueControls';
@ -8,6 +8,7 @@ import { GenerationSettingsAccordion } from 'features/settingsAccordions/compone
import { UpscaleSettingsAccordion } from 'features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion';
import { StylePresetMenu } from 'features/stylePresets/components/StylePresetMenu';
import { StylePresetMenuTrigger } from 'features/stylePresets/components/StylePresetMenuTrigger';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import type { CSSProperties } from 'react';
import { memo } from 'react';
@ -18,29 +19,28 @@ const overlayScrollbarsStyles: CSSProperties = {
};
const ParametersPanelUpscale = () => {
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
const isMenuOpen = useStore($isMenuOpen);
return (
<Flex w="full" h="full" flexDir="column" gap={2}>
<QueueControls />
<StylePresetMenuTrigger />
<Flex w="full" h="full" position="relative">
<Box position="absolute" top={0} left={0} right={0} bottom={0}>
{isMenuOpen ? (
{isMenuOpen && (
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<StylePresetMenu />
</Flex>
</OverlayScrollbarsComponent>
) : (
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<Prompts />
<UpscaleSettingsAccordion />
<GenerationSettingsAccordion />
<AdvancedSettingsAccordion />
</Flex>
</OverlayScrollbarsComponent>
)}
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
<Flex gap={2} flexDirection="column" h="full" w="full">
<Prompts />
<UpscaleSettingsAccordion />
<GenerationSettingsAccordion />
<AdvancedSettingsAccordion />
</Flex>
</OverlayScrollbarsComponent>
</Box>
</Flex>
</Flex>

View File

@ -44,9 +44,8 @@ export const stylePresetsApi = api.injectEndpoints({
if (image) {
formData.append('image', image);
}
formData.append('name', name);
formData.append('positive_prompt', positive_prompt);
formData.append('negative_prompt', negative_prompt);
formData.append('data', JSON.stringify({ name, positive_prompt, negative_prompt }));
return {
url: buildStylePresetsUrl(),
@ -70,10 +69,7 @@ export const stylePresetsApi = api.injectEndpoints({
if (image) {
formData.append('image', image);
}
formData.append('name', name);
formData.append('positive_prompt', positive_prompt);
formData.append('negative_prompt', negative_prompt);
formData.append('data', JSON.stringify({ name, positive_prompt, negative_prompt }));
return {
url: buildStylePresetsUrl(`i/${id}`),