From 301cbbfdfbf5eed665756d9619ae6b5ad5a65e97 Mon Sep 17 00:00:00 2001 From: xiaotianxt Date: Thu, 6 Apr 2023 01:34:46 +0800 Subject: [PATCH] feat(dnd): add drag and drop feature --- app/components/chat-list.tsx | 125 +++++++++++++++++++++----------- app/components/home.module.scss | 2 +- app/store/app.ts | 26 +++++++ 3 files changed, 108 insertions(+), 45 deletions(-) diff --git a/app/components/chat-list.tsx b/app/components/chat-list.tsx index 8ad2b7dc..8d02805f 100644 --- a/app/components/chat-list.tsx +++ b/app/components/chat-list.tsx @@ -1,14 +1,13 @@ -import { useState, useRef, useEffect, useLayoutEffect } from "react"; import DeleteIcon from "../icons/delete.svg"; import styles from "./home.module.scss"; - import { - Message, - SubmitKey, - useChatStore, - ChatSession, - BOT_HELLO, -} from "../store"; + DragDropContext, + Droppable, + Draggable, + OnDragEndResponder, +} from "@hello-pangea/dnd"; + +import { useChatStore } from "../store"; import Locale from "../locales"; import { isMobileScreen } from "../utils"; @@ -20,54 +19,92 @@ export function ChatItem(props: { count: number; time: string; selected: boolean; + id: number; + index: number; }) { return ( -
-
{props.title}
-
-
- {Locale.ChatItem.ChatItemCount(props.count)} + + {(provided) => ( +
+
{props.title}
+
+
+ {Locale.ChatItem.ChatItemCount(props.count)} +
+
{props.time}
+
+
+ +
-
{props.time}
-
-
- -
-
+ )} + ); } export function ChatList() { - const [sessions, selectedIndex, selectSession, removeSession] = useChatStore( - (state) => [ + const [sessions, selectedIndex, selectSession, removeSession, moveSession] = + useChatStore((state) => [ state.sessions, state.currentSessionIndex, state.selectSession, state.removeSession, - ], - ); + state.moveSession, + ]); + + const onDragEnd: OnDragEndResponder = (result) => { + const { destination, source } = result; + if (!destination) { + return; + } + + if ( + destination.droppableId === source.droppableId && + destination.index === source.index + ) { + return; + } + + moveSession(source.index, destination.index); + }; return ( -
- {sessions.map((item, i) => ( - selectSession(i)} - onDelete={() => - (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) && - removeSession(i) - } - /> - ))} -
+ + + {(provided) => ( +
+ {sessions.map((item, i) => ( + selectSession(i)} + onDelete={() => + (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) && + removeSession(i) + } + /> + ))} + {provided.placeholder} +
+ )} +
+
); } diff --git a/app/components/home.module.scss b/app/components/home.module.scss index 64ac2363..da954dc1 100644 --- a/app/components/home.module.scss +++ b/app/components/home.module.scss @@ -125,7 +125,7 @@ border-radius: 10px; margin-bottom: 10px; box-shadow: var(--card-shadow); - transition: all 0.3s ease; + transition: background-color 0.3s ease; cursor: pointer; user-select: none; border: 2px solid transparent; diff --git a/app/store/app.ts b/app/store/app.ts index d01e3cdd..0a4d487d 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -189,6 +189,7 @@ interface ChatStore { currentSessionIndex: number; clearSessions: () => void; removeSession: (index: number) => void; + moveSession: (from: number, to: number) => void; selectSession: (index: number) => void; newSession: () => void; currentSession: () => ChatSession; @@ -278,6 +279,31 @@ export const useChatStore = create()( }); }, + moveSession(from: number, to: number) { + set((state) => { + const { sessions, currentSessionIndex: oldIndex } = state; + + // move the session + const newSessions = [...sessions]; + const session = newSessions[from]; + newSessions.splice(from, 1); + newSessions.splice(to, 0, session); + + // modify current session id + let newIndex = oldIndex === from ? to : oldIndex; + if (oldIndex > from && oldIndex <= to) { + newIndex -= 1; + } else if (oldIndex < from && oldIndex >= to) { + newIndex += 1; + } + + return { + currentSessionIndex: newIndex, + sessions: newSessions, + }; + }); + }, + newSession() { set((state) => ({ currentSessionIndex: 0,