diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 76f1ac0069..c309e4de50 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1154,6 +1154,136 @@ "variations": "Try a variation with a value between 0.1 and 1.0 to change the result for a given seed. Interesting variations of the seed are between 0.1 and 0.3." } }, + "popovers": { + "clipSkip": { + "heading": "CLIP Skip", + "paragraph": "Choose how many layers of the CLIP model to skip. Certain models are better suited to be used with CLIP Skip." + }, + "compositingBlur": { + "heading": "Blur", + "paragraph": "The blur radius of the mask." + }, + "compositingBlurMethod": { + "heading": "Blur Method", + "paragraph": "The method of blur applied to the masked area." + }, + "compositingCoherencePass": { + "heading": "Coherence Pass", + "paragraph": "Composite the Inpainted/Outpainted images." + }, + "compositingCoherenceMode": { + "heading": "Mode", + "paragraph": "The mode of the Coherence Pass." + }, + "compositingCoherenceSteps": { + "heading": "Steps", + "paragraph": "Number of steps in the Coherence Pass. Similar to Denoising Steps." + }, + "compositingStrength": { + "heading": "Strength", + "paragraph": "Amount of noise added for the Coherence Pass. Similar to Denoising Strength." + }, + "compositingMaskAdjustments": { + "heading": "Mask Adjustments", + "paragraph": "Adjust the mask." + }, + "controlNetBeginEnd": { + "heading": "Begin / End Step Percentage", + "paragraph": "Which parts of the denoising process will have the ControlNet applied. ControlNets applied at the start of the process guide composition, and ControlNets applied at the end guide details." + }, + "controlNetControlMode": { + "heading": "Control Mode", + "paragraph": "Lends more weight to either the prompt or ControlNet." + }, + "controlNetResizeMode": { + "heading": "Resize Mode", + "paragraph": "How the ControlNet image will be fit to the image generation Ratio" + }, + "controlNetToggle": { + "heading": "Enable ControlNet", + "paragraph": "ControlNets provide guidance to the generation process, helping create images with controlled composition, structure, or style, depending on the model selected." + }, + "controlNetWeight": { + "heading": "Weight", + "paragraph": "How strongly the ControlNet will impact the generated image." + }, + "dynamicPromptsToggle": { + "heading": "Enable Dynamic Prompts", + "paragraph": "Dynamic prompts allow multiple options within a prompt. Dynamic prompts can be used by: {option1|option2|option3}. Combinations of prompts will be randomly generated until the “Images” number has been reached." + }, + "dynamicPromptsCombinatorial": { + "heading": "Combinatorial Generation", + "paragraph": "Generate an image for every possible combination of Dynamic Prompt until the Max Prompts is reached." + }, + "infillMethod": { + "heading": "Infill Method", + "paragraph": "Method to infill the selected area." + }, + "lora": { + "heading": "LoRA", + "paragraph": "Weight of the LoRA. Higher weight will lead to larger impacts on the final image." + }, + "noiseEnable": { + "heading": "Enable Noise Settings", + "paragraph": "Advanced control over noise generation." + }, + "noiseUseCPU": { + "heading": "Use CPU Noise", + "paragraph": "Uses the CPU to generate random noise." + }, + "paramCFGScale": { + "heading": "CFG Scale", + "paragraph": "Controls how much your prompt influences the generation process." + }, + "paramDenoisingStrength": { + "heading": "Denoising Strength", + "paragraph": "How much noise is added to the input image. 0 will result in an identical image, while 1 will result in a completely new image." + }, + "paramImages": { + "heading": "Images", + "paragraph": "Number of images that will be generated." + }, + "paramModel": { + "heading": "Model", + "paragraph": "Model used for the denoising steps. Different models are trained to specialize in producing different aesthetic results and content." + }, + "paramNegativeConditioning": { + "heading": "Negative Prompts", + "paragraph": "This is where you enter your negative prompts." + }, + "paramPositiveConditioning": { + "heading": "Positive Prompts", + "paragraph": "This is where you enter your positive prompts." + }, + "paramRatio": { + "heading": "Ratio", + "paragraph": "The ratio of the dimensions of the image generated. An image size (in number of pixels) equivalent to 512x512 is recommended for SD1.5 models and a size equivalent to 1024x1024 is recommended for SDXL models." + }, + "paramScheduler": { + "heading": "Scheduler", + "paragraph": "Scheduler defines how to iteratively add noise to an image or how to update a sample based on a model's output." + }, + "paramSeed": { + "heading": "Seed", + "paragraph": "Controls the starting noise used for generation. Disable “Random Seed” to produce identical results with the same generation settings." + }, + "paramSteps": { + "heading": "Steps", + "paragraph": "Number of steps that will be performed in each generation. Higher step counts will typically create better images but will require more generation time." + }, + "paramVAE": { + "heading": "VAE", + "paragraph": "Model used for translating AI output into the final image." + }, + "paramVAEPrecision": { + "heading": "VAE Precision", + "paragraph": "The precision used during VAE encoding and decoding. Fp16/Half precision is more efficient, at the expense of minor image variations." + }, + "scaleBeforeProcessing": { + "heading": "Scale Before Processing", + "paragraph": "Scales the selected area to the size best suited for the model before the image generation process." + } + }, "ui": { "hideProgressImages": "Hide Progress Images", "lockRatio": "Lock Ratio", diff --git a/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx b/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx new file mode 100644 index 0000000000..bbfccf7c0d --- /dev/null +++ b/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx @@ -0,0 +1,112 @@ +import { + Button, + Popover, + PopoverTrigger, + PopoverContent, + PopoverArrow, + PopoverCloseButton, + PopoverHeader, + PopoverBody, + PopoverProps, + Flex, + Text, + Image, +} from '@chakra-ui/react'; +import { useAppSelector } from '../../app/store/storeHooks'; +import { useTranslation } from 'react-i18next'; + +interface Props extends PopoverProps { + details: string; + children: JSX.Element; + image?: string; + buttonLabel?: string; + buttonHref?: string; + placement?: PopoverProps['placement']; +} + +function IAIInformationalPopover({ + details, + image, + buttonLabel, + buttonHref, + children, + placement, +}: Props): JSX.Element { + const shouldDisableInformationalPopovers = useAppSelector( + (state) => state.system.shouldDisableInformationalPopovers + ); + const { t } = useTranslation(); + + const heading = t(`popovers.${details}.heading`); + const paragraph = t(`popovers.${details}.paragraph`); + + if (shouldDisableInformationalPopovers) { + return children; + } else { + return ( + + +
{children}
+
+ + + + + + + {image && ( + Optional Image + )} + + {heading && {heading}} + {paragraph} + {buttonLabel && ( + + + + )} + + + + +
+ ); + } +} + +export default IAIInformationalPopover; diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetBeginEnd.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetBeginEnd.tsx index f34c863cff..fb43c3553d 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetBeginEnd.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetBeginEnd.tsx @@ -10,6 +10,7 @@ import { Tooltip, } from '@chakra-ui/react'; import { useAppDispatch } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import { ControlNetConfig, controlNetBeginStepPctChanged, @@ -49,58 +50,60 @@ const ParamControlNetBeginEnd = (props: Props) => { ); return ( - - {t('controlnet.beginEndStepPercent')} - - - - - - - - - - - - + + {t('controlnet.beginEndStepPercent')} + + - 0% - - - 50% - - - 100% - - - - + + + + + + + + + + + 0% + + + 50% + + + 100% + + + + + ); }; diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetControlMode.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetControlMode.tsx index e8f26a6dd1..9b17c2bfb2 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetControlMode.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetControlMode.tsx @@ -1,4 +1,5 @@ import { useAppDispatch } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSelect from 'common/components/IAIMantineSelect'; import { ControlModes, @@ -34,12 +35,14 @@ export default function ParamControlNetControlMode( ); return ( - + + + ); } diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx index 97a54dc7d1..1902d622ff 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISwitch from 'common/components/IAISwitch'; import { isControlNetEnabledToggled } from 'features/controlNet/store/controlNetSlice'; import { memo, useCallback } from 'react'; @@ -25,14 +26,16 @@ const ParamControlNetFeatureToggle = () => { }, [dispatch]); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetResizeMode.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetResizeMode.tsx index f2b2b59785..0ad2f342b2 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetResizeMode.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetResizeMode.tsx @@ -1,4 +1,5 @@ import { useAppDispatch } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSelect from 'common/components/IAIMantineSelect'; import { ControlNetConfig, @@ -33,12 +34,14 @@ export default function ParamControlNetResizeMode( ); return ( - + + + ); } diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx index 8314f26cfc..4e9928d828 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx @@ -1,4 +1,5 @@ import { useAppDispatch } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISlider from 'common/components/IAISlider'; import { ControlNetConfig, @@ -23,17 +24,19 @@ const ParamControlNetWeight = (props: ParamControlNetWeightProps) => { ); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx index 29c06ffdc7..391d588733 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx +++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx @@ -6,6 +6,7 @@ import IAISwitch from 'common/components/IAISwitch'; import { memo, useCallback } from 'react'; import { combinatorialToggled } from '../store/dynamicPromptsSlice'; import { useTranslation } from 'react-i18next'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const selector = createSelector( stateSelector, @@ -27,11 +28,13 @@ const ParamDynamicPromptsCombinatorial = () => { }, [dispatch]); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/lora/components/ParamLora.tsx b/invokeai/frontend/web/src/features/lora/components/ParamLora.tsx index 3432838ec0..951de86217 100644 --- a/invokeai/frontend/web/src/features/lora/components/ParamLora.tsx +++ b/invokeai/frontend/web/src/features/lora/components/ParamLora.tsx @@ -10,6 +10,7 @@ import { loraWeightChanged, loraWeightReset, } from '../store/loraSlice'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; type Props = { lora: LoRA; @@ -35,30 +36,32 @@ const ParamLora = (props: Props) => { }, [dispatch, lora.id]); return ( - - - } - colorScheme="error" - /> - + + + + } + colorScheme="error" + /> + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx index f51e42b6a1..a7d3d3c655 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx @@ -1,5 +1,6 @@ import { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISlider from 'common/components/IAISlider'; import { setClipSkip } from 'features/parameters/store/generationSlice'; import { clipSkipMap } from 'features/parameters/types/constants'; @@ -42,19 +43,21 @@ export default function ParamClipSkip() { }, [model]); return ( - + + + ); } diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/BoundingBox/ParamBoundingBoxSize.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/BoundingBox/ParamBoundingBoxSize.tsx index 1c1f60bc09..a3eb428526 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/BoundingBox/ParamBoundingBoxSize.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/BoundingBox/ParamBoundingBoxSize.tsx @@ -18,6 +18,7 @@ import ParamAspectRatio, { } from '../../Core/ParamAspectRatio'; import ParamBoundingBoxHeight from './ParamBoundingBoxHeight'; import ParamBoundingBoxWidth from './ParamBoundingBoxWidth'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const sizeOptsSelector = createSelector( [generationSelector, canvasSelector], @@ -93,18 +94,20 @@ export default function ParamBoundingBoxSize() { }} > - - {t('parameters.aspectRatio')} - + + + {t('parameters.aspectRatio')} + + { }; return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceSteps.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceSteps.tsx index 5482a7e1d9..f7de446737 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceSteps.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceSteps.tsx @@ -1,5 +1,6 @@ import type { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISlider from 'common/components/IAISlider'; import { setCanvasCoherenceSteps } from 'features/parameters/store/generationSlice'; import { memo } from 'react'; @@ -13,23 +14,25 @@ const ParamCanvasCoherenceSteps = () => { const { t } = useTranslation(); return ( - { - dispatch(setCanvasCoherenceSteps(v)); - }} - withInput - withSliderMarks - withReset - handleReset={() => { - dispatch(setCanvasCoherenceSteps(20)); - }} - /> + + { + dispatch(setCanvasCoherenceSteps(v)); + }} + withInput + withSliderMarks + withReset + handleReset={() => { + dispatch(setCanvasCoherenceSteps(20)); + }} + /> + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceStrength.tsx index f478bd70fe..31b86cfd49 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceStrength.tsx @@ -1,5 +1,6 @@ import type { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISlider from 'common/components/IAISlider'; import { setCanvasCoherenceStrength } from 'features/parameters/store/generationSlice'; import { memo } from 'react'; @@ -13,23 +14,25 @@ const ParamCanvasCoherenceStrength = () => { const { t } = useTranslation(); return ( - { - dispatch(setCanvasCoherenceStrength(v)); - }} - withInput - withSliderMarks - withReset - handleReset={() => { - dispatch(setCanvasCoherenceStrength(0.3)); - }} - /> + + { + dispatch(setCanvasCoherenceStrength(v)); + }} + withInput + withSliderMarks + withReset + handleReset={() => { + dispatch(setCanvasCoherenceStrength(0.3)); + }} + /> + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlur.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlur.tsx index 82b82228e2..da68f5ed3c 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlur.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlur.tsx @@ -1,5 +1,6 @@ import type { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISlider from 'common/components/IAISlider'; import { setMaskBlur } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; @@ -12,21 +13,23 @@ export default function ParamMaskBlur() { const { t } = useTranslation(); return ( - { - dispatch(setMaskBlur(v)); - }} - withInput - withSliderMarks - withReset - handleReset={() => { - dispatch(setMaskBlur(16)); - }} - /> + + { + dispatch(setMaskBlur(v)); + }} + withInput + withSliderMarks + withReset + handleReset={() => { + dispatch(setMaskBlur(16)); + }} + /> + ); } diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlurMethod.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlurMethod.tsx index 62d0605640..12da7fd2fd 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlurMethod.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/MaskAdjustment/ParamMaskBlurMethod.tsx @@ -2,6 +2,7 @@ import { SelectItem } from '@mantine/core'; import { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSelect from 'common/components/IAIMantineSelect'; import { setMaskBlurMethod } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; @@ -28,11 +29,13 @@ export default function ParamMaskBlurMethod() { }; return ( - + + + ); } diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx index d0a0ff8f01..606d6d2dfc 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx @@ -15,13 +15,19 @@ const ParamCompositingSettingsCollapse = () => { return ( - + - + diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx index 9ac0e3588f..7a4ac1601d 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSelect from 'common/components/IAIMantineSelect'; import { setInfillMethod } from 'features/parameters/store/generationSlice'; @@ -39,14 +40,16 @@ const ParamInfillMethod = () => { ); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaleBeforeProcessing.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaleBeforeProcessing.tsx index e00d56b639..a1c63d6ddb 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaleBeforeProcessing.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaleBeforeProcessing.tsx @@ -1,6 +1,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { setBoundingBoxScaleMethod } from 'features/canvas/store/canvasSlice'; @@ -35,12 +36,14 @@ const ParamScaleBeforeProcessing = () => { }; return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamCFGScale.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamCFGScale.tsx index 54a7ccbe65..51d6edc2dc 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamCFGScale.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamCFGScale.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAINumberInput from 'common/components/IAINumberInput'; import IAISlider from 'common/components/IAISlider'; import { setCfgScale } from 'features/parameters/store/generationSlice'; @@ -53,31 +54,35 @@ const ParamCFGScale = () => { ); return shouldUseSliders ? ( - + + + ) : ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamIterations.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamIterations.tsx index 46d90b3954..f9df43d7ca 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamIterations.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamIterations.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAINumberInput from 'common/components/IAINumberInput'; import IAISlider from 'common/components/IAISlider'; import { setIterations } from 'features/parameters/store/generationSlice'; @@ -60,29 +61,33 @@ const ParamIterations = ({ asSlider }: Props) => { }, [dispatch, initial]); return asSlider || shouldUseSliders ? ( - + + + ) : ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx index 2aab013f4f..1154187eaf 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx @@ -9,6 +9,7 @@ import { ChangeEvent, KeyboardEvent, memo, useCallback, useRef } from 'react'; import { flushSync } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const ParamNegativeConditioning = () => { const negativePrompt = useAppSelector( @@ -81,18 +82,20 @@ const ParamNegativeConditioning = () => { onClose={onClose} onSelect={handleSelectEmbedding} > - + + + {!isOpen && isEmbeddingEnabled && ( { onClose={onClose} onSelect={handleSelectEmbedding} > - + + + {!isOpen && isEmbeddingEnabled && ( diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamScheduler.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamScheduler.tsx index da1b359b37..3aadac0457 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamScheduler.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamScheduler.tsx @@ -1,6 +1,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect'; import { generationSelector } from 'features/parameters/store/generationSelectors'; import { setScheduler } from 'features/parameters/store/generationSlice'; @@ -51,12 +52,14 @@ const ParamScheduler = () => { ); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamSize.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamSize.tsx index 99d0617de3..c7ddd59559 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamSize.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamSize.tsx @@ -16,6 +16,7 @@ import { activeTabNameSelector } from '../../../../ui/store/uiSelectors'; import ParamAspectRatio, { mappedAspectRatios } from './ParamAspectRatio'; import ParamHeight from './ParamHeight'; import ParamWidth from './ParamWidth'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; const sizeOptsSelector = createSelector( @@ -83,18 +84,20 @@ export default function ParamSize() { }} > - - {t('parameters.aspectRatio')} - + + + {t('parameters.aspectRatio')} + + { }, [dispatch]); return shouldUseSliders ? ( - + + + ) : ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/ImageToImageStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/ImageToImageStrength.tsx index 2a14ee634c..b22dff22e5 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/ImageToImageStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/ImageToImageStrength.tsx @@ -7,6 +7,7 @@ import { setImg2imgStrength } from 'features/parameters/store/generationSlice'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import SubParametersWrapper from '../SubParametersWrapper'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const selector = createSelector( [stateSelector], @@ -46,20 +47,22 @@ const ImageToImageStrength = () => { return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/MainModel/ParamMainModelSelect.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/MainModel/ParamMainModelSelect.tsx index 05b5b6468a..9c957523bc 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/MainModel/ParamMainModelSelect.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/MainModel/ParamMainModelSelect.tsx @@ -21,6 +21,7 @@ import { useGetOnnxModelsQuery, } from 'services/api/endpoints/models'; import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const selector = createSelector( stateSelector, @@ -118,24 +119,28 @@ const ParamMainModelSelect = () => { data={[]} /> ) : ( - - 0 ? 'Select a model' : 'No models available'} - data={data} - error={data.length === 0} - disabled={data.length === 0} - onChange={handleChangeModel} - w="100%" - /> - {isSyncModelEnabled && ( - - - - )} - + + + 0 ? 'Select a model' : 'No models available' + } + data={data} + error={data.length === 0} + disabled={data.length === 0} + onChange={handleChangeModel} + w="100%" + /> + {isSyncModelEnabled && ( + + + + )} + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Noise/ParamCpuNoise.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Noise/ParamCpuNoise.tsx index 23f8f23fb6..b3c8aea415 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Noise/ParamCpuNoise.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Noise/ParamCpuNoise.tsx @@ -1,4 +1,5 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAISwitch from 'common/components/IAISwitch'; import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice'; import { ChangeEvent, useCallback } from 'react'; @@ -19,10 +20,12 @@ export const ParamCpuNoiseToggle = () => { ); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Seed/ParamSeedFull.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Seed/ParamSeedFull.tsx index a1887ec896..8ddba1cbb2 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Seed/ParamSeedFull.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Seed/ParamSeedFull.tsx @@ -3,14 +3,17 @@ import { memo } from 'react'; import ParamSeed from './ParamSeed'; import ParamSeedShuffle from './ParamSeedShuffle'; import ParamSeedRandomize from './ParamSeedRandomize'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const ParamSeedFull = () => { return ( - - - - - + + + + + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/SubParametersWrapper.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/SubParametersWrapper.tsx index 96c78b1336..65b565e926 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/SubParametersWrapper.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/SubParametersWrapper.tsx @@ -1,9 +1,11 @@ import { Flex, Text } from '@chakra-ui/react'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import { ReactNode, memo } from 'react'; type SubParameterWrapperProps = { children: ReactNode | ReactNode[]; label?: string; + headerInfoPopover?: string; }; const SubParametersWrapper = (props: SubParameterWrapperProps) => ( @@ -21,7 +23,18 @@ const SubParametersWrapper = (props: SubParameterWrapperProps) => ( }, }} > - {props.label && ( + {props.headerInfoPopover && props.label && ( + + + {props.label} + + + )} + {!props.headerInfoPopover && props.label && ( { ); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEPrecision.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEPrecision.tsx index c57cdc1132..5fa15c5fe3 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEPrecision.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEPrecision.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; import IAIMantineSelect from 'common/components/IAIMantineSelect'; import { vaePrecisionChanged } from 'features/parameters/store/generationSlice'; import { PrecisionParam } from 'features/parameters/types/parameterSchemas'; @@ -34,12 +35,14 @@ const ParamVAEModelSelect = () => { ); return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLImg2ImgDenoisingStrength.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLImg2ImgDenoisingStrength.tsx index 5433c77b4e..dc8ae775f9 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLImg2ImgDenoisingStrength.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLImg2ImgDenoisingStrength.tsx @@ -7,6 +7,7 @@ import SubParametersWrapper from 'features/parameters/components/Parameters/SubP import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { setSDXLImg2ImgDenoisingStrength } from '../store/sdxlSlice'; +import IAIInformationalPopover from 'common/components/IAIInformationalPopover'; const selector = createSelector( [stateSelector], @@ -36,19 +37,21 @@ const ParamSDXLImg2ImgDenoisingStrength = () => { return ( - + + + ); }; diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx index f1bc3f0a40..0a50f9ad7f 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx @@ -23,6 +23,7 @@ import { consoleLogLevelChanged, setEnableImageDebugging, setShouldConfirmOnDelete, + setShouldDisableInformationalPopovers, shouldAntialiasProgressImageChanged, shouldLogToConsoleChanged, shouldUseNSFWCheckerChanged, @@ -66,6 +67,7 @@ const selector = createSelector( shouldAntialiasProgressImage, shouldUseNSFWChecker, shouldUseWatermarker, + shouldDisableInformationalPopovers, } = system; const { @@ -85,6 +87,7 @@ const selector = createSelector( shouldUseNSFWChecker, shouldUseWatermarker, shouldAutoChangeDimensions, + shouldDisableInformationalPopovers, }; }, { @@ -158,6 +161,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { shouldUseNSFWChecker, shouldUseWatermarker, shouldAutoChangeDimensions, + shouldDisableInformationalPopovers, } = useAppSelector(selector); const handleClickResetWebUI = useCallback(() => { @@ -307,6 +311,15 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { onChange={handleLanguageChanged} /> )} + ) => + dispatch( + setShouldDisableInformationalPopovers(e.target.checked) + ) + } + /> {shouldShowDeveloperSettings && ( diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index 40e8c42145..c74ab87dcf 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -35,6 +35,7 @@ export const initialSystemState: SystemState = { language: 'en', shouldUseNSFWChecker: false, shouldUseWatermarker: false, + shouldDisableInformationalPopovers: false, status: 'DISCONNECTED', }; @@ -75,6 +76,12 @@ export const systemSlice = createSlice({ shouldUseWatermarkerChanged(state, action: PayloadAction) { state.shouldUseWatermarker = action.payload; }, + setShouldDisableInformationalPopovers( + state, + action: PayloadAction + ) { + state.shouldDisableInformationalPopovers = action.payload; + }, }, extraReducers(builder) { /** @@ -234,6 +241,7 @@ export const { languageChanged, shouldUseNSFWCheckerChanged, shouldUseWatermarkerChanged, + setShouldDisableInformationalPopovers, } = systemSlice.actions; export default systemSlice.reducer; diff --git a/invokeai/frontend/web/src/features/system/store/types.ts b/invokeai/frontend/web/src/features/system/store/types.ts index b81e292e36..29bc836dae 100644 --- a/invokeai/frontend/web/src/features/system/store/types.ts +++ b/invokeai/frontend/web/src/features/system/store/types.ts @@ -33,6 +33,7 @@ export interface SystemState { shouldUseNSFWChecker: boolean; shouldUseWatermarker: boolean; status: SystemStatus; + shouldDisableInformationalPopovers: boolean; } export const LANGUAGES = { diff --git a/invokeai/frontend/web/src/theme/components/button.ts b/invokeai/frontend/web/src/theme/components/button.ts index dd802a878b..fc6cde9cd0 100644 --- a/invokeai/frontend/web/src/theme/components/button.ts +++ b/invokeai/frontend/web/src/theme/components/button.ts @@ -80,6 +80,13 @@ const invokeAIOutline = defineStyle((props) => { return { border: '1px solid', borderColor: c === 'gray' ? borderColor : 'currentColor', + _hover: { + bg: mode(`${c}.500`, `${c}.500`)(props), + color: mode('white', `base.50`)(props), + svg: { + fill: mode('white', `base.50`)(props), + }, + }, '.chakra-button__group[data-attached][data-orientation=horizontal] > &:not(:last-of-type)': { marginEnd: '-1px', diff --git a/invokeai/frontend/web/src/theme/components/popover.ts b/invokeai/frontend/web/src/theme/components/popover.ts index a28e2bfbc4..55f69e9036 100644 --- a/invokeai/frontend/web/src/theme/components/popover.ts +++ b/invokeai/frontend/web/src/theme/components/popover.ts @@ -29,13 +29,34 @@ const invokeAIContent = defineStyle((props) => { }; }); +const informationalContent = defineStyle((props) => { + return { + [$arrowBg.variable]: mode('colors.base.100', 'colors.base.600')(props), + [$popperBg.variable]: mode('colors.base.100', 'colors.base.600')(props), + [$arrowShadowColor.variable]: mode( + 'colors.base.400', + 'colors.base.400' + )(props), + p: 0, + bg: mode('base.100', 'base.600')(props), + border: 'none', + shadow: 'dark-lg', + }; +}); + const invokeAI = definePartsStyle((props) => ({ content: invokeAIContent(props), })); +const informational = definePartsStyle((props) => ({ + content: informationalContent(props), + body: { padding: 0 }, +})); + export const popoverTheme = defineMultiStyleConfig({ variants: { invokeAI, + informational, }, defaultProps: { variant: 'invokeAI',