diff --git a/src/app/chat/components/__tests__/tailwind-components.test.tsx b/src/app/chat/components/__tests__/tailwind-components.test.tsx index 54cb2521..c54b5cae 100644 --- a/src/app/chat/components/__tests__/tailwind-components.test.tsx +++ b/src/app/chat/components/__tests__/tailwind-components.test.tsx @@ -13,6 +13,7 @@ import { MessageAvatar } from "../message-avatar"; import { PrivateMessageCard } from "../private-message-card"; import { PwaInstallDialog } from "../pwa-install-dialog"; import { TextBubble } from "../text-bubble"; +import { VoiceUnlockOptionsDialog } from "../voice-unlock-options-dialog"; vi.mock("@/router/use-app-navigator", () => ({ useAppNavigator: () => ({ @@ -294,4 +295,38 @@ describe("chat Tailwind components", () => { expect(html).toContain("bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)]"); expect(html).toContain("Top up now"); }); + + it("renders VoiceUnlockOptionsDialog action choices", () => { + expect( + renderToStaticMarkup( + undefined} + onBuyVoicePackage={() => undefined} + onActivateVip={() => undefined} + />, + ), + ).toBe(""); + + const html = renderToStaticMarkup( + undefined} + onBuyVoicePackage={() => undefined} + onActivateVip={() => undefined} + />, + ); + + expect(html).toContain('aria-labelledby="voice-unlock-options-title"'); + expect(html).toContain("z-[72]"); + expect(html).toContain("Unlock voice message"); + expect(html).toContain("购买语音包"); + expect(html).toContain("开通 VIP"); + expect(html).toContain("免费10条语言消息+无限畅聊"); + expect(html).toContain("Cancel"); + expect(html).toContain("bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)]"); + expect(html).toContain( + "bg-[linear-gradient(#ffffff,#ffffff)_padding-box,linear-gradient(90deg,#ff67e0,#ff52a2)_border-box]", + ); + }); }); diff --git a/src/app/chat/components/index.ts b/src/app/chat/components/index.ts index 2f1133b4..f6161756 100644 --- a/src/app/chat/components/index.ts +++ b/src/app/chat/components/index.ts @@ -17,7 +17,6 @@ export * from "./fullscreen-image-viewer"; export * from "./history-unlock-dialog"; export * from "./image-bubble"; export * from "./insufficient-credits-dialog"; -export * from "./language-dialog"; export * from "./lottie-message-bubble"; export * from "./message-avatar"; export * from "./message-bubble"; diff --git a/src/app/chat/components/language-dialog.module.css b/src/app/chat/components/language-dialog.module.css deleted file mode 100644 index 5bafb96d..00000000 --- a/src/app/chat/components/language-dialog.module.css +++ /dev/null @@ -1,78 +0,0 @@ -/* LanguageDialog 语言切换弹窗样式 */ - -.overlay { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 50; - padding: - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-top, 0px)) - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-right, 0px)) - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-bottom, 0px)) - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-left, 0px)); -} - -.dialog { - width: 100%; - max-width: var(--dialog-max-width, 360px); - background: var(--color-surface, #1f1a2e); - border-radius: var(--responsive-card-radius-sm, var(--radius-lg, 12px)); - padding: var(--responsive-card-padding-lg, var(--spacing-5, 20px)); - display: flex; - flex-direction: column; - gap: var(--spacing-3, 12px); - max-height: calc( - var(--app-visible-height, 100dvh) - - calc(var(--dialog-safe-margin, 16px) * 2) - ); -} - -.title { - font-size: var(--responsive-section-title, var(--font-size-lg, 18px)); - font-weight: 600; - margin: 0; - color: var(--color-text-primary, #fff); -} - -.list { - display: flex; - flex-direction: column; - gap: var(--spacing-1, 4px); - overflow-y: auto; - max-height: calc( - var(--app-visible-height, 100dvh) - - calc(var(--dialog-safe-margin, 16px) * 2) - - 88px - ); -} - -.item { - display: flex; - align-items: center; - justify-content: space-between; - padding: var(--spacing-3, 12px) var(--spacing-4, 16px); - background: transparent; - border: 0; - border-radius: var(--radius-md, 8px); - color: var(--color-text-primary, #fff); - font-size: var(--responsive-body, var(--font-size-base, 14px)); - text-align: left; - cursor: pointer; -} - -.item:hover, -.item:focus-visible { - background: rgba(255, 255, 255, 0.05); -} - -.itemActive { - background: rgba(248, 77, 150, 0.15); -} - -.check { - color: var(--color-accent, #f84d96); - font-weight: 700; -} diff --git a/src/app/chat/components/language-dialog.tsx b/src/app/chat/components/language-dialog.tsx deleted file mode 100644 index 6b76bbea..00000000 --- a/src/app/chat/components/language-dialog.tsx +++ /dev/null @@ -1,95 +0,0 @@ -"use client"; -/** - * LanguageDialog 语言切换弹窗 - * - * - * - * 简化版:单语种列表选择(保留可扩展性) - * - 支持未来添加更多语言 - * - 当前选中状态高亮 - * - ESC / 点击外部 → 关闭 - */ -import { useEffect } from "react"; - -import styles from "./language-dialog.module.css"; - -export interface LanguageItem { - code: string; - label: string; - nativeLabel: string; -} - -export const DEFAULT_LANGUAGES: readonly LanguageItem[] = [ - { code: "en", label: "English", nativeLabel: "English" }, - { code: "zh", label: "Chinese (Simplified)", nativeLabel: "简体中文" }, - { code: "zh-TW", label: "Chinese (Traditional)", nativeLabel: "繁體中文" }, - { code: "ja", label: "Japanese", nativeLabel: "日本語" }, - { code: "ko", label: "Korean", nativeLabel: "한국어" }, - { code: "es", label: "Spanish", nativeLabel: "Español" }, - { code: "fr", label: "French", nativeLabel: "Français" }, - { code: "de", label: "German", nativeLabel: "Deutsch" }, -]; - -export interface LanguageDialogProps { - open: boolean; - onClose: () => void; - currentLanguageCode?: string; - languages?: readonly LanguageItem[]; - onSelect: (code: string) => void; -} - -export function LanguageDialog({ - open, - onClose, - currentLanguageCode = "en", - languages = DEFAULT_LANGUAGES, - onSelect, -}: LanguageDialogProps) { - useEffect(() => { - if (!open) return; - const onKey = (e: KeyboardEvent) => { - if (e.key === "Escape") onClose(); - }; - document.addEventListener("keydown", onKey); - return () => document.removeEventListener("keydown", onKey); - }, [open, onClose]); - - if (!open) return null; - - return ( -
-
e.stopPropagation()}> -

Select Language

-
- {languages.map((lang) => { - const isActive = currentLanguageCode === lang.code; - return ( - - ); - })} -
-
-
- ); -} diff --git a/src/app/chat/components/voice-unlock-options-dialog.module.css b/src/app/chat/components/voice-unlock-options-dialog.module.css deleted file mode 100644 index f4434899..00000000 --- a/src/app/chat/components/voice-unlock-options-dialog.module.css +++ /dev/null @@ -1,108 +0,0 @@ -.overlay { - position: fixed; - inset: 0; - z-index: 72; - display: flex; - align-items: center; - justify-content: center; - padding: - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-top, 0px)) - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-right, 0px)) - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-bottom, 0px)) - calc(var(--dialog-safe-margin, 16px) + var(--app-safe-left, 0px)); - background: rgba(0, 0, 0, 0.5); -} - -.dialog { - width: 100%; - max-width: var(--dialog-max-width, 380px); - padding: - var(--responsive-card-padding-lg, 24px) - var(--responsive-card-padding, 18px) - var(--responsive-card-padding, 18px); - border-radius: var(--responsive-card-radius, 36px); - background: var(--color-page-background, #ffffff); - box-shadow: 0 18px 40px rgba(0, 0, 0, 0.16); -} - -.title { - margin: 0 0 clamp(7px, 1.481vw, 8px); - color: var(--color-text-foreground, #171717); - font-size: var(--responsive-page-title, var(--font-size-22, 22px)); - font-weight: 700; - line-height: 1.2; - text-align: center; -} - -.content { - margin: 0 var(--spacing-md, 12px) var(--page-section-gap-lg, 20px); - color: #393939; - font-size: var(--responsive-body, var(--font-size-md, 14px)); - line-height: 1.5; - text-align: center; -} - -.options { - display: flex; - flex-direction: column; - gap: var(--spacing-md, 12px); -} - -.optionButton, -.cancel { - width: 100%; - min-height: var(--responsive-control-height, 48px); - border: 0; - border-radius: var(--radius-bottom-sheet, 28px); - cursor: pointer; - font-size: var(--responsive-body, var(--font-size-lg, 16px)); - font-weight: 700; -} - -.optionButton { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: var(--responsive-inline-gap-xs, 4px); - padding: - clamp(9px, 1.852vw, 10px) - var(--responsive-card-padding, 16px); -} - -.primary { - color: #ffffff; - background: linear-gradient(90deg, #ff67e0 0%, #ff52a2 100%); - box-shadow: 0 5px 7px rgba(247, 89, 168, 0.24); -} - -.secondaryOption { - color: #f657a0; - background: - linear-gradient(#ffffff, #ffffff) padding-box, - linear-gradient(90deg, #ff67e0, #ff52a2) border-box; - border: 1px solid transparent; -} - -.optionTitle { - line-height: 1.2; -} - -.optionDescription { - color: #3c3b3b; - font-size: var(--responsive-caption, 13px); - font-weight: 500; - line-height: 1.25; -} - -.cancel { - margin-top: clamp(12px, 2.593vw, 14px); - color: #ffffff; - background: var(--color-text-secondary, #9e9e9e); -} - -.optionButton:focus-visible, -.cancel:focus-visible { - outline: 2px solid #f657a0; - outline-offset: 3px; -} diff --git a/src/app/chat/components/voice-unlock-options-dialog.tsx b/src/app/chat/components/voice-unlock-options-dialog.tsx index 918ef93e..3d5d79d1 100644 --- a/src/app/chat/components/voice-unlock-options-dialog.tsx +++ b/src/app/chat/components/voice-unlock-options-dialog.tsx @@ -1,7 +1,5 @@ "use client"; -import styles from "./voice-unlock-options-dialog.module.css"; - export interface VoiceUnlockOptionsDialogProps { open: boolean; onClose: () => void; @@ -19,40 +17,47 @@ export function VoiceUnlockOptionsDialog({ return (
-
-

+
+

Unlock voice message

-

+

Choose how you would like to unlock this voice message.

-
+
-