diff --git a/src/app/chat/components/__tests__/tailwind-components.test.tsx b/src/app/chat/components/__tests__/tailwind-components.test.tsx index dce97b4f..630f048f 100644 --- a/src/app/chat/components/__tests__/tailwind-components.test.tsx +++ b/src/app/chat/components/__tests__/tailwind-components.test.tsx @@ -1,7 +1,9 @@ import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vitest"; +import { ChatSendButton } from "../chat-send-button"; import { MessageAvatar } from "../message-avatar"; +import { PrivateMessageCard } from "../private-message-card"; import { TextBubble } from "../text-bubble"; describe("chat Tailwind components", () => { @@ -37,4 +39,55 @@ describe("chat Tailwind components", () => { ); expect(userHtml).toContain("from user"); }); + + it("renders PrivateMessageCard with fallback and loading states", () => { + const fallbackHtml = renderToStaticMarkup(); + const unlockingHtml = renderToStaticMarkup( + undefined} />, + ); + + expect(fallbackHtml).toContain('role="group"'); + expect(fallbackHtml).toContain('aria-label="Locked private message"'); + expect(fallbackHtml).toContain("rounded-tl-none"); + expect(fallbackHtml).toContain("Elio has a private message for you."); + expect(fallbackHtml).toContain("disabled"); + expect(unlockingHtml).toContain("Premium secret"); + expect(unlockingHtml).toContain("Unlocking..."); + }); + + it("renders ChatSendButton visual states", () => { + const activeHtml = renderToStaticMarkup( + undefined} + onPointerDownSend={() => undefined} + />, + ); + const emptyHtml = renderToStaticMarkup( + undefined} + onPointerDownSend={() => undefined} + />, + ); + const disabledHtml = renderToStaticMarkup( + undefined} + onPointerDownSend={() => undefined} + />, + ); + + expect(activeHtml).toContain('aria-label="Send message"'); + expect(activeHtml).toContain("size-[var(--chat-send-button-size,40px)]"); + expect(activeHtml).toContain( + "bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]", + ); + expect(emptyHtml).toContain("bg-[#f8a8ce]"); + expect(emptyHtml).toContain("text-[rgba(255,255,255,0.88)]"); + expect(disabledHtml).toContain("disabled"); + }); }); diff --git a/src/app/chat/components/ai-disclosure-banner.module.css b/src/app/chat/components/ai-disclosure-banner.module.css deleted file mode 100644 index 56337aed..00000000 --- a/src/app/chat/components/ai-disclosure-banner.module.css +++ /dev/null @@ -1,9 +0,0 @@ -/* AiDisclosureBanner 样式(独立文件以便 chat-area 内联版本可复用) */ - -.banner { - align-self: center; - background: transparent; - font-size: var(--responsive-micro, var(--font-size-xs, 11px)); - color: var(--color-text-banner, #8c8b8b); - text-align: center; -} diff --git a/src/app/chat/components/chat-send-button.module.css b/src/app/chat/components/chat-send-button.module.css deleted file mode 100644 index 7fdb13cc..00000000 --- a/src/app/chat/components/chat-send-button.module.css +++ /dev/null @@ -1,44 +0,0 @@ -/* ChatSendButton 发送按钮样式 */ - -.button { - flex: 0 0 auto; - width: var(--chat-send-button-size, 40px); - height: var(--chat-send-button-size, 40px); - aspect-ratio: 1 / 1; - border: 0; - border-radius: 50%; - background: var(--color-button-gradient-end, #fc69df); - color: #fff; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: background 0.2s, transform 0.1s; -} - -.button:disabled { - opacity: 0.4; - cursor: not-allowed; -} - -.buttonEmpty { - background: #f8a8ce; - color: rgba(255, 255, 255, 0.88); - box-shadow: none; -} - -.button:focus-visible, -.buttonActive { - background: linear-gradient( - to right, - var(--color-button-gradient-start, #ff67e0), - var(--color-button-gradient-end, #ff52a2) - ); -} - -.icon { - width: var(--icon-size-xl, 24px); - height: var(--icon-size-xl, 24px); - font-size: var(--icon-size-xl, 24px); - line-height: 1; -} diff --git a/src/app/chat/components/chat-send-button.tsx b/src/app/chat/components/chat-send-button.tsx index cb08c8aa..00565c0a 100644 --- a/src/app/chat/components/chat-send-button.tsx +++ b/src/app/chat/components/chat-send-button.tsx @@ -12,8 +12,6 @@ */ import { ArrowUp } from "lucide-react"; -import styles from "./chat-send-button.module.css"; - export interface ChatSendButtonProps { disabled: boolean; hasContent: boolean; @@ -27,12 +25,18 @@ export function ChatSendButton({ onClick, onPointerDownSend, }: ChatSendButtonProps) { + const isActive = hasContent && !disabled; return ( ); } diff --git a/src/app/chat/components/private-message-card.module.css b/src/app/chat/components/private-message-card.module.css deleted file mode 100644 index bbbd2408..00000000 --- a/src/app/chat/components/private-message-card.module.css +++ /dev/null @@ -1,60 +0,0 @@ -.card { - max-width: min(72vw, 280px); - padding: var(--responsive-card-padding, 14px); - border: 1px solid rgba(246, 87, 160, 0.2); - border-radius: var(--responsive-card-radius-sm, 18px); - border-top-left-radius: 0; - background: - linear-gradient(180deg, rgba(255, 244, 248, 0.95), rgba(255, 255, 255, 0.95)), - #ffffff; - box-shadow: 0 4px 12px rgba(246, 87, 160, 0.12); - color: #3c3b3b; -} - -.iconWrap { - width: var(--responsive-icon-button-size, 42px); - height: var(--responsive-icon-button-size, 42px); - border-radius: 50%; - background: linear-gradient(135deg, #ff8fc7 0%, #f657a0 100%); - color: #ffffff; - display: flex; - align-items: center; - justify-content: center; - margin-bottom: clamp(8px, 1.852vw, 10px); -} - -.icon { - display: block; -} - -.hint { - margin: 0; - color: #3c3b3b; - font-size: var(--responsive-body, 14px); - line-height: 1.4; -} - -.button { - width: 100%; - margin-top: var(--spacing-md, 12px); - padding: - clamp(9px, 1.852vw, 10px) - var(--spacing-md, 12px); - border: 0; - border-radius: 999px; - background: linear-gradient(90deg, #ff67e0, #ff52a2); - color: #ffffff; - cursor: pointer; - font-size: var(--responsive-body, 14px); - font-weight: 700; -} - -.button:disabled { - cursor: not-allowed; - opacity: 0.65; -} - -.button:focus-visible { - outline: 2px solid #f657a0; - outline-offset: 3px; -} diff --git a/src/app/chat/components/private-message-card.tsx b/src/app/chat/components/private-message-card.tsx index 7c7deda1..9b1f6425 100644 --- a/src/app/chat/components/private-message-card.tsx +++ b/src/app/chat/components/private-message-card.tsx @@ -2,8 +2,6 @@ import { LockKeyhole } from "lucide-react"; -import styles from "./private-message-card.module.css"; - export interface PrivateMessageCardProps { hint?: string | null; isUnlocking?: boolean; @@ -16,18 +14,25 @@ export function PrivateMessageCard({ onUnlock, }: PrivateMessageCardProps) { return ( -
-