Browse Source

feat: #499 revert delete session

Yidadaa 2 years ago
parent
commit
5952064362

+ 1 - 1
app/components/button.module.scss

@@ -12,7 +12,7 @@
   user-select: none;
   outline: none;
   border: none;
-  color: rgb(51, 51, 51);
+  color: var(--black);
 
   &[disabled] {
     cursor: not-allowed;

+ 2 - 4
app/components/chat-list.tsx

@@ -59,6 +59,7 @@ export function ChatList() {
       state.removeSession,
       state.moveSession,
     ]);
+  const chatStore = useChatStore();
 
   const onDragEnd: OnDragEndResponder = (result) => {
     const { destination, source } = result;
@@ -95,10 +96,7 @@ export function ChatList() {
                 index={i}
                 selected={i === selectedIndex}
                 onClick={() => selectSession(i)}
-                onDelete={() =>
-                  (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) &&
-                  removeSession(i)
-                }
+                onDelete={chatStore.deleteSession}
               />
             ))}
             {provided.placeholder}

+ 2 - 5
app/components/home.tsx

@@ -93,6 +93,7 @@ function _Home() {
       state.removeSession,
     ],
   );
+  const chatStore = useChatStore();
   const loading = !useHasHydrated();
   const [showSideBar, setShowSideBar] = useState(true);
 
@@ -142,11 +143,7 @@ function _Home() {
             <div className={styles["sidebar-action"] + " " + styles.mobile}>
               <IconButton
                 icon={<CloseIcon />}
-                onClick={() => {
-                  if (confirm(Locale.Home.DeleteChat)) {
-                    removeSession(currentIndex);
-                  }
-                }}
+                onClick={chatStore.deleteSession}
               />
             </div>
             <div className={styles["sidebar-action"]}>

+ 18 - 2
app/components/ui-lib.module.scss

@@ -135,9 +135,25 @@
     box-shadow: var(--card-shadow);
     border: var(--border-in-light);
     color: var(--black);
-    padding: 10px 30px;
+    padding: 10px 20px;
     border-radius: 50px;
     margin-bottom: 20px;
+    display: flex;
+    align-items: center;
+
+    .toast-action {
+      padding-left: 20px;
+      color: var(--primary);
+      opacity: 0.8;
+      border: 0;
+      background: none;
+      cursor: pointer;
+      font-family: inherit;
+
+      &:hover {
+        opacity: 1;
+      }
+    }
   }
 }
 
@@ -160,4 +176,4 @@
       max-height: 50vh;
     }
   }
-}
+}

+ 24 - 4
app/components/ui-lib.tsx

@@ -110,17 +110,37 @@ export function showModal(props: ModalProps) {
   root.render(<Modal {...props} onClose={closeModal}></Modal>);
 }
 
-export type ToastProps = { content: string };
+export type ToastProps = {
+  content: string;
+  action?: {
+    text: string;
+    onClick: () => void;
+  };
+};
 
 export function Toast(props: ToastProps) {
   return (
     <div className={styles["toast-container"]}>
-      <div className={styles["toast-content"]}>{props.content}</div>
+      <div className={styles["toast-content"]}>
+        <span>{props.content}</span>
+        {props.action && (
+          <button
+            onClick={props.action.onClick}
+            className={styles["toast-action"]}
+          >
+            {props.action.text}
+          </button>
+        )}
+      </div>
     </div>
   );
 }
 
-export function showToast(content: string, delay = 3000) {
+export function showToast(
+  content: string,
+  action?: ToastProps["action"],
+  delay = 3000,
+) {
   const div = document.createElement("div");
   div.className = styles.show;
   document.body.appendChild(div);
@@ -139,7 +159,7 @@ export function showToast(content: string, delay = 3000) {
     close();
   }, delay);
 
-  root.render(<Toast content={content} />);
+  root.render(<Toast content={content} action={action} />);
 }
 
 export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {

+ 2 - 0
app/locales/cn.ts

@@ -47,6 +47,8 @@ const cn = {
   Home: {
     NewChat: "新的聊天",
     DeleteChat: "确认删除选中的对话?",
+    DeleteToast: "已删除会话",
+    Revert: "撤销",
   },
   Settings: {
     Title: "设置",

+ 2 - 0
app/locales/en.ts

@@ -50,6 +50,8 @@ const en: LocaleType = {
   Home: {
     NewChat: "New Chat",
     DeleteChat: "Confirm to delete the selected conversation?",
+    DeleteToast: "Chat Deleted",
+    Revert: "Revert",
   },
   Settings: {
     Title: "Settings",

+ 2 - 0
app/locales/es.ts

@@ -50,6 +50,8 @@ const es: LocaleType = {
   Home: {
     NewChat: "Nuevo chat",
     DeleteChat: "¿Confirmar eliminación de la conversación seleccionada?",
+    DeleteToast: "Chat Deleted",
+    Revert: "Revert",
   },
   Settings: {
     Title: "Configuración",

+ 2 - 0
app/locales/it.ts

@@ -50,6 +50,8 @@ const it: LocaleType = {
   Home: {
     NewChat: "Nuova Chat",
     DeleteChat: "Confermare la cancellazione della conversazione selezionata?",
+    DeleteToast: "Chat Deleted",
+    Revert: "Revert",
   },
   Settings: {
     Title: "Impostazioni",

+ 2 - 0
app/locales/tw.ts

@@ -48,6 +48,8 @@ const tw: LocaleType = {
   Home: {
     NewChat: "新的對話",
     DeleteChat: "確定要刪除選取的對話嗎?",
+    DeleteToast: "已刪除對話",
+    Revert: "撤銷",
   },
   Settings: {
     Title: "設定",

+ 23 - 1
app/store/app.ts

@@ -7,9 +7,10 @@ import {
   requestChatStream,
   requestWithPrompt,
 } from "../requests";
-import { trimTopic } from "../utils";
+import { isMobileScreen, trimTopic } from "../utils";
 
 import Locale from "../locales";
+import { showToast } from "../components/ui-lib";
 
 export type Message = ChatCompletionResponseMessage & {
   date: string;
@@ -204,6 +205,7 @@ interface ChatStore {
   moveSession: (from: number, to: number) => void;
   selectSession: (index: number) => void;
   newSession: () => void;
+  deleteSession: () => void;
   currentSession: () => ChatSession;
   onNewMessage: (message: Message) => void;
   onUserInput: (content: string) => Promise<void>;
@@ -324,6 +326,26 @@ export const useChatStore = create<ChatStore>()(
         }));
       },
 
+      deleteSession() {
+        const deletedSession = get().currentSession();
+        const index = get().currentSessionIndex;
+        const isLastSession = get().sessions.length === 1;
+        if (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) {
+          get().removeSession(index);
+        }
+        showToast(Locale.Home.DeleteToast, {
+          text: Locale.Home.Revert,
+          onClick() {
+            set((state) => ({
+              sessions: state.sessions
+                .slice(0, index)
+                .concat([deletedSession])
+                .concat(state.sessions.slice(index + Number(isLastSession))),
+            }));
+          },
+        });
+      },
+
       currentSession() {
         let index = get().currentSessionIndex;
         const sessions = get().sessions;