mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): hide the root container frame and header
This commit is contained in:
@@ -1727,7 +1727,6 @@
|
||||
"emptyRootPlaceholderViewMode": "Click Edit to start building a form for this workflow.",
|
||||
"emptyRootPlaceholderEditMode": "Drag a form element or node field here to get started.",
|
||||
"containerPlaceholder": "Empty Container",
|
||||
"containerPlaceholderDesc": "Drag a form element or node field into this container.",
|
||||
"headingPlaceholder": "Empty Heading",
|
||||
"textPlaceholder": "Empty Text",
|
||||
"workflowBuilderAlphaWarning": "The workflow builder is currently in alpha. There may be breaking changes before the stable release."
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
useDepthContext,
|
||||
} from 'features/nodes/components/sidePanel/builder/contexts';
|
||||
import { DividerElementComponent } from 'features/nodes/components/sidePanel/builder/DividerElementComponent';
|
||||
import { useIsRootElement } from 'features/nodes/components/sidePanel/builder/dnd-hooks';
|
||||
import { FormElementEditModeWrapper } from 'features/nodes/components/sidePanel/builder/FormElementEditModeWrapper';
|
||||
import { HeadingElementComponent } from 'features/nodes/components/sidePanel/builder/HeadingElementComponent';
|
||||
import { NodeFieldElementComponent } from 'features/nodes/components/sidePanel/builder/NodeFieldElementComponent';
|
||||
@@ -83,10 +84,10 @@ const ContainerElementComponentViewMode = memo(({ el }: { el: ContainerElement }
|
||||
ContainerElementComponentViewMode.displayName = 'ContainerElementComponentViewMode';
|
||||
|
||||
const ContainerElementComponentEditMode = memo(({ el }: { el: ContainerElement }) => {
|
||||
const { t } = useTranslation();
|
||||
const depth = useDepthContext();
|
||||
const { id, data } = el;
|
||||
const { children, layout } = data;
|
||||
const isRootElement = useIsRootElement(id);
|
||||
|
||||
return (
|
||||
<FormElementEditModeWrapper element={el}>
|
||||
@@ -96,11 +97,8 @@ const ContainerElementComponentEditMode = memo(({ el }: { el: ContainerElement }
|
||||
{children.map((childId) => (
|
||||
<FormElementComponent key={childId} id={childId} />
|
||||
))}
|
||||
{children.length === 0 && (
|
||||
<Flex p={8} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Text variant="subtext">{t('workflows.builder.containerPlaceholderDesc')}</Text>
|
||||
</Flex>
|
||||
)}
|
||||
{children.length === 0 && isRootElement && <RootPlaceholder />}
|
||||
{children.length === 0 && !isRootElement && <NonRootPlaceholder />}
|
||||
</Flex>
|
||||
</ContainerContextProvider>
|
||||
</DepthContextProvider>
|
||||
@@ -109,6 +107,26 @@ const ContainerElementComponentEditMode = memo(({ el }: { el: ContainerElement }
|
||||
});
|
||||
ContainerElementComponentEditMode.displayName = 'ContainerElementComponentEditMode';
|
||||
|
||||
const RootPlaceholder = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Flex p={8} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Text variant="subtext">{t('workflows.builder.emptyRootPlaceholderEditMode')}</Text>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
RootPlaceholder.displayName = 'RootPlaceholder';
|
||||
|
||||
const NonRootPlaceholder = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Flex p={8} w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Text variant="subtext">{t('workflows.builder.containerPlaceholder')}</Text>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
NonRootPlaceholder.displayName = 'NonRootPlaceholder';
|
||||
|
||||
// TODO(psyche): Can we move this into a separate file and avoid circular dependencies between it and ContainerElementComponent?
|
||||
export const FormElementComponent = memo(({ id }: { id: string }) => {
|
||||
const el = useElement(id);
|
||||
|
||||
@@ -20,6 +20,10 @@ const wrapperSx: SystemStyleObject = {
|
||||
'&[data-element-type="divider"]&[data-layout="row"]': {
|
||||
flex: '0 1 0',
|
||||
},
|
||||
'&[data-is-root="true"]': {
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
},
|
||||
borderRadius: 'base',
|
||||
};
|
||||
|
||||
@@ -86,10 +90,21 @@ export const FormElementEditModeWrapper = memo(({ element, children }: PropsWith
|
||||
data-element-type={element.type}
|
||||
data-layout={containerCtx?.layout}
|
||||
>
|
||||
<FormElementEditModeHeader ref={dragHandleRef} element={element} />
|
||||
<Flex sx={contentWrapperSx} data-depth={depth}>
|
||||
{children}
|
||||
</Flex>
|
||||
{!isRootElement && (
|
||||
// Non-root elements get the header and content wrapper
|
||||
<>
|
||||
<FormElementEditModeHeader ref={dragHandleRef} element={element} />
|
||||
<Flex sx={contentWrapperSx} data-depth={depth}>
|
||||
{children}
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
{isRootElement && (
|
||||
// But the root does not - helps the builder to look less busy
|
||||
<Flex ref={dragHandleRef} w="full" h="full">
|
||||
{children}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
<DndListDropIndicator activeDropRegion={activeDropRegion} gap="var(--invoke-space-4)" />
|
||||
</Flex>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
||||
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
||||
import type { SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { Button, ButtonGroup, Flex, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
@@ -7,7 +8,7 @@ import { firefoxDndFix } from 'features/dnd/util';
|
||||
import { FormElementComponent } from 'features/nodes/components/sidePanel/builder/ContainerElementComponent';
|
||||
import { buildFormElementDndData, useBuilderDndMonitor } from 'features/nodes/components/sidePanel/builder/dnd-hooks';
|
||||
import { WorkflowBuilderEditMenu } from 'features/nodes/components/sidePanel/builder/WorkflowBuilderMenu';
|
||||
import { selectFormRootElementId } from 'features/nodes/store/workflowSlice';
|
||||
import { selectFormRootElementId, selectIsFormEmpty } from 'features/nodes/store/workflowSlice';
|
||||
import type { FormElement } from 'features/nodes/types/workflow';
|
||||
import { buildContainer, buildDivider, buildHeading, buildText } from 'features/nodes/types/workflow';
|
||||
import { startCase } from 'lodash-es';
|
||||
@@ -16,9 +17,19 @@ import { memo, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
const sx: SystemStyleObject = {
|
||||
pt: 3,
|
||||
'&[data-is-empty="true"]': {
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
pt: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export const WorkflowBuilder = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const rootElementId = useAppSelector(selectFormRootElementId);
|
||||
const isFormEmpty = useAppSelector(selectIsFormEmpty);
|
||||
useBuilderDndMonitor();
|
||||
|
||||
return (
|
||||
@@ -36,7 +47,7 @@ export const WorkflowBuilder = memo(() => {
|
||||
<WorkflowBuilderEditMenu />
|
||||
</ButtonGroup>
|
||||
<ScrollableContent>
|
||||
<Flex>
|
||||
<Flex sx={sx} data-is-empty={isFormEmpty}>
|
||||
<FormElementComponent id={rootElementId} />
|
||||
</Flex>
|
||||
</ScrollableContent>
|
||||
|
||||
@@ -322,7 +322,7 @@ export const useFormElementDnd = (
|
||||
draggableRef: RefObject<HTMLElement>,
|
||||
dragHandleRef: RefObject<HTMLElement>
|
||||
) => {
|
||||
const rootElementId = useAppSelector(selectFormRootElementId);
|
||||
const isRootElement = useIsRootElement(elementId);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [activeDropRegion, setActiveDropRegion] = useState<CenterOrEdge | null>(null);
|
||||
const getElement = useGetElement();
|
||||
@@ -340,7 +340,7 @@ export const useFormElementDnd = (
|
||||
firefoxDndFix(draggableElement),
|
||||
draggable({
|
||||
// Don't allow dragging the root element
|
||||
canDrag: () => elementId !== rootElementId,
|
||||
canDrag: () => !isRootElement,
|
||||
element: draggableElement,
|
||||
dragHandle: dragHandleElement,
|
||||
getInitialData: () => {
|
||||
@@ -356,7 +356,7 @@ export const useFormElementDnd = (
|
||||
}),
|
||||
dropTargetForElements({
|
||||
element: draggableElement,
|
||||
getIsSticky: () => elementId !== rootElementId,
|
||||
getIsSticky: () => !isRootElement,
|
||||
canDrop: ({ source }) =>
|
||||
isFormElementDndData(source.data) && source.data.element.id !== getElement(elementId).parentId,
|
||||
getData: ({ input }) => {
|
||||
@@ -399,7 +399,7 @@ export const useFormElementDnd = (
|
||||
},
|
||||
})
|
||||
);
|
||||
}, [dragHandleRef, draggableRef, elementId, getAllowedDropRegions, getElement, rootElementId]);
|
||||
}, [dragHandleRef, draggableRef, elementId, getAllowedDropRegions, getElement, isRootElement]);
|
||||
|
||||
return [activeDropRegion, isDragging] as const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user