refactor(chat): simplify input send button
This commit is contained in:
@@ -24,13 +24,6 @@
|
||||
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 边框 */
|
||||
.row {
|
||||
display: flex;
|
||||
@@ -46,9 +39,3 @@
|
||||
.rowFocused {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { useChatDispatch } from "@/stores/chat/chat-context";
|
||||
import { useUserState } from "@/stores/user/user-context";
|
||||
import { useKeyboardHeight } from "@/hooks";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
import { ChatInputActionPanel } from "./chat-input-action-panel";
|
||||
import { ChatInputTextField } from "./chat-input-text-field";
|
||||
import { ChatSendButton } from "./chat-send-button";
|
||||
import styles from "./chat-input-bar.module.css";
|
||||
@@ -19,15 +17,11 @@ export interface ChatInputBarProps {
|
||||
|
||||
export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
const dispatch = useChatDispatch();
|
||||
const { currentUser } = useUserState();
|
||||
const [input, setInput] = useState("");
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const [isActionPanelOpen, setIsActionPanelOpen] = useState(false);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const hasContent = input.trim().length > 0;
|
||||
const isActive = isFocused || isActionPanelOpen;
|
||||
const voiceMinutesRemaining = currentUser?.voiceMinutesRemaining ?? 0;
|
||||
|
||||
useKeyboardHeight({
|
||||
targetRef: textareaRef,
|
||||
@@ -37,9 +31,6 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
|
||||
const handleInputChange = (value: string) => {
|
||||
setInput(value);
|
||||
if (value.trim().length > 0) {
|
||||
setIsActionPanelOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSend = () => {
|
||||
@@ -56,34 +47,9 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
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 (
|
||||
<div
|
||||
className={`${styles.bar} ${isActive ? styles.barFocused : ""} ${
|
||||
isActionPanelOpen ? styles.barExpanded : ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`${styles.row} ${isActive ? styles.rowFocused : ""} ${
|
||||
isActionPanelOpen ? styles.rowExpanded : ""
|
||||
}`}
|
||||
>
|
||||
<div className={`${styles.bar} ${isFocused ? styles.barFocused : ""}`}>
|
||||
<div className={`${styles.row} ${isFocused ? styles.rowFocused : ""}`}>
|
||||
<ChatInputTextField
|
||||
ref={textareaRef}
|
||||
value={input}
|
||||
@@ -94,17 +60,9 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
/>
|
||||
<ChatSendButton
|
||||
disabled={disabled}
|
||||
hasContent={hasContent}
|
||||
isExpanded={isActionPanelOpen}
|
||||
onClick={handleActionButtonClick}
|
||||
onClick={handleSend}
|
||||
/>
|
||||
</div>
|
||||
{isActionPanelOpen ? (
|
||||
<ChatInputActionPanel
|
||||
voiceMinutesRemaining={voiceMinutesRemaining}
|
||||
onVoiceMessageClick={handleVoiceMessageClick}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,38 +8,30 @@
|
||||
* - 默认:粉色背景 + 渐变边缘
|
||||
* - 聚焦 / 激活:完整 primaryGradient(accent → 透明)
|
||||
*
|
||||
* 图标:空输入显示 <Plus />,有内容时显示 <ArrowUp />
|
||||
* 图标:固定显示 <ArrowUp />,按钮只负责发送消息。
|
||||
*/
|
||||
import { ArrowUp, Plus } from "lucide-react";
|
||||
import { ArrowUp } from "lucide-react";
|
||||
|
||||
import styles from "./chat-send-button.module.css";
|
||||
|
||||
export interface ChatSendButtonProps {
|
||||
disabled: boolean;
|
||||
hasContent: boolean;
|
||||
isExpanded?: boolean;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export function ChatSendButton({
|
||||
disabled,
|
||||
hasContent,
|
||||
isExpanded = false,
|
||||
onClick,
|
||||
}: ChatSendButtonProps) {
|
||||
const Icon = hasContent ? ArrowUp : Plus;
|
||||
const ariaLabel = hasContent ? "Send message" : "Open chat actions";
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`${styles.button} ${disabled ? "" : styles.buttonActive}`}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
aria-expanded={hasContent ? undefined : isExpanded}
|
||||
aria-label={ariaLabel}
|
||||
aria-label="Send message"
|
||||
>
|
||||
<Icon className={styles.icon} size={24} aria-hidden="true" />
|
||||
<ArrowUp className={styles.icon} size={24} aria-hidden="true" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user