diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index bc0b194510..712f1d2f7a 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -2471,6 +2471,10 @@ "title": "Upload Image to Upscale", "description": "Click or drag an image to upscale (JPG, PNG, WebP up to 100MB)" }, + "replaceImage": { + "title": "Replace Current Image", + "description": "Click or drag a new image to replace the current one" + }, "imageReady": { "title": "Image Ready", "description": "Press Invoke to begin upscaling" diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/LaunchpadButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/LaunchpadButton.tsx index 150fada4e6..26ea2950d5 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/LaunchpadButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/LaunchpadButton.tsx @@ -11,6 +11,7 @@ export const LaunchpadButton = memo( display="flex" position="relative" alignItems="center" + justifyContent="left" borderWidth={1} borderRadius="base" p={4} diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/UpscalingLaunchpadPanel.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/UpscalingLaunchpadPanel.tsx index 2deb3e449c..f956f867eb 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/UpscalingLaunchpadPanel.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/UpscalingLaunchpadPanel.tsx @@ -1,17 +1,14 @@ -import { Box, Flex, Grid, Heading, Icon, Text } from '@invoke-ai/ui-library'; +import { Box, Button, Flex, Grid, Heading, Icon, Text } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useImageUploadButton } from 'common/hooks/useImageUploadButton'; import { setUpscaleInitialImageDndTarget } from 'features/dnd/dnd'; import { DndDropTarget } from 'features/dnd/DndDropTarget'; import { DndImage } from 'features/dnd/DndImage'; import { DndImageIcon } from 'features/dnd/DndImageIcon'; -import ParamSpandrelModel from 'features/parameters/components/Upscale/ParamSpandrelModel'; -import { selectUpscaleInitialImage, upscaleInitialImageChanged } from 'features/parameters/store/upscaleSlice'; -import { MainModelPicker } from 'features/settingsAccordions/components/GenerationSettingsAccordion/MainModelPicker'; -import { UpscaleScaleSlider } from 'features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider'; +import { selectUpscaleInitialImage, upscaleInitialImageChanged, creativityChanged, structureChanged, selectCreativity, selectStructure } from 'features/parameters/store/upscaleSlice'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { PiArrowCounterClockwiseBold, PiImageBold, PiUploadBold } from 'react-icons/pi'; +import { PiArrowCounterClockwiseBold, PiImageBold, PiUploadBold, PiShieldCheckBold, PiScalesBold, PiPaletteBold, PiSparkleBold } from 'react-icons/pi'; import type { ImageDTO } from 'services/api/types'; import { LaunchpadButton } from './LaunchpadButton'; @@ -20,6 +17,8 @@ export const UpscalingLaunchpadPanel = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const upscaleInitialImage = useAppSelector(selectUpscaleInitialImage); + const creativity = useAppSelector(selectCreativity); + const structure = useAppSelector(selectStructure); const dndTargetData = useMemo(() => setUpscaleInitialImageDndTarget.getData(), []); @@ -36,6 +35,27 @@ export const UpscalingLaunchpadPanel = memo(() => { const uploadApi = useImageUploadButton({ allowMultiple: false, onUpload }); + // Preset button handlers + const onConservativeClick = useCallback(() => { + dispatch(creativityChanged(-5)); + dispatch(structureChanged(5)); + }, [dispatch]); + + const onBalancedClick = useCallback(() => { + dispatch(creativityChanged(0)); + dispatch(structureChanged(0)); + }, [dispatch]); + + const onCreativeClick = useCallback(() => { + dispatch(creativityChanged(5)); + dispatch(structureChanged(-2)); + }, [dispatch]); + + const onArtisticClick = useCallback(() => { + dispatch(creativityChanged(8)); + dispatch(structureChanged(-5)); + }, [dispatch]); + return ( @@ -57,34 +77,14 @@ export const UpscalingLaunchpadPanel = memo(() => { ) : ( <> - - - - } - tooltip={t('common.reset')} - /> - - {`${upscaleInitialImage.width}x${upscaleInitialImage.height}`} - + - {t('ui.launchpad.upscaling.imageReady.title')} - {t('ui.launchpad.upscaling.imageReady.description')} + {t('ui.launchpad.upscaling.replaceImage.title')} + {t('ui.launchpad.upscaling.replaceImage.description')} + + + + )} @@ -108,33 +108,54 @@ export const UpscalingLaunchpadPanel = memo(() => { {/* Controls */} - {/* Left Column: All parameters stacked */} - - - - {t('ui.launchpad.upscaling.upscaleModel')} - - - - - - - - {t('ui.launchpad.upscaling.model')} - - - - - - - - {t('ui.launchpad.upscaling.scale')} - - - - - - + {/* Left Column: Creativity and Structural Defaults */} + + + Creativity & Structural Defaults + + + + + + + + {/* Right Column: Description/help text */} diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/WorkflowsLaunchpadPanel.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/WorkflowsLaunchpadPanel.tsx index 867c571cd1..df1b0cf2c9 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/WorkflowsLaunchpadPanel.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/WorkflowsLaunchpadPanel.tsx @@ -1,4 +1,4 @@ -import { Flex, Heading, Icon, Link, Text } from '@invoke-ai/ui-library'; +import { Button, Flex, Heading, Icon, Text } from '@invoke-ai/ui-library'; import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal'; import { useNewWorkflow } from 'features/workflowLibrary/components/NewWorkflowConfirmationAlertDialog'; import { useLoadWorkflowFromFile } from 'features/workflowLibrary/hooks/useLoadWorkflowFromFile'; @@ -53,14 +53,18 @@ export const WorkflowsLaunchpadPanel = memo(() => { {t('ui.launchpad.workflows.description')} - - {t('ui.launchpad.workflows.learnMoreLink')} - + + + {/* Action Buttons */} diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/viewMode/EmptyState.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/viewMode/EmptyState.tsx index 674f121a50..aa746995c5 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/viewMode/EmptyState.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/viewMode/EmptyState.tsx @@ -1,11 +1,13 @@ -import { Button, Flex, Image, Link, Text } from '@invoke-ai/ui-library'; +import { Flex, Heading, Icon, Image, Link, Text } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; +import { LaunchpadButton } from 'features/controlLayers/components/SimpleSession/LaunchpadButton'; import { useIsWorkflowUntouched } from 'features/nodes/components/sidePanel/workflow/IsolatedWorkflowBuilderWatcher'; import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal'; import { workflowModeChanged } from 'features/nodes/store/workflowLibrarySlice'; import InvokeLogoSVG from 'public/assets/images/invoke-symbol-wht-lrg.svg'; import { useCallback } from 'react'; import { Trans, useTranslation } from 'react-i18next'; +import { PiFolderOpenBold, PiPlusBold } from 'react-icons/pi'; export const EmptyState = () => { const isWorkflowUntouched = useIsWorkflowUntouched(); @@ -18,8 +20,9 @@ export const EmptyState = () => { borderRadius="base" flexDir="column" gap={5} - maxW="230px" + maxW="400px" pt={24} + px={4} > { return ( <> - - - + + + + + {t('nodes.newWorkflow')} + + Create a new workflow from scratch + + + + + + + {t('nodes.loadWorkflow')} + + Browse and load existing workflows + + + - + @@ -74,12 +89,20 @@ const DirtyEditorContent = () => { return ( <> - + {t('nodes.noFieldsViewMode')} - + + + + + {t('nodes.edit')} + + Switch to edit mode to build workflows + + + + ); }; @@ -93,4 +116,4 @@ const workflowHelpTextComponents = { target="_blank" /> ), -}; +}; \ No newline at end of file