feat(chat): support ai photo viewing
This commit is contained in:
@@ -1,25 +1,4 @@
|
||||
"use client";
|
||||
/**
|
||||
* ChatInputBar 输入栏
|
||||
*
|
||||
* 原始 Dart: lib/ui/chat/widgets/chat_input_bar.dart(121 行)
|
||||
*
|
||||
* 状态:
|
||||
* - input:受控文本
|
||||
* - 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 { useRef, useState } from "react";
|
||||
|
||||
import { useChatDispatch } from "@/stores/chat/chat-context";
|
||||
|
||||
@@ -44,7 +44,7 @@ export const ChatInputTextField = forwardRef<
|
||||
onChange,
|
||||
onSubmit,
|
||||
onFocusChange,
|
||||
placeholder = "|Say anything that’s on your mind ^U^…",
|
||||
placeholder = "Say anything that’s on your mind ^U^…",
|
||||
disabled = false,
|
||||
autoFocus = false,
|
||||
},
|
||||
|
||||
@@ -27,6 +27,8 @@ import { ROUTES } from "@/router/routes";
|
||||
import styles from "./chat-quota-exhausted-banner.module.css";
|
||||
|
||||
export interface ChatQuotaExhaustedBannerProps {
|
||||
title?: string;
|
||||
ctaLabel?: string;
|
||||
/**
|
||||
* 自定义点击回调(不传则默认 router.push(ROUTES.subscription))
|
||||
* - 测试时可传 mock
|
||||
@@ -36,9 +38,12 @@ export interface ChatQuotaExhaustedBannerProps {
|
||||
}
|
||||
|
||||
export function ChatQuotaExhaustedBanner({
|
||||
title = "The limit for free chat times\nhas been reached today",
|
||||
ctaLabel = "Unlock your membership to continue",
|
||||
onUnlock,
|
||||
}: ChatQuotaExhaustedBannerProps) {
|
||||
const router = useRouter();
|
||||
const titleLines = title.split("\n");
|
||||
|
||||
const handleClick = () => {
|
||||
if (onUnlock) {
|
||||
@@ -56,17 +61,20 @@ export function ChatQuotaExhaustedBanner({
|
||||
data-testid="chat-quota-exhausted-banner"
|
||||
>
|
||||
<p className={styles.text}>
|
||||
The limit for free chat times
|
||||
<br />
|
||||
has been reached today
|
||||
{titleLines.map((line, index) => (
|
||||
<span key={`${line}-${index}`}>
|
||||
{line}
|
||||
{index < titleLines.length - 1 ? <br /> : null}
|
||||
</span>
|
||||
))}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.cta}
|
||||
onClick={handleClick}
|
||||
aria-label="Unlock your membership to continue"
|
||||
aria-label={ctaLabel}
|
||||
>
|
||||
Unlock your membership to continue
|
||||
{ctaLabel}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user