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));
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,38 +8,30 @@
|
|||||||
* - 默认:粉色背景 + 渐变边缘
|
* - 默认:粉色背景 + 渐变边缘
|
||||||
* - 聚焦 / 激活:完整 primaryGradient(accent → 透明)
|
* - 聚焦 / 激活:完整 primaryGradient(accent → 透明)
|
||||||
*
|
*
|
||||||
* 图标:空输入显示 <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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user