refactor(chat): align chat header and input bar with Dart source
This commit is contained in:
@@ -4,25 +4,28 @@
|
||||
*
|
||||
* 原始 Dart: lib/ui/chat/widgets/chat_input_bar.dart(121 行)
|
||||
*
|
||||
* 组成(从左到右):
|
||||
* - ChatMoreButton(⊞):展开更多选项(图片/语音/功能)
|
||||
* - ChatInputTextField:文本输入
|
||||
* - ChatSendButton(↑):发送
|
||||
*
|
||||
* 状态管理(自包含):
|
||||
* 状态:
|
||||
* - input:受控文本
|
||||
* - focused:是否聚焦(视觉状态)
|
||||
* - hasContent:是否有内容(决定发送按钮启用)
|
||||
* - isFocused:是否聚焦(控制外层 pink-bg / box-shadow / padding-top)
|
||||
* - hasContent:是否有 trim 内容(决定发送按钮是否启用)
|
||||
*
|
||||
* 容器层次(与 Dart 一致):
|
||||
* - 外层 `.bar`:focused 时 `padding-top: md` + 粉色背景 + 阴影
|
||||
* - 内层 `.row`:白底 + `border-radius: 32` + focused 时 accent 边框
|
||||
* - Row:[ChatInputTextField (Expanded), ChatSendButton]
|
||||
*
|
||||
* 行为:
|
||||
* - send 后清空 input + 保持 textarea 焦点(与 Dart `_focusNode.requestFocus()` 一致)
|
||||
*
|
||||
* 注意:Dart 源里的 `ImageUploadButton` 已被注释(`// const ImageUploadButton()`),
|
||||
* `ChatMoreButton` / `FunctionButtonBar` 不存在于 Dart 源;本组件仅保留与 Dart 一致的部分。
|
||||
*/
|
||||
import { useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { useChatDispatch } from "@/stores/chat/chat-context";
|
||||
|
||||
import { ChatInputTextField } from "./chat-input-text-field";
|
||||
import { ChatMoreButton } from "./chat-more-button";
|
||||
import { ChatSendButton } from "./chat-send-button";
|
||||
import { FunctionButtonBar } from "./function-button-bar";
|
||||
import { ImageUploadButton } from "./image-upload-button";
|
||||
import styles from "./chat-input-bar.module.css";
|
||||
|
||||
export interface ChatInputBarProps {
|
||||
@@ -32,8 +35,8 @@ export interface ChatInputBarProps {
|
||||
export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
const dispatch = useChatDispatch();
|
||||
const [input, setInput] = useState("");
|
||||
const [focused, setFocused] = useState(false);
|
||||
const [showFunctions, setShowFunctions] = useState(false);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const hasContent = input.trim().length > 0;
|
||||
|
||||
@@ -41,45 +44,24 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
if (!hasContent) return;
|
||||
dispatch({ type: "ChatSendMessage", content: input });
|
||||
setInput("");
|
||||
textareaRef.current?.focus();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.bar}>
|
||||
{showFunctions && (
|
||||
<FunctionButtonBar
|
||||
items={[
|
||||
{
|
||||
key: "image",
|
||||
icon: "🖼",
|
||||
label: "Image",
|
||||
// ImageUploadButton 内部已管理 sheet;FunctionButtonBar 仅触发
|
||||
onClick: () => {
|
||||
/* 触发:ImageUploadButton 已在 ChatInputBar 中渲染 */
|
||||
},
|
||||
},
|
||||
{ key: "restart", icon: "↻", label: "Restart" },
|
||||
{ key: "history", icon: "⏱", label: "History" },
|
||||
{ key: "call", icon: "📞", label: "Call" },
|
||||
]}
|
||||
<div className={`${styles.bar} ${isFocused ? styles.barFocused : ""}`}>
|
||||
<div className={`${styles.row} ${isFocused ? styles.rowFocused : ""}`}>
|
||||
<ChatInputTextField
|
||||
ref={textareaRef}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
onSubmit={handleSend}
|
||||
onFocusChange={setIsFocused}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<ChatSendButton
|
||||
disabled={!hasContent || disabled}
|
||||
onClick={handleSend}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className={`${styles.row} ${focused ? styles.rowFocused : ""}`}>
|
||||
<ImageUploadButton disabled={disabled} />
|
||||
<ChatMoreButton onClick={() => setShowFunctions((v) => !v)} />
|
||||
<div
|
||||
className={styles.textFieldWrap}
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => setFocused(false)}
|
||||
>
|
||||
<ChatInputTextField
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
onSubmit={handleSend}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
<ChatSendButton disabled={!hasContent || disabled} onClick={handleSend} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user