Upscale Workflow Launchpad updates & translation updates

This commit is contained in:
Kent Keirsey
2025-06-30 13:56:17 -04:00
committed by psychedelicious
parent a7d413d372
commit d608a7469e
5 changed files with 161 additions and 91 deletions

View File

@@ -2444,6 +2444,12 @@
"upscaling": "Upscaling",
"upscalingTab": "$t(ui.tabs.upscaling) $t(common.tab)",
"gallery": "Gallery"
},
"launchpad": {
"workflowsTitle": "Go deep with Workflows.",
"upscalingTitle": "Upscale and add detail.",
"canvasTitle": "Edit and refine on Canvas.",
"generateTitle": "Generate images from text prompts."
}
},
"system": {

View File

@@ -2,6 +2,7 @@ import { Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
import { WORKSPACE_PANEL_ID } from 'features/ui/layouts/shared';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { InitialStateMainModelPicker } from './InitialStateMainModelPicker';
import { LaunchpadAddStyleReference } from './LaunchpadAddStyleReference';
@@ -10,6 +11,7 @@ import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButt
import { LaunchpadUseALayoutImageButton } from './LaunchpadUseALayoutImageButton';
export const CanvasLaunchpadPanel = memo(() => {
const { t } = useTranslation();
const ctx = useAutoLayoutContext();
const focusCanvas = useCallback(() => {
ctx.focusPanel(WORKSPACE_PANEL_ID);
@@ -17,7 +19,7 @@ export const CanvasLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
<Heading mb={4}>Edit and refine on Canvas.</Heading>
<Heading mb={4}>{t('ui.launchpad.canvasTitle')}</Heading>
<Flex flexDir="column" gap={8}>
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
<InitialStateMainModelPicker />

View File

@@ -4,10 +4,12 @@ import { InitialStateMainModelPicker } from 'features/controlLayers/components/S
import { LaunchpadAddStyleReference } from 'features/controlLayers/components/SimpleSession/LaunchpadAddStyleReference';
import { setActiveTab } from 'features/ui/store/uiSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButton';
export const GenerateLaunchpadPanel = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const newCanvasSession = useCallback(() => {
dispatch(setActiveTab('canvas'));
@@ -16,7 +18,7 @@ export const GenerateLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
<Heading mb={4}>Generate images from text prompts.</Heading>
<Heading mb={4}>{t('ui.launchpad.generateTitle')}</Heading>
<Flex flexDir="column" gap={8}>
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
<InitialStateMainModelPicker />

View File

@@ -1,83 +1,150 @@
import { Box, Flex, FormControl, FormLabel, Heading, Text } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { Box, Flex, FormControl, FormLabel, 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 } from 'features/parameters/store/upscaleSlice';
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 { memo, useCallback } from 'react';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiImageBold } from 'react-icons/pi';
import { PiArrowCounterClockwiseBold, PiImageBold, PiUploadBold } from 'react-icons/pi';
import type { ImageDTO } from 'services/api/types';
import { LaunchpadButton } from './LaunchpadButton';
export const UpscalingLaunchpadPanel = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const upscaleInitialImage = useAppSelector(selectUpscaleInitialImage);
const onUpload = useCallback(() => {
// Upload handler will be called automatically by the upload hook
}, []);
const dndTargetData = useMemo(() => setUpscaleInitialImageDndTarget.getData(), []);
const onUpload = useCallback(
(imageDTO: ImageDTO) => {
dispatch(upscaleInitialImageChanged(imageDTO));
},
[dispatch]
);
const onReset = useCallback(() => {
dispatch(upscaleInitialImageChanged(null));
}, [dispatch]);
const uploadApi = useImageUploadButton({ allowMultiple: false, onUpload });
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
<Flex flexDir="column" w="full" gap={6} px={14} maxW={768} pt="20vh">
<Heading mb={4}>{t('upscaling.upscale')} and add detail.</Heading>
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
<Heading mb={4}>{t('ui.launchpad.upscalingTitle')}</Heading>
{/* Upload Area - First CTA as per Devon's feedback */}
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8} h={24}>
<Flex flexDir="column" alignItems="center" gap={2}>
<PiImageBold size={32} />
<Box textAlign="center">
{!upscaleInitialImage && (
<>
<Text fontWeight="semibold">Click or drag an image to upscale</Text>
<Text variant="subtext" fontSize="sm">
JPG, PNG, WebP up to 100MB
</Text>
</>
)}
{upscaleInitialImage && (
<>
<Text fontWeight="semibold">Image ready</Text>
<Text variant="subtext" fontSize="sm">
Press Invoke to begin upscaling
</Text>
</>
)}
</Box>
</Flex>
{/* Upload Area */}
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8}>
{!upscaleInitialImage ? (
<>
<Icon as={PiImageBold} boxSize={8} color="base.500" />
<Flex flexDir="column" alignItems="flex-start" gap={2}>
<Heading size="sm">Upload Image to Upscale</Heading>
<Text color="base.300">Click or drag an image to upscale (JPG, PNG, WebP up to 100MB)</Text>
</Flex>
<Flex position="absolute" right={3} bottom={3}>
<PiUploadBold />
<input {...uploadApi.getUploadInputProps()} />
</Flex>
</>
) : (
<>
<Flex position="relative" w={16} h={16} alignItems="center" justifyContent="center">
<DndImage imageDTO={upscaleInitialImage} />
<Flex position="absolute" flexDir="column" top={1} insetInlineEnd={1} gap={1}>
<DndImageIcon
onClick={onReset}
icon={<PiArrowCounterClockwiseBold size={12} />}
tooltip={t('common.reset')}
/>
</Flex>
<Text
position="absolute"
background="base.900"
color="base.50"
fontSize="xs"
fontWeight="semibold"
bottom={0}
left={0}
opacity={0.7}
px={1}
lineHeight={1.25}
borderTopEndRadius="base"
borderBottomStartRadius="base"
pointerEvents="none"
>{`${upscaleInitialImage.width}x${upscaleInitialImage.height}`}</Text>
</Flex>
<Flex flexDir="column" alignItems="flex-start" gap={2}>
<Heading size="sm">Image Ready</Heading>
<Text color="base.300">Press Invoke to begin upscaling</Text>
</Flex>
</>
)}
<DndDropTarget
dndTarget={setUpscaleInitialImageDndTarget}
dndTargetData={dndTargetData}
label={t('gallery.drop')}
/>
</LaunchpadButton>
{/* Controls - 60% width as per Devon's feedback */}
<Flex flexDir="column" gap={4} w="60%">
{/* Upscale Model */}
<FormControl>
<FormLabel>{t('upscaling.upscaleModel')}</FormLabel>
<ParamSpandrelModel />
</FormControl>
{/* Guidance text */}
{upscaleInitialImage && (
<Flex
bg="base.800"
p={4}
borderRadius="base"
border="1px solid"
borderColor="base.700"
mt={6}
>
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
<strong>Ready to upscale!</strong> Configure your settings below, then click the <strong>Invoke</strong> button to begin upscaling your image.
</Text>
</Flex>
)}
{/* Generation Model */}
<FormControl>
<FormLabel>{t('parameters.model')}</FormLabel>
<MainModelPicker />
</FormControl>
{/* Scale Slider - Same width as dropdowns */}
<UpscaleScaleSlider />
</Flex>
{/* Description text with paragraph breaks as per Devon's feedback */}
<Box w="full" maxW="40%" ml="auto">
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
When upscaling, use a prompt that describes the medium and style. Avoid describing specific content details in the image.
</Text>
<Text variant="subtext" fontSize="sm" lineHeight="1.6" mt={3}>
Upscaling works best with the general style of your image.
</Text>
</Box>
{/* Controls */}
<style>{`.launchpad-hide-label .chakra-form__label { display: none !important; }`}</style>
<Grid gridTemplateColumns="1fr 1fr" gap={10} alignItems="start" mt={upscaleInitialImage ? 8 : 12}>
{/* Left Column: All parameters stacked */}
<Flex flexDir="column" gap={6} alignItems="flex-start">
<Box w="full">
<Text fontWeight="semibold" fontSize="sm" mb={1}>Upscale Model</Text>
<Box className="launchpad-hide-label">
<ParamSpandrelModel />
</Box>
</Box>
<Box w="full">
<Text fontWeight="semibold" fontSize="sm" mb={1}>Model</Text>
<Box className="launchpad-hide-label">
<MainModelPicker />
</Box>
</Box>
<Box w="full">
<Text fontWeight="semibold" fontSize="sm" mb={1}>Scale</Text>
<Box className="launchpad-hide-label">
<UpscaleScaleSlider />
</Box>
</Box>
</Flex>
{/* Right Column: Description/help text */}
<Box>
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
When upscaling, use a prompt that describes the medium and style. Avoid describing specific content details in the image.
</Text>
<Text variant="subtext" fontSize="sm" lineHeight="1.6" mt={3}>
Upscaling works best with the general style of your image.
</Text>
</Box>
</Grid>
</Flex>
</Flex>
);

View File

@@ -1,4 +1,4 @@
import { Button, Flex, Heading, Link, Text } from '@invoke-ai/ui-library';
import { Button, Flex, Heading, Icon, Link, Text } from '@invoke-ai/ui-library';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
import { useNewWorkflow } from 'features/workflowLibrary/components/NewWorkflowConfirmationAlertDialog';
@@ -53,11 +53,11 @@ export const WorkflowsLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
<Flex flexDir="column" w="full" gap={6} px={14} maxW={768} pt="20vh">
<Heading mb={4}>Go deep with Workflows.</Heading>
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
<Heading mb={4}>{t('ui.launchpad.workflowsTitle')}</Heading>
{/* Description */}
<Text variant="subtext" fontSize="md" lineHeight="1.6" mb={2}>
<Text variant="subtext" fontSize="md" lineHeight="1.6">
Workflows are reusable templates that automate image generation tasks,
allowing you to quickly perform complex operations and get consistent results.
</Text>
@@ -67,43 +67,36 @@ export const WorkflowsLaunchpadPanel = memo(() => {
isExternal
color="invokeBlue.400"
fontSize="sm"
mb={4}
>
{t('nodes.learnMore')} about creating workflows
{t('learnMore')} about creating workflows
</Link>
{/* Action Buttons */}
<Flex flexDir="column" gap={4}>
{/* Browse Workflow Templates - Updated copy per Devon's feedback */}
<LaunchpadButton onClick={handleBrowseTemplates} gap={4}>
<PiFolderOpenBold size={24} />
<Flex flexDir="column" alignItems="flex-start" flex={1}>
<Text fontWeight="semibold">Browse Workflow Templates</Text>
<Text variant="subtext" fontSize="sm">
Choose from pre-built workflows for common tasks
</Text>
<Flex flexDir="column" gap={8}>
{/* Browse Workflow Templates */}
<LaunchpadButton onClick={handleBrowseTemplates} position="relative" gap={8}>
<Icon as={PiFolderOpenBold} boxSize={8} color="base.500" />
<Flex flexDir="column" alignItems="flex-start" gap={2}>
<Heading size="sm">Browse Workflow Templates</Heading>
<Text color="base.300">Choose from pre-built workflows for common tasks</Text>
</Flex>
</LaunchpadButton>
{/* Create a new Workflow */}
<LaunchpadButton onClick={handleCreateNew} gap={4}>
<PiFilePlusBold size={24} />
<Flex flexDir="column" alignItems="flex-start" flex={1}>
<Text fontWeight="semibold">Create a new Workflow</Text>
<Text variant="subtext" fontSize="sm">
Start a new workflow from scratch
</Text>
<LaunchpadButton onClick={handleCreateNew} position="relative" gap={8}>
<Icon as={PiFilePlusBold} boxSize={8} color="base.500" />
<Flex flexDir="column" alignItems="flex-start" gap={2}>
<Heading size="sm">Create a new Workflow</Heading>
<Text color="base.300">Start a new workflow from scratch</Text>
</Flex>
</LaunchpadButton>
{/* Load workflow from existing image or file - Updated copy per Devon's feedback */}
<LaunchpadButton onClick={handleLoadFromFile} gap={4}>
<PiUploadBold size={24} />
<Flex flexDir="column" alignItems="flex-start" flex={1}>
<Text fontWeight="semibold">Load workflow from existing image or file</Text>
<Text variant="subtext" fontSize="sm">
Drag or upload a workflow to start with an existing setup
</Text>
{/* Load workflow from existing image or file */}
<LaunchpadButton onClick={handleLoadFromFile} position="relative" gap={8}>
<Icon as={PiUploadBold} boxSize={8} color="base.500" />
<Flex flexDir="column" alignItems="flex-start" gap={2}>
<Heading size="sm">Load workflow from existing image or file</Heading>
<Text color="base.300">Drag or upload a workflow to start with an existing setup</Text>
</Flex>
</LaunchpadButton>
</Flex>