feat(ui): rough out regional prompts components

This commit is contained in:
psychedelicious 2024-04-05 17:03:37 +11:00 committed by Kent Keirsey
parent 1d1e4d02dc
commit f87eee810b
6 changed files with 161 additions and 0 deletions

View File

@ -0,0 +1,23 @@
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { useTransform } from 'features/regionalPrompts/hooks/useTransform';
import type { LineObject } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { Line } from 'react-konva';
type Props = {
line: LineObject;
};
export const LineComponent = ({ line }: Props) => {
const { shapeRef } = useTransform(line);
return (
<Line
ref={shapeRef}
key={line.id}
points={line.points}
stroke={rgbaColorToString(line.color)}
strokeWidth={line.strokeWidth}
draggable
/>
);
};

View File

@ -0,0 +1,25 @@
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { useTransform } from 'features/regionalPrompts/hooks/useTransform';
import type { FillRectObject } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { Rect } from 'react-konva';
type Props = {
rect: FillRectObject;
};
export const RectComponent = ({ rect }: Props) => {
const { shapeRef } = useTransform(rect);
return (
<Rect
ref={shapeRef}
key={rect.id}
x={rect.x}
y={rect.y}
width={rect.width}
height={rect.height}
fill={rgbaColorToString(rect.color)}
draggable
/>
);
};

View File

@ -0,0 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react';
import { RegionalPromptsEditor } from 'features/regionalPrompts/components/RegionalPromptsEditor';
const meta: Meta<typeof RegionalPromptsEditor> = {
title: 'Feature/RegionalPrompts',
tags: ['autodocs'],
component: RegionalPromptsEditor,
};
export default meta;
type Story = StoryObj<typeof RegionalPromptsEditor>;
const Component = () => {
return <RegionalPromptsEditor />;
};
export const Default: Story = {
render: Component,
};

View File

@ -0,0 +1,25 @@
import { Flex } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { RegionalPromptsStage } from 'features/regionalPrompts/components/RegionalPromptsStage';
import { layersSelectors, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
const selectLayers = createSelector(selectRegionalPromptsSlice, (regionalPrompts) =>
layersSelectors.selectAll(regionalPrompts)
);
export const RegionalPromptsEditor = () => {
const layers = useAppSelector(selectLayers);
return (
<Flex>
<Flex flexBasis={1}>
{layers.map((layer) => (
<Flex key={layer.id}>{layer.prompt}</Flex>
))}
</Flex>
<Flex flexBasis={1}>
<RegionalPromptsStage />
</Flex>
</Flex>
);
};

View File

@ -0,0 +1,39 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { LineComponent } from 'features/regionalPrompts/components/LineComponent';
import { RectComponent } from 'features/regionalPrompts/components/RectComponent';
import {
layerObjectsSelectors,
layersSelectors,
selectRegionalPromptsSlice,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
import { memo } from 'react';
import { Group, Layer, Stage } from 'react-konva';
const selectLayers = createSelector(selectRegionalPromptsSlice, (regionalPrompts) =>
layersSelectors.selectAll(regionalPrompts)
);
export const RegionalPromptsStage: React.FC = memo(() => {
const layers = useAppSelector(selectLayers);
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
{layers.map((layer) => (
<Group key={layer.id}>
{layerObjectsSelectors.selectAll(layer.objects).map((obj) => {
if (obj.kind === 'line') {
return <LineComponent key={obj.id} line={obj} />;
}
if (obj.kind === 'fillRect') {
return <RectComponent key={obj.id} rect={obj} />;
}
})}
</Group>
))}
</Layer>
</Stage>
);
});
RegionalPromptsStage.displayName = 'RegionalPromptingEditor';

View File

@ -0,0 +1,30 @@
import type { FillRectObject, LayerObject, LineObject } from 'features/regionalPrompts/store/regionalPromptsSlice';
import type { Image } from 'konva/lib/shapes/Image';
import type { Line } from 'konva/lib/shapes/Line';
import type { Rect } from 'konva/lib/shapes/Rect';
import type { Transformer } from 'konva/lib/shapes/Transformer';
import { useEffect, useRef } from 'react';
type ShapeType<T> = T extends LineObject ? Line : T extends FillRectObject ? Rect : Image;
export const useTransform = <TObject extends LayerObject>(object: TObject) => {
const shapeRef = useRef<ShapeType<TObject>>(null);
const transformerRef = useRef<Transformer>(null);
useEffect(() => {
if (!object.isSelected) {
return;
}
if (!transformerRef.current || !shapeRef.current) {
return;
}
if (object.isSelected) {
transformerRef.current.nodes([shapeRef.current]);
transformerRef.current.getLayer()?.batchDraw();
}
}, [object.isSelected]);
return { shapeRef, transformerRef };
};