refactor(chat): simplify input send button

This commit is contained in:
2026-07-01 12:42:26 +08:00
parent a80d68c1e4
commit eccb6d3074
3 changed files with 7 additions and 70 deletions
@@ -24,13 +24,6 @@
box-shadow: 0 4px 12px var(--color-input-box-shadow, rgba(0, 0, 0, 0.1)); box-shadow: 0 4px 12px var(--color-input-box-shadow, rgba(0, 0, 0, 0.1));
} }
.barExpanded {
padding-right: 0;
padding-bottom: 0;
padding-left: 0;
background: #fff1f4;
}
/* 内层:白底 + 大圆角(Dart AppRadius.radius32+ focused 时 accent 边框 */ /* 内层:白底 + 大圆角(Dart AppRadius.radius32+ focused 时 accent 边框 */
.row { .row {
display: flex; display: flex;
@@ -46,9 +39,3 @@
.rowFocused { .rowFocused {
border-color: var(--color-accent, #f84d96); border-color: var(--color-accent, #f84d96);
} }
.rowExpanded {
margin: 0 var(--spacing-md, 12px) var(--spacing-md, 12px);
border-color: #ff8fc7;
box-shadow: 0 2px 10px rgba(246, 87, 160, 0.16);
}
+3 -45
View File
@@ -2,11 +2,9 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { useChatDispatch } from "@/stores/chat/chat-context"; import { useChatDispatch } from "@/stores/chat/chat-context";
import { useUserState } from "@/stores/user/user-context";
import { useKeyboardHeight } from "@/hooks"; import { useKeyboardHeight } from "@/hooks";
import { Logger } from "@/utils"; import { Logger } from "@/utils";
import { ChatInputActionPanel } from "./chat-input-action-panel";
import { ChatInputTextField } from "./chat-input-text-field"; import { ChatInputTextField } from "./chat-input-text-field";
import { ChatSendButton } from "./chat-send-button"; import { ChatSendButton } from "./chat-send-button";
import styles from "./chat-input-bar.module.css"; import styles from "./chat-input-bar.module.css";
@@ -19,15 +17,11 @@ export interface ChatInputBarProps {
export function ChatInputBar({ disabled = false }: ChatInputBarProps) { export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
const dispatch = useChatDispatch(); const dispatch = useChatDispatch();
const { currentUser } = useUserState();
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [isFocused, setIsFocused] = useState(false); const [isFocused, setIsFocused] = useState(false);
const [isActionPanelOpen, setIsActionPanelOpen] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null); const textareaRef = useRef<HTMLTextAreaElement>(null);
const hasContent = input.trim().length > 0; const hasContent = input.trim().length > 0;
const isActive = isFocused || isActionPanelOpen;
const voiceMinutesRemaining = currentUser?.voiceMinutesRemaining ?? 0;
useKeyboardHeight({ useKeyboardHeight({
targetRef: textareaRef, targetRef: textareaRef,
@@ -37,9 +31,6 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
const handleInputChange = (value: string) => { const handleInputChange = (value: string) => {
setInput(value); setInput(value);
if (value.trim().length > 0) {
setIsActionPanelOpen(false);
}
}; };
const handleSend = () => { const handleSend = () => {
@@ -56,34 +47,9 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
textareaRef.current?.focus(); textareaRef.current?.focus();
}; };
const handleActionButtonClick = () => {
if (hasContent) {
handleSend();
return;
}
textareaRef.current?.blur();
setIsFocused(false);
setIsActionPanelOpen((open) => !open);
};
const handleVoiceMessageClick = () => {
log.debug("[chat-input-bar] voice message action clicked", {
voiceMinutesRemaining,
});
};
return ( return (
<div <div className={`${styles.bar} ${isFocused ? styles.barFocused : ""}`}>
className={`${styles.bar} ${isActive ? styles.barFocused : ""} ${ <div className={`${styles.row} ${isFocused ? styles.rowFocused : ""}`}>
isActionPanelOpen ? styles.barExpanded : ""
}`}
>
<div
className={`${styles.row} ${isActive ? styles.rowFocused : ""} ${
isActionPanelOpen ? styles.rowExpanded : ""
}`}
>
<ChatInputTextField <ChatInputTextField
ref={textareaRef} ref={textareaRef}
value={input} value={input}
@@ -94,17 +60,9 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
/> />
<ChatSendButton <ChatSendButton
disabled={disabled} disabled={disabled}
hasContent={hasContent} onClick={handleSend}
isExpanded={isActionPanelOpen}
onClick={handleActionButtonClick}
/> />
</div> </div>
{isActionPanelOpen ? (
<ChatInputActionPanel
voiceMinutesRemaining={voiceMinutesRemaining}
onVoiceMessageClick={handleVoiceMessageClick}
/>
) : null}
</div> </div>
); );
} }
+4 -12
View File
@@ -8,38 +8,30 @@
* - 默认:粉色背景 + 渐变边缘 * - 默认:粉色背景 + 渐变边缘
* - 聚焦 / 激活:完整 primaryGradientaccent → 透明) * - 聚焦 / 激活:完整 primaryGradientaccent → 透明)
* *
* 图标:空输入显示 <Plus />,有内容时显示 <ArrowUp /> * 图标:固定显示 <ArrowUp />,按钮只负责发送消息。
*/ */
import { ArrowUp, Plus } from "lucide-react"; import { ArrowUp } from "lucide-react";
import styles from "./chat-send-button.module.css"; import styles from "./chat-send-button.module.css";
export interface ChatSendButtonProps { export interface ChatSendButtonProps {
disabled: boolean; disabled: boolean;
hasContent: boolean;
isExpanded?: boolean;
onClick: () => void; onClick: () => void;
} }
export function ChatSendButton({ export function ChatSendButton({
disabled, disabled,
hasContent,
isExpanded = false,
onClick, onClick,
}: ChatSendButtonProps) { }: ChatSendButtonProps) {
const Icon = hasContent ? ArrowUp : Plus;
const ariaLabel = hasContent ? "Send message" : "Open chat actions";
return ( return (
<button <button
type="button" type="button"
className={`${styles.button} ${disabled ? "" : styles.buttonActive}`} className={`${styles.button} ${disabled ? "" : styles.buttonActive}`}
disabled={disabled} disabled={disabled}
onClick={onClick} onClick={onClick}
aria-expanded={hasContent ? undefined : isExpanded} aria-label="Send message"
aria-label={ariaLabel}
> >
<Icon className={styles.icon} size={24} aria-hidden="true" /> <ArrowUp className={styles.icon} size={24} aria-hidden="true" />
</button> </button>
); );
} }