mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-12 17:55:02 -05:00
feat(ui): canvas launchpad
This commit is contained in:
@@ -26,7 +26,7 @@ import { CanvasHUD } from 'features/controlLayers/components/HUD/CanvasHUD';
|
||||
import { InvokeCanvasComponent } from 'features/controlLayers/components/InvokeCanvasComponent';
|
||||
import { SelectObject } from 'features/controlLayers/components/SelectObject/SelectObject';
|
||||
import { CanvasSessionContextProvider } from 'features/controlLayers/components/SimpleSession/context';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/InitialState';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { StagingAreaItemsList } from 'features/controlLayers/components/SimpleSession/StagingAreaItemsList';
|
||||
import { StagingAreaToolbar } from 'features/controlLayers/components/StagingArea/StagingAreaToolbar';
|
||||
import { CanvasToolbar } from 'features/controlLayers/components/Toolbar/CanvasToolbar';
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { InitialStateMainModelPicker } from './InitialStateMainModelPicker';
|
||||
import { LaunchpadAddStyleReference } from './LaunchpadAddStyleReference';
|
||||
import { LaunchpadEditImageButton } from './LaunchpadEditImageButton';
|
||||
import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButton';
|
||||
import { LaunchpadUseALayoutImageButton } from './LaunchpadUseALayoutImageButton';
|
||||
|
||||
export const CanvasLaunchpadPanel = memo(() => {
|
||||
return (
|
||||
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||
<Flex flexDir="column" w="full" h="full" gap={4} px={12} maxW={768} pt="20%">
|
||||
<Heading mb={4}>Get started with Invoke.</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="#" size="sm">
|
||||
Check our our Model Guide.
|
||||
</Button>
|
||||
</Text>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<LaunchpadGenerateFromTextButton />
|
||||
<LaunchpadAddStyleReference />
|
||||
<LaunchpadEditImageButton />
|
||||
<LaunchpadUseALayoutImageButton />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
CanvasLaunchpadPanel.displayName = 'CanvasLaunchpadPanel';
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Alert, Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { InitialStateAddAStyleReference } from 'features/controlLayers/components/SimpleSession/InitialStateAddAStyleReference';
|
||||
import { InitialStateGenerateFromText } from 'features/controlLayers/components/SimpleSession/InitialStateGenerateFromText';
|
||||
import { InitialStateMainModelPicker } from 'features/controlLayers/components/SimpleSession/InitialStateMainModelPicker';
|
||||
import { LaunchpadAddStyleReference } from 'features/controlLayers/components/SimpleSession/LaunchpadAddStyleReference';
|
||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButton';
|
||||
|
||||
export const GenerateLaunchpadPanel = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const newCanvasSession = useCallback(() => {
|
||||
@@ -28,8 +29,8 @@ export const GenerateLaunchpadPanel = memo(() => {
|
||||
</Text>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<InitialStateGenerateFromText />
|
||||
<InitialStateAddAStyleReference />
|
||||
<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?
|
||||
@@ -43,4 +44,4 @@ export const GenerateLaunchpadPanel = memo(() => {
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
GenerateLaunchpadPanel.displayName = 'InitialState';
|
||||
GenerateLaunchpadPanel.displayName = 'GenerateLaunchpad';
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Flex, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppStore } from 'app/store/nanostores/store';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import { InitialStateButtonGridItem } from 'features/controlLayers/components/SimpleSession/InitialStateButtonGridItem';
|
||||
import { LaunchpadButton } from 'features/controlLayers/components/SimpleSession/LaunchpadButton';
|
||||
import { getDefaultRefImageConfig } from 'features/controlLayers/hooks/addLayerHooks';
|
||||
import { refImageAdded } from 'features/controlLayers/store/refImagesSlice';
|
||||
import { imageDTOToImageWithDims } from 'features/controlLayers/store/util';
|
||||
@@ -13,7 +13,7 @@ import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
const dndTargetData = addGlobalReferenceImageDndTarget.getData();
|
||||
|
||||
export const InitialStateAddAStyleReference = memo(() => {
|
||||
export const LaunchpadAddStyleReference = memo(() => {
|
||||
const { dispatch, getState } = useAppStore();
|
||||
|
||||
const uploadOptions = useMemo(
|
||||
@@ -32,7 +32,7 @@ export const InitialStateAddAStyleReference = memo(() => {
|
||||
const uploadApi = useImageUploadButton(uploadOptions);
|
||||
|
||||
return (
|
||||
<InitialStateButtonGridItem {...uploadApi.getUploadButtonProps()} position="relative" gap={8}>
|
||||
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8}>
|
||||
<Icon as={PiUserCircleGearBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Add a Style Reference</Heading>
|
||||
@@ -43,7 +43,7 @@ export const InitialStateAddAStyleReference = memo(() => {
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
<DndDropTarget dndTarget={newCanvasFromImageDndTarget} dndTargetData={dndTargetData} label="Drop" />
|
||||
</InitialStateButtonGridItem>
|
||||
</LaunchpadButton>
|
||||
);
|
||||
});
|
||||
InitialStateAddAStyleReference.displayName = 'InitialStateAddAStyleReference';
|
||||
LaunchpadAddStyleReference.displayName = 'LaunchpadAddStyleReference';
|
||||
@@ -2,7 +2,7 @@ import type { ButtonProps } from '@invoke-ai/ui-library';
|
||||
import { Button, forwardRef } from '@invoke-ai/ui-library';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const InitialStateButtonGridItem = memo(
|
||||
export const LaunchpadButton = memo(
|
||||
forwardRef(({ children, ...rest }: ButtonProps, ref) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -26,4 +26,4 @@ export const InitialStateButtonGridItem = memo(
|
||||
})
|
||||
);
|
||||
|
||||
InitialStateButtonGridItem.displayName = 'InitialStateButtonGridItem';
|
||||
LaunchpadButton.displayName = 'LaunchpadButton';
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Flex, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppStore } from 'app/store/nanostores/store';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import { InitialStateButtonGridItem } from 'features/controlLayers/components/SimpleSession/InitialStateButtonGridItem';
|
||||
import { LaunchpadButton } from 'features/controlLayers/components/SimpleSession/LaunchpadButton';
|
||||
import { newCanvasFromImageDndTarget } from 'features/dnd/dnd';
|
||||
import { DndDropTarget } from 'features/dnd/DndDropTarget';
|
||||
import { newCanvasFromImage } from 'features/imageActions/actions';
|
||||
@@ -13,7 +13,7 @@ const NEW_CANVAS_OPTIONS = { type: 'raster_layer', withInpaintMask: true } as co
|
||||
|
||||
const dndTargetData = newCanvasFromImageDndTarget.getData(NEW_CANVAS_OPTIONS);
|
||||
|
||||
export const InitialStateEditImageCard = memo(() => {
|
||||
export const LaunchpadEditImageButton = memo(() => {
|
||||
const { getState, dispatch } = useAppStore();
|
||||
|
||||
const onUpload = useCallback(
|
||||
@@ -25,16 +25,18 @@ export const InitialStateEditImageCard = memo(() => {
|
||||
const uploadApi = useImageUploadButton({ allowMultiple: false, onUpload });
|
||||
|
||||
return (
|
||||
<InitialStateButtonGridItem {...uploadApi.getUploadButtonProps()}>
|
||||
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8}>
|
||||
<Icon as={PiPencilBold} boxSize={8} color="base.500" />
|
||||
<Heading size="sm">Edit Image</Heading>
|
||||
<Text color="base.300">Add an image to refine.</Text>
|
||||
<Flex w="full" justifyContent="flex-end" p={2}>
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Edit Image</Heading>
|
||||
<Text color="base.300">Add an image to refine.</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
<DndDropTarget dndTarget={newCanvasFromImageDndTarget} dndTargetData={dndTargetData} label="Drop" />
|
||||
</InitialStateButtonGridItem>
|
||||
</LaunchpadButton>
|
||||
);
|
||||
});
|
||||
InitialStateEditImageCard.displayName = 'InitialStateEditImageCard';
|
||||
LaunchpadEditImageButton.displayName = 'LaunchpadEditImageButton';
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Flex, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
||||
import { InitialStateButtonGridItem } from 'features/controlLayers/components/SimpleSession/InitialStateButtonGridItem';
|
||||
import { LaunchpadButton } from 'features/controlLayers/components/SimpleSession/LaunchpadButton';
|
||||
import { memo } from 'react';
|
||||
import { PiCursorTextBold, PiTextAaBold } from 'react-icons/pi';
|
||||
|
||||
@@ -11,9 +11,9 @@ const focusOnPrompt = () => {
|
||||
}
|
||||
};
|
||||
|
||||
export const InitialStateGenerateFromText = memo(() => {
|
||||
export const LaunchpadGenerateFromTextButton = memo(() => {
|
||||
return (
|
||||
<InitialStateButtonGridItem onClick={focusOnPrompt} position="relative" gap={8}>
|
||||
<LaunchpadButton onClick={focusOnPrompt} position="relative" gap={8}>
|
||||
<Icon as={PiTextAaBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Generate from Text</Heading>
|
||||
@@ -22,7 +22,7 @@ export const InitialStateGenerateFromText = memo(() => {
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiCursorTextBold />
|
||||
</Flex>
|
||||
</InitialStateButtonGridItem>
|
||||
</LaunchpadButton>
|
||||
);
|
||||
});
|
||||
InitialStateGenerateFromText.displayName = 'InitialStateGenerateFromText';
|
||||
LaunchpadGenerateFromTextButton.displayName = 'LaunchpadGenerateFromTextButton';
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Flex, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppStore } from 'app/store/nanostores/store';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import { InitialStateButtonGridItem } from 'features/controlLayers/components/SimpleSession/InitialStateButtonGridItem';
|
||||
import { newCanvasFromImageDndTarget } from 'features/dnd/dnd';
|
||||
import { DndDropTarget } from 'features/dnd/DndDropTarget';
|
||||
import { newCanvasFromImage } from 'features/imageActions/actions';
|
||||
@@ -9,11 +8,13 @@ import { memo, useCallback } from 'react';
|
||||
import { PiRectangleDashedBold, PiUploadBold } from 'react-icons/pi';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
import { LaunchpadButton } from './LaunchpadButton';
|
||||
|
||||
const NEW_CANVAS_OPTIONS = { type: 'control_layer', withResize: true } as const;
|
||||
|
||||
const dndTargetData = newCanvasFromImageDndTarget.getData(NEW_CANVAS_OPTIONS);
|
||||
|
||||
export const InitialStateUseALayoutImageCard = memo(() => {
|
||||
export const LaunchpadUseALayoutImageButton = memo(() => {
|
||||
const { getState, dispatch } = useAppStore();
|
||||
|
||||
const onUpload = useCallback(
|
||||
@@ -25,16 +26,18 @@ export const InitialStateUseALayoutImageCard = memo(() => {
|
||||
const uploadApi = useImageUploadButton({ allowMultiple: false, onUpload });
|
||||
|
||||
return (
|
||||
<InitialStateButtonGridItem {...uploadApi.getUploadButtonProps()}>
|
||||
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8}>
|
||||
<Icon as={PiRectangleDashedBold} boxSize={8} color="base.500" />
|
||||
<Heading size="sm">Use a Layout Image</Heading>
|
||||
<Text color="base.300">Add an image to control composition.</Text>
|
||||
<Flex w="full" justifyContent="flex-end" p={2}>
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Use a Layout Image</Heading>
|
||||
<Text color="base.300">Add an image to control composition.</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
<DndDropTarget dndTarget={newCanvasFromImageDndTarget} dndTargetData={dndTargetData} label="Drop" />
|
||||
</InitialStateButtonGridItem>
|
||||
</LaunchpadButton>
|
||||
);
|
||||
});
|
||||
InitialStateUseALayoutImageCard.displayName = 'InitialStateUseALayoutImageCard';
|
||||
LaunchpadUseALayoutImageButton.displayName = 'LaunchpadUseALayoutImageButton';
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Flex, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/InitialState';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer2';
|
||||
import { ProgressImage } from 'features/gallery/components/ImageViewer/ProgressImage2';
|
||||
import { ViewerToolbar } from 'features/gallery/components/ImageViewer/ViewerToolbar2';
|
||||
|
||||
@@ -14,14 +14,14 @@ export const CanvasToolbarResetViewButton = memo(() => {
|
||||
useRegisteredHotkeys({
|
||||
id: 'fitLayersToCanvas',
|
||||
category: 'canvas',
|
||||
callback: canvasManager.stage.fitLayersToStage,
|
||||
callback: () => canvasManager.stage.fitLayersToStage(),
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
useRegisteredHotkeys({
|
||||
id: 'fitBboxToCanvas',
|
||||
category: 'canvas',
|
||||
callback: canvasManager.stage.fitBboxToStage,
|
||||
callback: () => canvasManager.stage.fitBboxToStage(),
|
||||
options: { enabled: isCanvasFocused, preventDefault: true },
|
||||
dependencies: [isCanvasFocused],
|
||||
});
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import type { DockviewApi, GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { DockviewReact, GridviewReact, Orientation } from 'dockview';
|
||||
import { CanvasLayersPanel } from 'features/controlLayers/components/CanvasLayersPanelContent';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/InitialState';
|
||||
import { CanvasLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/CanvasLaunchpadPanel';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
|
||||
import { GalleryPanel } from 'features/gallery/components/Gallery';
|
||||
import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer/GenerationProgressPanel';
|
||||
@@ -30,7 +31,7 @@ export const dockviewComponents: IDockviewReactProps['components'] = {
|
||||
// Workflows tab
|
||||
WorkflowsLaunchpad: GenerateLaunchpadPanel,
|
||||
// Canvas tab
|
||||
CanvasLaunchpad: GenerateLaunchpadPanel,
|
||||
CanvasLaunchpad: CanvasLaunchpadPanel,
|
||||
CanvasWorkspace: CanvasWorkspacePanel,
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { CanvasHUD } from 'features/controlLayers/components/HUD/CanvasHUD';
|
||||
import { InvokeCanvasComponent } from 'features/controlLayers/components/InvokeCanvasComponent';
|
||||
import { SelectObject } from 'features/controlLayers/components/SelectObject/SelectObject';
|
||||
import { CanvasSessionContextProvider } from 'features/controlLayers/components/SimpleSession/context';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/InitialState';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { StagingAreaItemsList } from 'features/controlLayers/components/SimpleSession/StagingAreaItemsList';
|
||||
import { StagingAreaToolbar } from 'features/controlLayers/components/StagingArea/StagingAreaToolbar';
|
||||
import { CanvasToolbar } from 'features/controlLayers/components/Toolbar/CanvasToolbar';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { CanvasLayersPanel } from 'features/controlLayers/components/CanvasLayersPanelContent';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/InitialState';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
|
||||
import { GalleryPanel } from 'features/gallery/components/Gallery';
|
||||
import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer/GenerationProgressPanel';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Box, Divider, Flex } from '@invoke-ai/ui-library';
|
||||
import { $isLayoutLoading } from 'app/store/nanostores/globalIsLoading';
|
||||
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { DockviewReact, GridviewReact, Orientation } from 'dockview';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/InitialState';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
|
||||
import { GalleryPanel } from 'features/gallery/components/Gallery';
|
||||
import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer2';
|
||||
|
||||
Reference in New Issue
Block a user