diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index fa3a1cf2..99b2d022 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -240,24 +240,39 @@ &:last-child { animation: slide-in ease 0.3s; } - - &:hover { - .chat-message-actions { - opacity: 1; - transform: translateY(0px); - max-width: 100%; - height: 40px; - } - - .chat-message-action-date { - opacity: 0.2; - } - } } .chat-message-user { display: flex; flex-direction: row-reverse; + + .chat-message-header { + flex-direction: row-reverse; + } +} + +.chat-message-header { + margin-top: 20px; + display: flex; + align-items: center; + + .chat-message-actions { + display: flex; + box-sizing: border-box; + font-size: 12px; + align-items: flex-end; + justify-content: space-between; + transition: all ease 0.3s; + transform: scale(0.9) translateY(5px); + margin: 0 10px; + opacity: 0; + pointer-events: none; + + .chat-input-actions { + display: flex; + flex-wrap: nowrap; + } + } } .chat-message-container { @@ -270,6 +285,12 @@ .chat-message-edit { opacity: 0.9; } + + .chat-message-actions { + opacity: 1; + pointer-events: all; + transform: scale(1) translateY(0); + } } } @@ -278,7 +299,6 @@ } .chat-message-avatar { - margin-top: 20px; position: relative; .chat-message-edit { @@ -318,27 +338,6 @@ border: var(--border-in-light); position: relative; transition: all ease 0.3s; - - .chat-message-actions { - display: flex; - box-sizing: border-box; - font-size: 12px; - align-items: flex-end; - justify-content: space-between; - transition: all ease 0.3s 0.15s; - transform: translateX(-5px) scale(0.9) translateY(30px); - opacity: 0; - height: 0; - max-width: 0; - position: absolute; - left: 0; - z-index: 2; - - .chat-input-actions { - display: flex; - flex-wrap: nowrap; - } - } } .chat-message-action-date { diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 13105e84..c479a08a 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -708,27 +708,26 @@ export function Chat() { let lastUserMessageIndex: number | null = null; for (let i = 0; i < session.messages.length; i += 1) { const message = session.messages[i]; - if (message.id === messageId) { - break; - } if (message.role === "user") { lastUserMessageIndex = i; } + if (message.id === messageId) { + break; + } } return lastUserMessageIndex; }; - const deleteMessage = (userIndex: number) => { - chatStore.updateCurrentSession((session) => - session.messages.splice(userIndex, 2), + const deleteMessage = (msgId?: number) => { + chatStore.updateCurrentSession( + (session) => + (session.messages = session.messages.filter((m) => m.id !== msgId)), ); }; - const onDelete = (botMessageId: number) => { - const userIndex = findLastUserIndex(botMessageId); - if (userIndex === null) return; - deleteMessage(userIndex); + const onDelete = (msgId: number) => { + deleteMessage(msgId); }; const onResend = (botMessageId: number) => { @@ -737,20 +736,16 @@ export function Chat() { if (userIndex === null) return; setIsLoading(true); - const content = session.messages[userIndex].content; - deleteMessage(userIndex); - chatStore.onUserInput(content).then(() => setIsLoading(false)); + const userMsg = session.messages[userIndex]; + deleteMessage(userMsg.id); + deleteMessage(botMessageId); + chatStore.onUserInput(userMsg.content).then(() => setIsLoading(false)); inputRef.current?.focus(); }; - const onPinMessage = (botMessage: ChatMessage) => { - if (!botMessage.id) return; - const userMessageIndex = findLastUserIndex(botMessage.id); - if (userMessageIndex === null) return; - - const userMessage = session.messages[userMessageIndex]; + const onPinMessage = (message: ChatMessage) => { chatStore.updateCurrentSession((session) => - session.mask.context.push(userMessage, botMessage), + session.mask.context.push(message), ); showToast(Locale.Chat.Actions.PinToastContent, { @@ -923,11 +918,12 @@ export function Chat() { > {messages.map((message, i) => { const isUser = message.role === "user"; - const showActions = - !isUser && - i > 0 && - !(message.preview || message.content.length === 0) && - i >= context.length; // do not show actions for context prompts + // const showActions = + // !isUser && + // i > 0 && + // !(message.preview || message.content.length === 0) && + // i >= context.length; // do not show actions for context prompts + const showActions = true; const showTyping = message.preview || message.streaming; const shouldShowClearContextDivider = i === clearContextIndex - 1; @@ -941,64 +937,38 @@ export function Chat() { } >
-
-
- } - onClick={async () => { - const newMessage = await showPrompt( - Locale.Chat.Actions.Edit, - message.content, - 10, - ); - chatStore.updateCurrentSession((session) => { - const m = session.messages.find( - (m) => m.id === message.id, +
+
+
+ } + onClick={async () => { + const newMessage = await showPrompt( + Locale.Chat.Actions.Edit, + message.content, + 10, ); - if (m) { - m.content = newMessage; - } - }); - }} - > + chatStore.updateCurrentSession((session) => { + const m = session.messages.find( + (m) => m.id === message.id, + ); + if (m) { + m.content = newMessage; + } + }); + }} + > +
+ {isUser ? ( + + ) : ( + + )}
- {isUser ? ( - - ) : ( - - )} -
- {showTyping && ( -
- {Locale.Chat.Typing} -
- )} -
- onRightClick(e, message)} - onDoubleClickCapture={() => { - if (!isMobileScreen) return; - setUserInput(message.content); - }} - fontSize={fontSize} - parentRef={scrollRef} - defaultShow={i >= messages.length - 10} - /> {showActions && (
-
+
{message.streaming ? ( )}
+ {showTyping && ( +
+ {Locale.Chat.Typing} +
+ )} +
+ onRightClick(e, message)} + onDoubleClickCapture={() => { + if (!isMobileScreen) return; + setUserInput(message.content); + }} + fontSize={fontSize} + parentRef={scrollRef} + defaultShow={i >= messages.length - 10} + /> +
{showActions && (
diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 07e87cbe..c6ba4ed7 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -26,7 +26,7 @@ const cn = { Stop: "停止", Retry: "重试", Pin: "固定", - PinToastContent: "已将 2 条对话固定至预设提示词", + PinToastContent: "已将 1 条对话固定至预设提示词", PinToastAction: "查看", Delete: "删除", Edit: "编辑", diff --git a/app/locales/en.ts b/app/locales/en.ts index 9373e2b1..23b6e7ca 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -28,7 +28,7 @@ const en: LocaleType = { Stop: "Stop", Retry: "Retry", Pin: "Pin", - PinToastContent: "Pinned 2 messages to contextual prompts", + PinToastContent: "Pinned 1 messages to contextual prompts", PinToastAction: "View", Delete: "Delete", Edit: "Edit", diff --git a/package.json b/package.json index cec288f4..20b76a44 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "fuse.js": "^6.6.2", "html-to-image": "^1.11.11", "mermaid": "^10.2.3", + "nanoid": "^4.0.2", "next": "^13.4.6", "node-fetch": "^3.3.1", "react": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index 4e86fd7c..1c76bd4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4639,6 +4639,11 @@ nanoid@^3.3.4: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^4.0.2: + version "4.0.2" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" + integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"