diff --git a/src/app/auth/components/__tests__/tailwind-components.test.tsx b/src/app/auth/components/__tests__/tailwind-components.test.tsx index 372b41f2..fd795f23 100644 --- a/src/app/auth/components/__tests__/tailwind-components.test.tsx +++ b/src/app/auth/components/__tests__/tailwind-components.test.tsx @@ -2,15 +2,26 @@ import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it, vi } from "vitest"; import { AuthBackground } from "../auth-background"; +import { AuthEmailPanel } from "../auth-email-panel"; import { AuthErrorMessage } from "../auth-error-message"; +import { AuthFacebookPanel } from "../auth-facebook-panel"; import { AuthLegalText } from "../auth-legal-text"; +import { AuthPrimaryButton } from "../auth-primary-button"; import { AuthSocialButton } from "../auth-social-button"; +import { AuthSocialButtons } from "../auth-social-buttons"; import { AuthTextField } from "../auth-text-field"; import { EmailLoginForm } from "../email-login-form"; import { EmailRegisterForm } from "../email-register-form"; vi.mock("@/stores/auth/auth-context", () => ({ useAuthDispatch: () => vi.fn(), + useAuthState: () => ({ + authPanelMode: "facebook", + isLoading: false, + errorMessage: null, + loginStatus: "notLoggedIn", + hasInitialized: true, + }), })); describe("auth Tailwind components", () => { @@ -23,6 +34,17 @@ describe("auth Tailwind components", () => { expect(html).toContain("Invalid email"); }); + it("renders AuthPrimaryButton with Tailwind gradient and spinner", () => { + const html = renderToStaticMarkup( + Continue, + ); + + expect(html).toContain("min-h-[var(--auth-field-height)]"); + expect(html).toContain("bg-[linear-gradient"); + expect(html).toContain("animate-spin"); + expect(html).toContain("Continue"); + }); + it("renders EmailLoginForm with Tailwind form layout", () => { const html = renderToStaticMarkup(); @@ -64,6 +86,24 @@ describe("auth Tailwind components", () => { expect(html).toContain("Continue"); }); + it("renders AuthSocialButtons with provider-specific Tailwind styles", () => { + const html = renderToStaticMarkup( + {}} + onGoogle={() => {}} + onApple={() => {}} + showApple + />, + ); + + expect(html).toContain("bg-facebook-blue"); + expect(html).toContain("bg-white"); + expect(html).toContain("bg-black"); + expect(html).toContain("Continue with Facebook"); + expect(html).toContain("Continue with Google"); + expect(html).toContain("Continue with Apple"); + }); + it("renders AuthLegalText with Tailwind checkbox and links", () => { const html = renderToStaticMarkup(); @@ -90,4 +130,25 @@ describe("auth Tailwind components", () => { expect(html).toContain("text-auth-text-primary"); expect(html).toContain("Invalid email"); }); + + it("renders AuthEmailPanel with Tailwind panel layout", () => { + const html = renderToStaticMarkup( + {}} />, + ); + + expect(html).toContain("flex min-h-0 w-full flex-auto flex-col"); + expect(html).toContain("h-xxl"); + expect(html).toContain("Other Sign In Options"); + }); + + it("renders AuthFacebookPanel with Tailwind Facebook button", () => { + const html = renderToStaticMarkup( + {}} />, + ); + + expect(html).toContain("Login with Facebook"); + expect(html).toContain("bg-auth-surface"); + expect(html).toContain("enabled:hover:brightness-[0.97]"); + expect(html).toContain("Other Sign In Options"); + }); }); diff --git a/src/app/auth/components/auth-email-panel.module.css b/src/app/auth/components/auth-email-panel.module.css deleted file mode 100644 index 103a6099..00000000 --- a/src/app/auth/components/auth-email-panel.module.css +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * 视觉规格(与 Dart 对齐): - * - 顶部:login 模式有 logo + 24px spacer;register 模式两个 24px spacer - * - 表单 + 12px gap + 切换链接 + 16px gap + 弹层链接 - * - Spacer + 法律 - * - 切换链接:14px 黑色下划线居中 - * - "Other Sign In Options" 链接:14px 黑色下划线居中 - */ -.panel { - display: flex; - flex-direction: column; - align-items: stretch; - flex: 1 1 auto; - width: 100%; - min-height: 0; -} - -.topSection { - display: flex; - flex-direction: column; - align-items: stretch; -} - -.spacer24 { - height: var(--spacing-xxl); -} - -.logo { - display: block; - height: clamp(92px, 22.222vw, var(--auth-logo-height)); - width: auto; - max-width: min(56vw, 220px); - margin: 0 auto; - object-fit: contain; -} - -.spacer { - flex: 1 1 0; - min-height: var(--page-section-gap, var(--spacing-lg)); -} - -.toggleButton { - align-self: center; - background: none; - border: none; - padding: var(--spacing-md) 0 0; - font-size: var(--responsive-body, var(--font-size-md)); - color: var(--color-auth-text-primary); - text-decoration: underline; - text-underline-offset: 3px; - cursor: pointer; - transition: opacity 0.15s ease; -} - -.toggleButton:hover { - opacity: 0.8; -} - -.linkButton { - align-self: center; - background: none; - border: none; - padding: var(--spacing-md) 0 var(--spacing-md); - font-size: var(--responsive-body, var(--font-size-md)); - color: var(--color-auth-text-primary); - text-decoration: underline; - text-underline-offset: 3px; - cursor: pointer; - transition: opacity 0.15s ease; -} - -.linkButton:hover { - opacity: 0.8; -} diff --git a/src/app/auth/components/auth-email-panel.tsx b/src/app/auth/components/auth-email-panel.tsx index 7142908f..43ca9e22 100644 --- a/src/app/auth/components/auth-email-panel.tsx +++ b/src/app/auth/components/auth-email-panel.tsx @@ -23,7 +23,6 @@ import { AuthLegalText } from "./auth-legal-text"; import { AuthOtherOptionsDialog } from "./auth-other-options-dialog"; import { EmailLoginForm } from "./email-login-form"; import { EmailRegisterForm } from "./email-register-form"; -import styles from "./auth-email-panel.module.css"; export interface AuthEmailPanelProps { /** "Other Sign-in Options" 弹层中 Facebook 按钮回调(派发回 facebook 模式) */ @@ -44,28 +43,28 @@ export function AuthEmailPanel({ const [showOptions, setShowOptions] = useState(false); return ( -
-
+
+
{mode === "login" ? ( <> -
+
Cozsweet ) : ( <> -
-
+
+
)} -
+
{mode === "login" ? ( @@ -84,7 +83,7 @@ export function AuthEmailPanel({ -
+
void; @@ -49,46 +48,52 @@ export function AuthFacebookPanel({ }; return ( -
-
+
+
Cozsweet -
+
-
+
diff --git a/src/app/auth/components/auth-other-options-dialog.module.css b/src/app/auth/components/auth-other-options-dialog.module.css deleted file mode 100644 index 9a8524e2..00000000 --- a/src/app/auth/components/auth-other-options-dialog.module.css +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * 视觉规格(与 Dart 对齐): - * - drag handle 40×4 灰胶囊 - * - 标题 24px bold 深色居中 - * - 选项按钮 40px 白胶囊 - * - Cancel 14px 深色居中文本按钮 - */ -.body { - display: flex; - flex-direction: column; - align-items: stretch; - gap: var(--spacing-md); - padding: var(--spacing-md) var(--spacing-xxl) - calc(var(--spacing-xxl) + var(--app-safe-bottom, 0px)); -} - -.handle { - align-self: center; - width: var(--auth-drag-handle-width); - height: var(--auth-drag-handle-height); - border-radius: 2px; - background: var(--color-auth-drag-handle); - margin-bottom: var(--spacing-sm); -} - -.title { - margin: var(--spacing-sm) 0; - font-size: var(--responsive-page-title, var(--font-size-bottom-sheet-title)); - font-weight: 700; - color: var(--color-auth-text-primary); - text-align: center; -} - -.googleSlot { - width: 100%; -} - -.cancel { - align-self: center; - background: none; - border: none; - padding: var(--spacing-md) 0; - color: var(--color-auth-text-primary); - font-size: var(--responsive-body, var(--font-size-md)); - font-weight: 500; - cursor: pointer; - text-decoration: none; -} - -.cancel:hover { - text-decoration: underline; -} diff --git a/src/app/auth/components/auth-other-options-dialog.tsx b/src/app/auth/components/auth-other-options-dialog.tsx index 9e911936..b3e5a460 100644 --- a/src/app/auth/components/auth-other-options-dialog.tsx +++ b/src/app/auth/components/auth-other-options-dialog.tsx @@ -7,7 +7,6 @@ import { AppEnvUtil } from "@/utils"; import { AuthProviderIcon } from "./auth-provider-icon"; import { AuthSocialButton } from "./auth-social-button"; -import styles from "./auth-other-options-dialog.module.css"; export interface AuthOtherOptionsDialogProps { open: boolean; @@ -39,9 +38,17 @@ export function AuthOtherOptionsDialog({ onClose={onClose} ariaLabel="Other sign-in options" > -
-