mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): workflows panel redesign WIP
This commit is contained in:
@@ -1707,7 +1707,9 @@
|
||||
"copyShareLink": "Copy Share Link",
|
||||
"copyShareLinkForWorkflow": "Copy Share Link for Workflow",
|
||||
"delete": "Delete",
|
||||
"openLibrary": "Open Library",
|
||||
"builder": {
|
||||
"resetForm": "Reset Form",
|
||||
"builder": "Form Builder",
|
||||
"layout": "Layout",
|
||||
"row": "Row",
|
||||
|
||||
@@ -22,7 +22,7 @@ export const NewWorkflowButton = memo(() => {
|
||||
return (
|
||||
<IconButton
|
||||
onClick={onClickNewWorkflow}
|
||||
variant="outline"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
aria-label={t('nodes.newWorkflow')}
|
||||
tooltip={t('nodes.newWorkflow')}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const ActiveWorkflowDescription = memo(() => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Text color="base.300" fontStyle="italic" noOfLines={1}>
|
||||
<Text color="base.300" fontStyle="italic" noOfLines={1} pb={2}>
|
||||
{description}
|
||||
</Text>
|
||||
);
|
||||
|
||||
@@ -37,7 +37,7 @@ const SaveWorkflowButton = () => {
|
||||
icon={<PiFloppyDiskBold />}
|
||||
onClick={handleClickSave}
|
||||
pointerEvents="auto"
|
||||
variant="outline"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { IconButton, Popover, PopoverBody, PopoverContent, PopoverTrigger, Porta
|
||||
import { WorkflowListMenuContent } from 'features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenuContent';
|
||||
import { useWorkflowListMenu } from 'features/nodes/store/workflowListMenu';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCaretDownBold } from 'react-icons/pi';
|
||||
import { PiFolderOpenFill } from 'react-icons/pi';
|
||||
|
||||
export const WorkflowListMenuTrigger = () => {
|
||||
const workflowListMenu = useWorkflowListMenu();
|
||||
@@ -11,7 +11,13 @@ export const WorkflowListMenuTrigger = () => {
|
||||
return (
|
||||
<Popover isOpen={workflowListMenu.isOpen} onClose={workflowListMenu.close} onOpen={workflowListMenu.open}>
|
||||
<PopoverTrigger>
|
||||
<IconButton aria-label={t('stylePresets.viewList')} variant="ghost" icon={<PiCaretDownBold />} size="sm" />
|
||||
<IconButton
|
||||
aria-label={t('workflows.openLibrary')}
|
||||
tooltip={t('workflows.openLibrary')}
|
||||
variant="ghost"
|
||||
icon={<PiFolderOpenFill />}
|
||||
size="sm"
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<Portal appendToParentPortal={false}>
|
||||
<PopoverContent p={4} w={512} maxW="full" minH={512} maxH="full">
|
||||
|
||||
@@ -4,7 +4,7 @@ import { selectWorkflowMode, workflowModeChanged } from 'features/nodes/store/wo
|
||||
import type { MouseEventHandler } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiEyeBold, PiPencilBold } from 'react-icons/pi';
|
||||
import { PiEyeBold, PiPencilSimpleFill } from 'react-icons/pi';
|
||||
|
||||
export const WorkflowViewEditToggleButton = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -33,8 +33,8 @@ export const WorkflowViewEditToggleButton = memo(() => {
|
||||
aria-label={t('nodes.editMode')}
|
||||
tooltip={t('nodes.editMode')}
|
||||
onClick={onClickEdit}
|
||||
icon={<PiPencilBold />}
|
||||
variant="outline"
|
||||
icon={<PiPencilSimpleFill />}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
@@ -47,7 +47,7 @@ export const WorkflowViewEditToggleButton = memo(() => {
|
||||
tooltip={t('nodes.viewMode')}
|
||||
onClick={onClickView}
|
||||
icon={<PiEyeBold />}
|
||||
variant="outline"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Divider, Flex } from '@invoke-ai/ui-library';
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { EditModeLeftPanelContent } from 'features/nodes/components/sidePanel/EditModeLeftPanelContent';
|
||||
import { ActiveWorkflowDescription } from 'features/nodes/components/sidePanel/WorkflowListMenu/ActiveWorkflowDescription';
|
||||
@@ -15,7 +15,6 @@ const WorkflowsTabLeftPanel = () => {
|
||||
<Flex w="full" h="full" gap={2} flexDir="column">
|
||||
<ActiveWorkflowNameAndActions />
|
||||
<ActiveWorkflowDescription />
|
||||
<Divider />
|
||||
{mode === 'view' && <ViewModeLeftPanelContent />}
|
||||
{mode === 'edit' && <EditModeLeftPanelContent />}
|
||||
</Flex>
|
||||
|
||||
@@ -27,7 +27,7 @@ import type { Equals } from 'tsafe';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
const sx: SystemStyleObject = {
|
||||
gap: 2,
|
||||
gap: 4,
|
||||
flex: '1 1 0',
|
||||
'&[data-depth="0"]': {
|
||||
flex: 1,
|
||||
@@ -71,7 +71,7 @@ const ContainerElementComponentViewMode = memo(({ el }: { el: ContainerElement }
|
||||
<FormElementComponent key={childId} id={childId} />
|
||||
))}
|
||||
{children.length === 0 && (
|
||||
<Flex p={4} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Flex p={8} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Text variant="subtext">{t('workflows.builder.containerPlaceholder')}</Text>
|
||||
</Flex>
|
||||
)}
|
||||
@@ -97,7 +97,7 @@ const ContainerElementComponentEditMode = memo(({ el }: { el: ContainerElement }
|
||||
<FormElementComponent key={childId} id={childId} />
|
||||
))}
|
||||
{children.length === 0 && (
|
||||
<Flex p={4} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Flex p={8} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Text variant="subtext">{t('workflows.builder.containerPlaceholderDesc')}</Text>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { CenterOrEdge } from 'features/nodes/components/sidePanel/builder/c
|
||||
*/
|
||||
const line = {
|
||||
thickness: 2,
|
||||
backgroundColor: 'base.500',
|
||||
backgroundColor: 'base.600',
|
||||
};
|
||||
|
||||
type DropIndicatorProps = {
|
||||
|
||||
@@ -21,12 +21,12 @@ const sx: SystemStyleObject = {
|
||||
maxH: 8,
|
||||
borderTopRadius: 'base',
|
||||
alignItems: 'center',
|
||||
cursor: 'grab',
|
||||
color: 'base.300',
|
||||
bg: 'baseAlpha.250',
|
||||
'&[data-depth="0"]': { bg: 'baseAlpha.100' },
|
||||
'&[data-depth="1"]': { bg: 'baseAlpha.150' },
|
||||
'&[data-depth="2"]': { bg: 'baseAlpha.200' },
|
||||
'&[data-is-root="false"]': { cursor: 'grab' },
|
||||
};
|
||||
|
||||
export const FormElementEditModeHeader = memo(
|
||||
@@ -42,18 +42,20 @@ export const FormElementEditModeHeader = memo(
|
||||
dispatch(formElementRemoved({ id: element.id }));
|
||||
}, [dispatch, element.id, isRootElement]);
|
||||
const label = useMemo(() => {
|
||||
if (isContainerElement(element)) {
|
||||
const baseLabel = isRootElement ? 'Root Container' : 'Container';
|
||||
if (element.data.layout === 'column') {
|
||||
return `${baseLabel} (column layout)`;
|
||||
}
|
||||
return `${baseLabel} (row layout)`;
|
||||
if (isRootElement) {
|
||||
return 'Root Container';
|
||||
}
|
||||
if (isContainerElement(element) && element.data.layout === 'column') {
|
||||
return `Container (column layout)`;
|
||||
}
|
||||
if (isContainerElement(element) && element.data.layout === 'row') {
|
||||
return `Container (row layout)`;
|
||||
}
|
||||
return startCase(element.type);
|
||||
}, [element, isRootElement]);
|
||||
|
||||
return (
|
||||
<Flex ref={ref} sx={sx} data-depth={depth}>
|
||||
<Flex ref={ref} sx={sx} data-depth={depth} data-is-root={isRootElement}>
|
||||
<Text fontWeight="semibold" noOfLines={1} wordBreak="break-all">
|
||||
{label}
|
||||
</Text>
|
||||
|
||||
@@ -36,7 +36,7 @@ const innerSx: SystemStyleObject = {
|
||||
},
|
||||
'&[data-active-drop-region="center"]': {
|
||||
opacity: 1,
|
||||
bg: 'base.700',
|
||||
bg: 'base.850',
|
||||
},
|
||||
'&[data-element-type="divider"]&[data-layout="row"]': {
|
||||
w: 'min-content',
|
||||
@@ -49,8 +49,8 @@ const innerSx: SystemStyleObject = {
|
||||
const contentWrapperSx: SystemStyleObject = {
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
p: 2,
|
||||
gap: 2,
|
||||
p: 4,
|
||||
gap: 4,
|
||||
borderWidth: 1,
|
||||
borderRadius: 'base',
|
||||
borderTopRadius: 'unset',
|
||||
|
||||
@@ -54,7 +54,7 @@ const NodeFieldElementComponentViewMode = memo(({ el }: { el: NodeFieldElement }
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex id={id} className={NODE_FIELD_CLASS_NAME}>
|
||||
<Flex id={id} className={NODE_FIELD_CLASS_NAME} flex={1}>
|
||||
<FormControl flex="1 1 0" orientation="vertical">
|
||||
<Flex w="full" gap={4}>
|
||||
<FormLabel>{_label}</FormLabel>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
||||
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
||||
import { Alert, AlertDescription, AlertIcon, Button, ButtonGroup, Flex, Spacer } from '@invoke-ai/ui-library';
|
||||
import { Button, ButtonGroup, Flex, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import { firefoxDndFix } from 'features/dnd/util';
|
||||
@@ -28,19 +28,15 @@ export const WorkflowBuilder = memo(() => {
|
||||
|
||||
return (
|
||||
<Flex justifyContent="center" w="full" h="full">
|
||||
<Flex flexDir="column" w="full" maxW="768px" gap={4}>
|
||||
<Alert status="warning" variant="subtle" borderRadius="base" flexShrink={0}>
|
||||
<AlertIcon />
|
||||
<AlertDescription fontSize="sm">{t('workflows.builder.workflowBuilderAlphaWarning')}</AlertDescription>
|
||||
</Alert>
|
||||
<ButtonGroup isAttached={false} justifyContent="center">
|
||||
<Flex flexDir="column" w="full" maxW="768px" gap={2}>
|
||||
<ButtonGroup isAttached={false} justifyContent="center" size="md">
|
||||
<AddFormElementDndButton type="container" />
|
||||
<AddFormElementDndButton type="divider" />
|
||||
<AddFormElementDndButton type="heading" />
|
||||
<AddFormElementDndButton type="text" />
|
||||
<Spacer />
|
||||
<Button onClick={resetForm} variant="ghost" leftIcon={<PiArrowCounterClockwiseBold />}>
|
||||
{t('common.reset')}
|
||||
{t('workflows.builder.resetForm')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ScrollableContent>
|
||||
@@ -106,20 +102,7 @@ const AddFormElementDndButton = ({ type }: { type: Parameters<typeof useAddFormE
|
||||
const isDragging = useAddFormElementDnd(type, draggableRef);
|
||||
|
||||
return (
|
||||
<Button
|
||||
as="div"
|
||||
ref={draggableRef}
|
||||
pointerEvents="all"
|
||||
variant="unstyled"
|
||||
borderWidth={2}
|
||||
borderStyle="dashed"
|
||||
borderRadius="base"
|
||||
px={4}
|
||||
py={1}
|
||||
cursor="grab"
|
||||
_hover={{ bg: 'base.800' }}
|
||||
isDisabled={isDragging}
|
||||
>
|
||||
<Button as="div" ref={draggableRef} variant="outline" cursor="grab" borderStyle="dashed" isDisabled={isDragging}>
|
||||
{startCase(type)}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ const isFormElementDndData = (data: Record<string | symbol, unknown>): data is F
|
||||
const flashElement = (elementId: ElementId) => {
|
||||
const element = document.querySelector(`#${getEditModeWrapperId(elementId)}`);
|
||||
if (element instanceof HTMLElement) {
|
||||
triggerPostMoveFlash(element, colorTokenToCssVar('base.700'));
|
||||
triggerPostMoveFlash(element, colorTokenToCssVar('base.800'));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user