From fb98050d9f8ea593377aa48bd2f612b212602d61 Mon Sep 17 00:00:00 2001 From: legao <837937787@qq.com> Date: Fri, 14 Jul 2023 18:08:03 +0800 Subject: [PATCH] feat: drag and drop in contextual prompts --- app/components/mask.tsx | 154 ++++++++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 53 deletions(-) diff --git a/app/components/mask.tsx b/app/components/mask.tsx index 091f3cdf..6ff38bc3 100644 --- a/app/components/mask.tsx +++ b/app/components/mask.tsx @@ -42,6 +42,20 @@ import { ModelConfigList } from "./model-config"; import { FileName, Path } from "../constant"; import { BUILTIN_MASK_STORE } from "../masks"; import { nanoid } from "nanoid"; +import { + DragDropContext, + Droppable, + Draggable, + OnDragEndResponder, +} from "@hello-pangea/dnd"; + +// drag and drop helper function +function reorder(list: T[], startIndex: number, endIndex: number): T[] { + const result = [...list]; + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + return result; +} export function MaskAvatar(props: { mask: Mask }) { return props.mask.avatar !== DEFAULT_MASK_AVATAR ? ( @@ -192,6 +206,7 @@ export function MaskConfig(props: { } function ContextPromptItem(props: { + index: number; prompt: ChatMessage; update: (prompt: ChatMessage) => void; remove: () => void; @@ -199,53 +214,62 @@ function ContextPromptItem(props: { const [focusingInput, setFocusingInput] = useState(false); return ( -
- {!focusingInput && ( - + {!focusingInput && ( + + )} + setFocusingInput(true)} + onBlur={() => { + setFocusingInput(false); + // If the selection is not removed when the user loses focus, some + // extensions like "Translate" will always display a floating bar + window?.getSelection()?.removeAllRanges(); + }} + onInput={(e) => + props.update({ + ...props.prompt, + content: e.currentTarget.value as any, + }) + } + /> + {!focusingInput && ( + } + className={chatStyle["context-delete-button"]} + onClick={() => props.remove()} + bordered + /> + )} +
)} - setFocusingInput(true)} - onBlur={() => { - setFocusingInput(false); - // If the selection is not removed when the user loses focus, some - // extensions like "Translate" will always display a floating bar - window?.getSelection()?.removeAllRanges(); - }} - onInput={(e) => - props.update({ - ...props.prompt, - content: e.currentTarget.value as any, - }) - } - /> - {!focusingInput && ( - } - className={chatStyle["context-delete-button"]} - onClick={() => props.remove()} - bordered - /> - )} - + ); } @@ -267,17 +291,41 @@ export function ContextPrompts(props: { props.updateContext((context) => (context[i] = prompt)); }; + const onDragEnd: OnDragEndResponder = (result) => { + if (!result.destination) { + return; + } + const newContext = reorder( + context, + result.source.index, + result.destination.index, + ); + props.updateContext((context) => { + context.splice(0, context.length, ...newContext); + }); + }; + return ( <>
- {context.map((c, i) => ( - updateContextPrompt(i, prompt)} - remove={() => removeContextPrompt(i)} - /> - ))} + + + {(provided) => ( +
+ {context.map((c, i) => ( + updateContextPrompt(i, prompt)} + remove={() => removeContextPrompt(i)} + /> + ))} + {provided.placeholder} +
+ )} +
+