mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-01 23:56:39 +08:00
feat: support for renaming topics(title) #112
This commit is contained in:
parent
067121d968
commit
b0e7cb4eff
@ -1,6 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useRef, useEffect, useLayoutEffect } from "react";
|
import {
|
||||||
|
useState,
|
||||||
|
useRef,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
ChangeEvent,
|
||||||
|
} from "react";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
|
||||||
import { IconButton } from "./button";
|
import { IconButton } from "./button";
|
||||||
@ -74,6 +80,16 @@ export function ChatItem(props: {
|
|||||||
time: string;
|
time: string;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const [updateTitle] = useChatStore((state) => [state.updateTitle]);
|
||||||
|
const [title, setTitle] = useState(props.title);
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
|
const handleInputBlur = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (e.target.value.length == 0) setTitle(props.title);
|
||||||
|
setIsEditing(false);
|
||||||
|
updateTitle(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${styles["chat-item"]} ${
|
className={`${styles["chat-item"]} ${
|
||||||
@ -81,7 +97,20 @@ export function ChatItem(props: {
|
|||||||
}`}
|
}`}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
>
|
>
|
||||||
<div className={styles["chat-item-title"]}>{props.title}</div>
|
<div
|
||||||
|
className={styles["chat-item-title"]}
|
||||||
|
onDoubleClick={() => setIsEditing(true)}
|
||||||
|
>
|
||||||
|
{isEditing ? (
|
||||||
|
<input
|
||||||
|
value={title}
|
||||||
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
|
onBlur={handleInputBlur}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
title
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className={styles["chat-item-info"]}>
|
<div className={styles["chat-item-info"]}>
|
||||||
<div className={styles["chat-item-count"]}>
|
<div className={styles["chat-item-count"]}>
|
||||||
{Locale.ChatItem.ChatItemCount(props.count)}
|
{Locale.ChatItem.ChatItemCount(props.count)}
|
||||||
@ -102,7 +131,7 @@ export function ChatList() {
|
|||||||
state.currentSessionIndex,
|
state.currentSessionIndex,
|
||||||
state.selectSession,
|
state.selectSession,
|
||||||
state.removeSession,
|
state.removeSession,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -194,7 +223,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
setPromptHints(promptStore.search(text));
|
setPromptHints(promptStore.search(text));
|
||||||
},
|
},
|
||||||
100,
|
100,
|
||||||
{ leading: true, trailing: true }
|
{ leading: true, trailing: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPromptSelect = (prompt: Prompt) => {
|
const onPromptSelect = (prompt: Prompt) => {
|
||||||
@ -280,7 +309,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
preview: true,
|
preview: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []
|
: [],
|
||||||
)
|
)
|
||||||
.concat(
|
.concat(
|
||||||
userInput.length > 0
|
userInput.length > 0
|
||||||
@ -292,7 +321,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
preview: true,
|
preview: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []
|
: [],
|
||||||
);
|
);
|
||||||
|
|
||||||
// auto scroll
|
// auto scroll
|
||||||
@ -375,32 +404,33 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles["chat-message-item"]}>
|
<div className={styles["chat-message-item"]}>
|
||||||
{(!isUser && !(message.preview || message.content.length === 0)) && (
|
{!isUser &&
|
||||||
<div className={styles["chat-message-top-actions"]}>
|
!(message.preview || message.content.length === 0) && (
|
||||||
{message.streaming ? (
|
<div className={styles["chat-message-top-actions"]}>
|
||||||
<div
|
{message.streaming ? (
|
||||||
className={styles["chat-message-top-action"]}
|
<div
|
||||||
onClick={() => onUserStop(i)}
|
className={styles["chat-message-top-action"]}
|
||||||
>
|
onClick={() => onUserStop(i)}
|
||||||
{Locale.Chat.Actions.Stop}
|
>
|
||||||
</div>
|
{Locale.Chat.Actions.Stop}
|
||||||
) : (
|
</div>
|
||||||
<div
|
) : (
|
||||||
className={styles["chat-message-top-action"]}
|
<div
|
||||||
onClick={() => onResend(i)}
|
className={styles["chat-message-top-action"]}
|
||||||
>
|
onClick={() => onResend(i)}
|
||||||
{Locale.Chat.Actions.Retry}
|
>
|
||||||
</div>
|
{Locale.Chat.Actions.Retry}
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={styles["chat-message-top-action"]}
|
className={styles["chat-message-top-action"]}
|
||||||
onClick={() => copyToClipboard(message.content)}
|
onClick={() => copyToClipboard(message.content)}
|
||||||
>
|
>
|
||||||
{Locale.Chat.Actions.Copy}
|
{Locale.Chat.Actions.Copy}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
{(message.preview || message.content.length === 0) &&
|
{(message.preview || message.content.length === 0) &&
|
||||||
!isUser ? (
|
!isUser ? (
|
||||||
<LoadingIcon />
|
<LoadingIcon />
|
||||||
@ -555,7 +585,7 @@ export function Home() {
|
|||||||
state.newSession,
|
state.newSession,
|
||||||
state.currentSessionIndex,
|
state.currentSessionIndex,
|
||||||
state.removeSession,
|
state.removeSession,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
const loading = !useHasHydrated();
|
const loading = !useHasHydrated();
|
||||||
const [showSideBar, setShowSideBar] = useState(true);
|
const [showSideBar, setShowSideBar] = useState(true);
|
||||||
|
@ -192,6 +192,7 @@ interface ChatStore {
|
|||||||
summarizeSession: () => void;
|
summarizeSession: () => void;
|
||||||
updateStat: (message: Message) => void;
|
updateStat: (message: Message) => void;
|
||||||
updateCurrentSession: (updater: (session: ChatSession) => void) => void;
|
updateCurrentSession: (updater: (session: ChatSession) => void) => void;
|
||||||
|
updateTitle: (title: string) => void;
|
||||||
updateMessage: (
|
updateMessage: (
|
||||||
sessionIndex: number,
|
sessionIndex: number,
|
||||||
messageIndex: number,
|
messageIndex: number,
|
||||||
@ -390,6 +391,10 @@ export const useChatStore = create<ChatStore>()(
|
|||||||
set(() => ({ sessions }));
|
set(() => ({ sessions }));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateTitle(title: string) {
|
||||||
|
get().updateCurrentSession((session) => (session.topic = title));
|
||||||
|
},
|
||||||
|
|
||||||
summarizeSession() {
|
summarizeSession() {
|
||||||
const session = get().currentSession();
|
const session = get().currentSession();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user