feat: modularize block system (#718)
This commit is contained in:
parent
5e8cddc886
commit
38527ff92e
18 changed files with 684 additions and 604 deletions
|
|
@ -11,6 +11,7 @@ import {
|
|||
import {
|
||||
type Dispatch,
|
||||
memo,
|
||||
ReactNode,
|
||||
type SetStateAction,
|
||||
useEffect,
|
||||
useRef,
|
||||
|
|
@ -32,22 +33,16 @@ import {
|
|||
LogsIcon,
|
||||
MessageIcon,
|
||||
PenIcon,
|
||||
SparklesIcon,
|
||||
StopIcon,
|
||||
SummarizeIcon,
|
||||
} from './icons';
|
||||
import { BlockKind } from './block';
|
||||
import { blockDefinitions, BlockKind } from './block';
|
||||
import { BlockToolbarItem } from './create-block';
|
||||
import { UseChatHelpers } from 'ai/react';
|
||||
|
||||
type ToolProps = {
|
||||
type:
|
||||
| 'final-polish'
|
||||
| 'request-suggestions'
|
||||
| 'adjust-reading-level'
|
||||
| 'code-review'
|
||||
| 'add-comments'
|
||||
| 'add-logs';
|
||||
description: string;
|
||||
icon: JSX.Element;
|
||||
icon: ReactNode;
|
||||
selectedTool: string | null;
|
||||
setSelectedTool: Dispatch<SetStateAction<string | null>>;
|
||||
isToolbarVisible?: boolean;
|
||||
|
|
@ -57,10 +52,14 @@ type ToolProps = {
|
|||
message: Message | CreateMessage,
|
||||
chatRequestOptions?: ChatRequestOptions,
|
||||
) => Promise<string | null | undefined>;
|
||||
onClick: ({
|
||||
appendMessage,
|
||||
}: {
|
||||
appendMessage: UseChatHelpers['append'];
|
||||
}) => void;
|
||||
};
|
||||
|
||||
const Tool = ({
|
||||
type,
|
||||
description,
|
||||
icon,
|
||||
selectedTool,
|
||||
|
|
@ -69,14 +68,15 @@ const Tool = ({
|
|||
setIsToolbarVisible,
|
||||
isAnimating,
|
||||
append,
|
||||
onClick,
|
||||
}: ToolProps) => {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTool !== type) {
|
||||
if (selectedTool !== description) {
|
||||
setIsHovered(false);
|
||||
}
|
||||
}, [selectedTool, type]);
|
||||
}, [selectedTool, description]);
|
||||
|
||||
const handleSelect = () => {
|
||||
if (!isToolbarVisible && setIsToolbarVisible) {
|
||||
|
|
@ -86,44 +86,15 @@ const Tool = ({
|
|||
|
||||
if (!selectedTool) {
|
||||
setIsHovered(true);
|
||||
setSelectedTool(type);
|
||||
setSelectedTool(description);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedTool !== type) {
|
||||
setSelectedTool(type);
|
||||
if (selectedTool !== description) {
|
||||
setSelectedTool(description);
|
||||
} else {
|
||||
if (type === 'final-polish') {
|
||||
append({
|
||||
role: 'user',
|
||||
content:
|
||||
'Please add final polish and check for grammar, add section titles for better structure, and ensure everything reads smoothly.',
|
||||
});
|
||||
|
||||
setSelectedTool(null);
|
||||
} else if (type === 'request-suggestions') {
|
||||
append({
|
||||
role: 'user',
|
||||
content:
|
||||
'Please add suggestions you have that could improve the writing.',
|
||||
});
|
||||
|
||||
setSelectedTool(null);
|
||||
} else if (type === 'add-comments') {
|
||||
append({
|
||||
role: 'user',
|
||||
content: 'Please add comments to explain the code.',
|
||||
});
|
||||
|
||||
setSelectedTool(null);
|
||||
} else if (type === 'add-logs') {
|
||||
append({
|
||||
role: 'user',
|
||||
content: 'Please add logs to help debug the code.',
|
||||
});
|
||||
|
||||
setSelectedTool(null);
|
||||
}
|
||||
setSelectedTool(null);
|
||||
onClick({ appendMessage: append });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -132,13 +103,13 @@ const Tool = ({
|
|||
<TooltipTrigger asChild>
|
||||
<motion.div
|
||||
className={cx('p-3 rounded-full', {
|
||||
'bg-primary !text-primary-foreground': selectedTool === type,
|
||||
'bg-primary !text-primary-foreground': selectedTool === description,
|
||||
})}
|
||||
onHoverStart={() => {
|
||||
setIsHovered(true);
|
||||
}}
|
||||
onHoverEnd={() => {
|
||||
if (selectedTool !== type) setIsHovered(false);
|
||||
if (selectedTool !== description) setIsHovered(false);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
|
|
@ -158,7 +129,7 @@ const Tool = ({
|
|||
handleSelect();
|
||||
}}
|
||||
>
|
||||
{selectedTool === type ? <ArrowUpIcon /> : icon}
|
||||
{selectedTool === description ? <ArrowUpIcon /> : icon}
|
||||
</motion.div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent
|
||||
|
|
@ -283,52 +254,6 @@ const ReadingLevelSelector = ({
|
|||
);
|
||||
};
|
||||
|
||||
const toolsByBlockKind: Record<
|
||||
BlockKind,
|
||||
Array<{
|
||||
type:
|
||||
| 'final-polish'
|
||||
| 'request-suggestions'
|
||||
| 'adjust-reading-level'
|
||||
| 'code-review'
|
||||
| 'add-comments'
|
||||
| 'add-logs';
|
||||
description: string;
|
||||
icon: JSX.Element;
|
||||
}>
|
||||
> = {
|
||||
text: [
|
||||
{
|
||||
type: 'final-polish',
|
||||
description: 'Add final polish',
|
||||
icon: <PenIcon />,
|
||||
},
|
||||
{
|
||||
type: 'adjust-reading-level',
|
||||
description: 'Adjust reading level',
|
||||
icon: <SummarizeIcon />,
|
||||
},
|
||||
{
|
||||
type: 'request-suggestions',
|
||||
description: 'Request suggestions',
|
||||
icon: <MessageIcon />,
|
||||
},
|
||||
],
|
||||
code: [
|
||||
{
|
||||
type: 'add-comments',
|
||||
description: 'Add comments',
|
||||
icon: <CodeIcon />,
|
||||
},
|
||||
{
|
||||
type: 'add-logs',
|
||||
description: 'Add logs',
|
||||
icon: <LogsIcon />,
|
||||
},
|
||||
],
|
||||
image: [],
|
||||
};
|
||||
|
||||
export const Tools = ({
|
||||
isToolbarVisible,
|
||||
selectedTool,
|
||||
|
|
@ -336,7 +261,7 @@ export const Tools = ({
|
|||
append,
|
||||
isAnimating,
|
||||
setIsToolbarVisible,
|
||||
blockKind,
|
||||
tools,
|
||||
}: {
|
||||
isToolbarVisible: boolean;
|
||||
selectedTool: string | null;
|
||||
|
|
@ -347,9 +272,9 @@ export const Tools = ({
|
|||
) => Promise<string | null | undefined>;
|
||||
isAnimating: boolean;
|
||||
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
|
||||
blockKind: BlockKind;
|
||||
tools: Array<BlockToolbarItem>;
|
||||
}) => {
|
||||
const [primaryTool, ...secondaryTools] = toolsByBlockKind[blockKind];
|
||||
const [primaryTool, ...secondaryTools] = tools;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
|
|
@ -362,20 +287,19 @@ export const Tools = ({
|
|||
{isToolbarVisible &&
|
||||
secondaryTools.map((secondaryTool) => (
|
||||
<Tool
|
||||
key={secondaryTool.type}
|
||||
type={secondaryTool.type}
|
||||
key={secondaryTool.description}
|
||||
description={secondaryTool.description}
|
||||
icon={secondaryTool.icon}
|
||||
selectedTool={selectedTool}
|
||||
setSelectedTool={setSelectedTool}
|
||||
append={append}
|
||||
isAnimating={isAnimating}
|
||||
onClick={secondaryTool.onClick}
|
||||
/>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
|
||||
<Tool
|
||||
type={primaryTool.type}
|
||||
description={primaryTool.description}
|
||||
icon={primaryTool.icon}
|
||||
selectedTool={selectedTool}
|
||||
|
|
@ -384,6 +308,7 @@ export const Tools = ({
|
|||
setIsToolbarVisible={setIsToolbarVisible}
|
||||
append={append}
|
||||
isAnimating={isAnimating}
|
||||
onClick={primaryTool.onClick}
|
||||
/>
|
||||
</motion.div>
|
||||
);
|
||||
|
|
@ -451,7 +376,17 @@ const PureToolbar = ({
|
|||
}
|
||||
}, [isLoading, setIsToolbarVisible]);
|
||||
|
||||
if (toolsByBlockKind[blockKind].length === 0) {
|
||||
const blockDefinition = blockDefinitions.find(
|
||||
(definition) => definition.kind === blockKind,
|
||||
);
|
||||
|
||||
if (!blockDefinition) {
|
||||
throw new Error('Block definition not found!');
|
||||
}
|
||||
|
||||
const toolsByBlockKind = blockDefinition.toolbar;
|
||||
|
||||
if (toolsByBlockKind.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +408,7 @@ const PureToolbar = ({
|
|||
: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
height: toolsByBlockKind[blockKind].length * 50,
|
||||
height: toolsByBlockKind.length * 50,
|
||||
transition: { delay: 0 },
|
||||
scale: 1,
|
||||
}
|
||||
|
|
@ -530,7 +465,7 @@ const PureToolbar = ({
|
|||
selectedTool={selectedTool}
|
||||
setIsToolbarVisible={setIsToolbarVisible}
|
||||
setSelectedTool={setSelectedTool}
|
||||
blockKind={blockKind}
|
||||
tools={toolsByBlockKind}
|
||||
/>
|
||||
)}
|
||||
</motion.div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue