mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-14 00:04:59 -05:00
feat(ui): add launchpad container component
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||
import { Button, Flex, Grid, Text } from '@invoke-ai/ui-library';
|
||||
import { navigationApi } from 'features/ui/layouts/navigation-api';
|
||||
import { WORKSPACE_PANEL_ID } from 'features/ui/layouts/shared';
|
||||
import { memo, useCallback } from 'react';
|
||||
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { InitialStateMainModelPicker } from './InitialStateMainModelPicker';
|
||||
import { LaunchpadAddStyleReference } from './LaunchpadAddStyleReference';
|
||||
import { LaunchpadContainer } from './LaunchpadContainer';
|
||||
import { LaunchpadEditImageButton } from './LaunchpadEditImageButton';
|
||||
import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButton';
|
||||
import { LaunchpadUseALayoutImageButton } from './LaunchpadUseALayoutImageButton';
|
||||
@@ -16,35 +17,30 @@ export const CanvasLaunchpadPanel = memo(() => {
|
||||
navigationApi.focusPanel('canvas', WORKSPACE_PANEL_ID);
|
||||
}, []);
|
||||
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}>{t('ui.launchpad.canvasTitle')}</Heading>
|
||||
<Flex flexDir="column" gap={8}>
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
|
||||
<InitialStateMainModelPicker />
|
||||
<Flex flexDir="column" gap={2} justifyContent="center">
|
||||
<Text>
|
||||
{t('ui.launchpad.modelGuideText')}{' '}
|
||||
<Button
|
||||
as="a"
|
||||
variant="link"
|
||||
href="https://support.invoke.ai/support/solutions/articles/151000216086-model-guide"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
{t('ui.launchpad.modelGuideLink')}
|
||||
</Button>
|
||||
</Text>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<LaunchpadGenerateFromTextButton extraAction={focusCanvas} />
|
||||
<LaunchpadAddStyleReference extraAction={focusCanvas} />
|
||||
<LaunchpadEditImageButton extraAction={focusCanvas} />
|
||||
<LaunchpadUseALayoutImageButton extraAction={focusCanvas} />
|
||||
<LaunchpadContainer heading={t('ui.launchpad.canvasTitle')}>
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
|
||||
<InitialStateMainModelPicker />
|
||||
<Flex flexDir="column" gap={2} justifyContent="center">
|
||||
<Text>
|
||||
{t('ui.launchpad.modelGuideText')}{' '}
|
||||
<Button
|
||||
as="a"
|
||||
variant="link"
|
||||
href="https://support.invoke.ai/support/solutions/articles/151000216086-model-guide"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
{t('ui.launchpad.modelGuideLink')}
|
||||
</Button>
|
||||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<LaunchpadGenerateFromTextButton extraAction={focusCanvas} />
|
||||
<LaunchpadAddStyleReference extraAction={focusCanvas} />
|
||||
<LaunchpadEditImageButton extraAction={focusCanvas} />
|
||||
<LaunchpadUseALayoutImageButton extraAction={focusCanvas} />
|
||||
</LaunchpadContainer>
|
||||
);
|
||||
});
|
||||
CanvasLaunchpadPanel.displayName = 'CanvasLaunchpadPanel';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Alert, Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||
import { Alert, Button, Flex, Grid, Text } from '@invoke-ai/ui-library';
|
||||
import { InitialStateMainModelPicker } from 'features/controlLayers/components/SimpleSession/InitialStateMainModelPicker';
|
||||
import { LaunchpadAddStyleReference } from 'features/controlLayers/components/SimpleSession/LaunchpadAddStyleReference';
|
||||
import { navigationApi } from 'features/ui/layouts/navigation-api';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
import { LaunchpadContainer } from './LaunchpadContainer';
|
||||
import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButton';
|
||||
|
||||
export const GenerateLaunchpadPanel = memo(() => {
|
||||
@@ -12,41 +13,36 @@ 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>
|
||||
<Flex flexDir="column" gap={8}>
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
|
||||
<InitialStateMainModelPicker />
|
||||
<Flex flexDir="column" gap={2} justifyContent="center">
|
||||
<Text>
|
||||
Want to learn what prompts work best for each model?{' '}
|
||||
<Button
|
||||
as="a"
|
||||
variant="link"
|
||||
href="https://support.invoke.ai/support/solutions/articles/151000216086-model-guide"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
Check out our Model Guide.
|
||||
</Button>
|
||||
</Text>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<LaunchpadGenerateFromTextButton />
|
||||
<LaunchpadAddStyleReference />
|
||||
<Alert status="info" borderRadius="base" flexDir="column" gap={2} overflow="unset">
|
||||
<Text fontSize="md" fontWeight="semibold">
|
||||
Looking to get more control, edit, and iterate on your images?
|
||||
</Text>
|
||||
<Button variant="link" onClick={newCanvasSession}>
|
||||
Navigate to Canvas for more capabilities.
|
||||
<LaunchpadContainer heading="Generate images from text prompts.">
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
|
||||
<InitialStateMainModelPicker />
|
||||
<Flex flexDir="column" gap={2} justifyContent="center">
|
||||
<Text>
|
||||
Want to learn what prompts work best for each model?{' '}
|
||||
<Button
|
||||
as="a"
|
||||
variant="link"
|
||||
href="https://support.invoke.ai/support/solutions/articles/151000216086-model-guide"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
Check out our Model Guide.
|
||||
</Button>
|
||||
</Alert>
|
||||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<LaunchpadGenerateFromTextButton />
|
||||
<LaunchpadAddStyleReference />
|
||||
<Alert status="info" borderRadius="base" flexDir="column" gap={2} overflow="unset">
|
||||
<Text fontSize="md" fontWeight="semibold">
|
||||
Looking to get more control, edit, and iterate on your images?
|
||||
</Text>
|
||||
<Button variant="link" onClick={newCanvasSession}>
|
||||
Navigate to Canvas for more capabilities.
|
||||
</Button>
|
||||
</Alert>
|
||||
</LaunchpadContainer>
|
||||
);
|
||||
});
|
||||
GenerateLaunchpadPanel.displayName = 'GenerateLaunchpad';
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Flex, Heading } from '@invoke-ai/ui-library';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const LaunchpadContainer = memo((props: PropsWithChildren<{ heading: string }>) => {
|
||||
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}>{props.heading}</Heading>
|
||||
<Flex flexDir="column" gap={8}>
|
||||
{props.children}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
LaunchpadContainer.displayName = 'LaunchpadContainer';
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
import { LaunchpadButton } from './LaunchpadButton';
|
||||
import { LaunchpadContainer } from './LaunchpadContainer';
|
||||
|
||||
export const UpscalingLaunchpadPanel = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
@@ -65,108 +66,104 @@ export const UpscalingLaunchpadPanel = memo(() => {
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||
<Flex flexDir="column" w="full" gap={8} px={14} maxW={768} pt="20vh">
|
||||
<Heading>{t('ui.launchpad.upscalingTitle')}</Heading>
|
||||
|
||||
{/* 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">{t('ui.launchpad.upscaling.uploadImage.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.upscaling.uploadImage.description')}</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Icon as={PiImageBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">{t('ui.launchpad.upscaling.replaceImage.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.upscaling.replaceImage.description')}</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
<DndDropTarget
|
||||
dndTarget={setUpscaleInitialImageDndTarget}
|
||||
dndTargetData={dndTargetData}
|
||||
label={t('gallery.drop')}
|
||||
/>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Guidance text */}
|
||||
{upscaleInitialImage && (
|
||||
<Flex bg="base.800" p={4} borderRadius="base" border="1px solid" borderColor="base.700">
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
<strong>{t('ui.launchpad.upscaling.readyToUpscale.title')}</strong>{' '}
|
||||
{t('ui.launchpad.upscaling.readyToUpscale.description')}
|
||||
</Text>
|
||||
</Flex>
|
||||
<LaunchpadContainer heading={t('ui.launchpad.upscalingTitle')}>
|
||||
{/* 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">{t('ui.launchpad.upscaling.uploadImage.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.upscaling.uploadImage.description')}</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Icon as={PiImageBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">{t('ui.launchpad.upscaling.replaceImage.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.upscaling.replaceImage.description')}</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
<DndDropTarget
|
||||
dndTarget={setUpscaleInitialImageDndTarget}
|
||||
dndTargetData={dndTargetData}
|
||||
label={t('gallery.drop')}
|
||||
/>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Controls */}
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8} alignItems="start">
|
||||
{/* Left Column: Creativity and Structural Defaults */}
|
||||
<Box>
|
||||
<Text fontWeight="semibold" fontSize="sm" mb={3}>
|
||||
Creativity & Structure Defaults
|
||||
</Text>
|
||||
<ButtonGroup size="sm" orientation="vertical" variant="outline" w="full">
|
||||
<Button
|
||||
colorScheme={creativity === -5 && structure === 5 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onConservativeClick}
|
||||
leftIcon={<PiShieldCheckBold />}
|
||||
>
|
||||
Conservative
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme={creativity === 0 && structure === 0 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onBalancedClick}
|
||||
leftIcon={<PiScalesBold />}
|
||||
>
|
||||
Balanced
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme={creativity === 5 && structure === -2 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onCreativeClick}
|
||||
leftIcon={<PiPaletteBold />}
|
||||
>
|
||||
Creative
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme={creativity === 8 && structure === -5 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onArtisticClick}
|
||||
leftIcon={<PiSparkleBold />}
|
||||
>
|
||||
Artistic
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Box>
|
||||
{/* Right Column: Description/help text */}
|
||||
<Box>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
{t('ui.launchpad.upscaling.helpText.promptAdvice')}
|
||||
</Text>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6" mt={3}>
|
||||
{t('ui.launchpad.upscaling.helpText.styleAdvice')}
|
||||
</Text>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</Flex>
|
||||
{/* Guidance text */}
|
||||
{upscaleInitialImage && (
|
||||
<Flex bg="base.800" p={4} borderRadius="base" border="1px solid" borderColor="base.700">
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
<strong>{t('ui.launchpad.upscaling.readyToUpscale.title')}</strong>{' '}
|
||||
{t('ui.launchpad.upscaling.readyToUpscale.description')}
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{/* Controls */}
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8} alignItems="start">
|
||||
{/* Left Column: Creativity and Structural Defaults */}
|
||||
<Box>
|
||||
<Text fontWeight="semibold" fontSize="sm" mb={3}>
|
||||
Creativity & Structure Defaults
|
||||
</Text>
|
||||
<ButtonGroup size="sm" orientation="vertical" variant="outline" w="full">
|
||||
<Button
|
||||
colorScheme={creativity === -5 && structure === 5 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onConservativeClick}
|
||||
leftIcon={<PiShieldCheckBold />}
|
||||
>
|
||||
Conservative
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme={creativity === 0 && structure === 0 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onBalancedClick}
|
||||
leftIcon={<PiScalesBold />}
|
||||
>
|
||||
Balanced
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme={creativity === 5 && structure === -2 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onCreativeClick}
|
||||
leftIcon={<PiPaletteBold />}
|
||||
>
|
||||
Creative
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme={creativity === 8 && structure === -5 ? 'invokeBlue' : undefined}
|
||||
justifyContent="center"
|
||||
onClick={onArtisticClick}
|
||||
leftIcon={<PiSparkleBold />}
|
||||
>
|
||||
Artistic
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Box>
|
||||
{/* Right Column: Description/help text */}
|
||||
<Box>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
{t('ui.launchpad.upscaling.helpText.promptAdvice')}
|
||||
</Text>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6" mt={3}>
|
||||
{t('ui.launchpad.upscaling.helpText.styleAdvice')}
|
||||
</Text>
|
||||
</Box>
|
||||
</Grid>
|
||||
</LaunchpadContainer>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { PiFilePlusBold, PiFolderOpenBold, PiUploadBold } from 'react-icons/pi';
|
||||
|
||||
import { LaunchpadButton } from './LaunchpadButton';
|
||||
import { LaunchpadContainer } from './LaunchpadContainer';
|
||||
|
||||
export const WorkflowsLaunchpadPanel = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
@@ -45,63 +46,59 @@ export const WorkflowsLaunchpadPanel = 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>{t('ui.launchpad.workflowsTitle')}</Heading>
|
||||
<LaunchpadContainer heading={t('ui.launchpad.workflowsTitle')}>
|
||||
{/* Description */}
|
||||
<Text variant="subtext" fontSize="md" lineHeight="1.6">
|
||||
{t('ui.launchpad.workflows.description')}
|
||||
</Text>
|
||||
|
||||
{/* Description */}
|
||||
<Text variant="subtext" fontSize="md" lineHeight="1.6">
|
||||
{t('ui.launchpad.workflows.description')}
|
||||
</Text>
|
||||
<Text>
|
||||
<Button
|
||||
as="a"
|
||||
variant="link"
|
||||
href="https://support.invoke.ai/support/solutions/articles/151000189610-getting-started-with-workflows-denoise-latents"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
{t('ui.launchpad.workflows.learnMoreLink')}
|
||||
</Button>
|
||||
</Text>
|
||||
|
||||
<Text>
|
||||
<Button
|
||||
as="a"
|
||||
variant="link"
|
||||
href="https://support.invoke.ai/support/solutions/articles/151000189610-getting-started-with-workflows-denoise-latents"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
{t('ui.launchpad.workflows.learnMoreLink')}
|
||||
</Button>
|
||||
</Text>
|
||||
{/* Action Buttons */}
|
||||
<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">{t('ui.launchpad.workflows.browseTemplates.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.workflows.browseTemplates.description')}</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<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">{t('ui.launchpad.workflows.browseTemplates.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.workflows.browseTemplates.description')}</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
{/* Create a new Workflow */}
|
||||
<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">{t('ui.launchpad.workflows.createNew.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.workflows.createNew.description')}</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Create a new Workflow */}
|
||||
<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">{t('ui.launchpad.workflows.createNew.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.workflows.createNew.description')}</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Load workflow from existing image or file */}
|
||||
<LaunchpadButton {...uploadApi.getRootProps()} position="relative" gap={8}>
|
||||
<Icon as={PiUploadBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">{t('ui.launchpad.workflows.loadFromFile.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.workflows.loadFromFile.description')}</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getInputProps()} />
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
</Flex>
|
||||
{/* Load workflow from existing image or file */}
|
||||
<LaunchpadButton {...uploadApi.getRootProps()} position="relative" gap={8}>
|
||||
<Icon as={PiUploadBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">{t('ui.launchpad.workflows.loadFromFile.title')}</Heading>
|
||||
<Text color="base.300">{t('ui.launchpad.workflows.loadFromFile.description')}</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getInputProps()} />
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</LaunchpadContainer>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user