diff --git a/app/components/button.module.scss b/app/components/button.module.scss
index 5b0bbe067..e7d5d8940 100644
--- a/app/components/button.module.scss
+++ b/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;
diff --git a/app/components/chat-list.tsx b/app/components/chat-list.tsx
index 8d02805f7..ab5d849f1 100644
--- a/app/components/chat-list.tsx
+++ b/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}
diff --git a/app/components/home.tsx b/app/components/home.tsx
index 9e57cb870..b6a2161d6 100644
--- a/app/components/home.tsx
+++ b/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() {
}
- onClick={() => {
- if (confirm(Locale.Home.DeleteChat)) {
- removeSession(currentIndex);
- }
- }}
+ onClick={chatStore.deleteSession}
/>
diff --git a/app/components/ui-lib.module.scss b/app/components/ui-lib.module.scss
index 95091cd0a..83eb614f7 100644
--- a/app/components/ui-lib.module.scss
+++ b/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;
}
}
-}
\ No newline at end of file
+}
diff --git a/app/components/ui-lib.tsx b/app/components/ui-lib.tsx
index 6761e7f97..a72aa868f 100644
--- a/app/components/ui-lib.tsx
+++ b/app/components/ui-lib.tsx
@@ -110,17 +110,37 @@ export function showModal(props: ModalProps) {
root.render(
);
}
-export type ToastProps = { content: string };
+export type ToastProps = {
+ content: string;
+ action?: {
+ text: string;
+ onClick: () => void;
+ };
+};
export function Toast(props: ToastProps) {
return (
-
{props.content}
+
+ {props.content}
+ {props.action && (
+
+ )}
+
);
}
-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(
);
+ root.render(
);
}
export type InputProps = React.HTMLProps
& {
diff --git a/app/locales/cn.ts b/app/locales/cn.ts
index 033e1c2cf..e21272a12 100644
--- a/app/locales/cn.ts
+++ b/app/locales/cn.ts
@@ -47,6 +47,8 @@ const cn = {
Home: {
NewChat: "新的聊天",
DeleteChat: "确认删除选中的对话?",
+ DeleteToast: "已删除会话",
+ Revert: "撤销",
},
Settings: {
Title: "设置",
diff --git a/app/locales/en.ts b/app/locales/en.ts
index aefc2e57c..61d20b60f 100644
--- a/app/locales/en.ts
+++ b/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",
diff --git a/app/locales/es.ts b/app/locales/es.ts
index 6997d5f6d..5a83cb55c 100644
--- a/app/locales/es.ts
+++ b/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",
diff --git a/app/locales/it.ts b/app/locales/it.ts
index 95e6747ba..7108090eb 100644
--- a/app/locales/it.ts
+++ b/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",
diff --git a/app/locales/tw.ts b/app/locales/tw.ts
index 4340fe2c8..ff1794b55 100644
--- a/app/locales/tw.ts
+++ b/app/locales/tw.ts
@@ -48,6 +48,8 @@ const tw: LocaleType = {
Home: {
NewChat: "新的對話",
DeleteChat: "確定要刪除選取的對話嗎?",
+ DeleteToast: "已刪除對話",
+ Revert: "撤銷",
},
Settings: {
Title: "設定",
diff --git a/app/store/app.ts b/app/store/app.ts
index c63fa9d4f..e72163ebb 100644
--- a/app/store/app.ts
+++ b/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;
@@ -324,6 +326,26 @@ export const useChatStore = create()(
}));
},
+ 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;