From 7d29dbd72fe6e4f04a32596c7884b42067dc9b72 Mon Sep 17 00:00:00 2001 From: chenhang Date: Fri, 10 Jul 2026 18:18:44 +0800 Subject: [PATCH] refactor(app): migrate small styles to tailwind --- .../__tests__/tailwind-components.test.tsx | 21 +++++++++++++++ .../core/loading-indicator.module.css | 26 ------------------- .../_components/core/loading-indicator.tsx | 26 ++++++++++++++----- .../__tests__/tailwind-components.test.tsx | 15 +++++++++++ .../components/auth-error-message.module.css | 16 ------------ .../auth/components/auth-error-message.tsx | 7 ++--- .../__tests__/pwa-install-overlay.test.tsx | 10 +++++++ .../components/pwa-install-overlay.module.css | 5 ---- .../chat/components/pwa-install-overlay.tsx | 3 +-- 9 files changed, 70 insertions(+), 59 deletions(-) create mode 100644 src/app/_components/core/__tests__/tailwind-components.test.tsx delete mode 100644 src/app/_components/core/loading-indicator.module.css create mode 100644 src/app/auth/components/__tests__/tailwind-components.test.tsx delete mode 100644 src/app/auth/components/auth-error-message.module.css create mode 100644 src/app/chat/components/__tests__/pwa-install-overlay.test.tsx delete mode 100644 src/app/chat/components/pwa-install-overlay.module.css diff --git a/src/app/_components/core/__tests__/tailwind-components.test.tsx b/src/app/_components/core/__tests__/tailwind-components.test.tsx new file mode 100644 index 00000000..7dcdaaca --- /dev/null +++ b/src/app/_components/core/__tests__/tailwind-components.test.tsx @@ -0,0 +1,21 @@ +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vitest"; + +import { LoadingIndicator } from "../loading-indicator"; + +describe("core Tailwind components", () => { + it("renders LoadingIndicator with accessible status and dynamic sizing", () => { + const html = renderToStaticMarkup( + , + ); + + expect(html).toContain('role="status"'); + expect(html).toContain('aria-label="Loading"'); + expect(html).toContain("animate-spin"); + expect(html).toContain("width:24px"); + expect(html).toContain("height:24px"); + expect(html).toContain("border-width:2px"); + expect(html).toContain("border-color:#f00 transparent transparent transparent"); + expect(html).toContain("Loading now"); + }); +}); diff --git a/src/app/_components/core/loading-indicator.module.css b/src/app/_components/core/loading-indicator.module.css deleted file mode 100644 index e9ed37a5..00000000 --- a/src/app/_components/core/loading-indicator.module.css +++ /dev/null @@ -1,26 +0,0 @@ -.wrapper { - display: inline-flex; - flex-direction: column; - align-items: center; - gap: var(--spacing-sm); -} - -.spinner { - display: inline-block; - border-style: solid; - border-color: var(--color-text-secondary) transparent transparent - transparent; - border-radius: 50%; - animation: spin 0.8s linear infinite; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -.label { - color: var(--color-text-secondary); - font-size: var(--font-size-sm); -} diff --git a/src/app/_components/core/loading-indicator.tsx b/src/app/_components/core/loading-indicator.tsx index 0593f270..f6ed3dd8 100644 --- a/src/app/_components/core/loading-indicator.tsx +++ b/src/app/_components/core/loading-indicator.tsx @@ -7,10 +7,10 @@ * 行为对齐 Flutter `CircularProgressIndicator`: * - `size`:圆圈直径(默认 32) * - `strokeWidth`:环宽(默认 3) - * - `color`:环颜色(默认 `--color-accent`) + * - `color`:环颜色(默认 `--color-text-secondary`) * - `label`:可选的可视标签(环形下方文本) */ -import styles from "./loading-indicator.module.css"; +import type { CSSProperties } from "react"; export interface LoadingIndicatorProps { size?: number; @@ -25,16 +25,28 @@ export function LoadingIndicator({ color, label, }: LoadingIndicatorProps) { - const style: React.CSSProperties = { + const spinnerColor = color ?? "var(--color-text-secondary)"; + const style: CSSProperties = { width: size, height: size, borderWidth: strokeWidth, - ...(color ? { borderTopColor: color } : {}), + borderColor: `${spinnerColor} transparent transparent transparent`, }; return ( -
-
- {label ? {label} : null} +
+
+ {label ? ( + + {label} + + ) : null}
); } diff --git a/src/app/auth/components/__tests__/tailwind-components.test.tsx b/src/app/auth/components/__tests__/tailwind-components.test.tsx new file mode 100644 index 00000000..91fede1a --- /dev/null +++ b/src/app/auth/components/__tests__/tailwind-components.test.tsx @@ -0,0 +1,15 @@ +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vitest"; + +import { AuthErrorMessage } from "../auth-error-message"; + +describe("auth Tailwind components", () => { + it("renders AuthErrorMessage only when a message is present", () => { + expect(renderToStaticMarkup()).toBe(""); + + const html = renderToStaticMarkup(); + expect(html).toContain('role="alert"'); + expect(html).toContain("text-error"); + expect(html).toContain("Invalid email"); + }); +}); diff --git a/src/app/auth/components/auth-error-message.module.css b/src/app/auth/components/auth-error-message.module.css deleted file mode 100644 index 24854701..00000000 --- a/src/app/auth/components/auth-error-message.module.css +++ /dev/null @@ -1,16 +0,0 @@ -/* - * - * 视觉规格(与 Dart 对齐): - * - 细小红字,无背景,无圆角,无边框 - * - 12px 居中 - */ -.banner { - width: 100%; - padding: 0; - background: transparent; - border: none; - color: var(--color-error); - font-size: var(--responsive-caption, var(--font-size-sm)); - line-height: 1.4; - text-align: center; -} diff --git a/src/app/auth/components/auth-error-message.tsx b/src/app/auth/components/auth-error-message.tsx index 8930edb0..824d4a2f 100644 --- a/src/app/auth/components/auth-error-message.tsx +++ b/src/app/auth/components/auth-error-message.tsx @@ -4,12 +4,13 @@ * * */ -import styles from "./auth-error-message.module.css"; - export function AuthErrorMessage({ message }: { message: string | null }) { if (!message) return null; return ( -
+
{message}
); diff --git a/src/app/chat/components/__tests__/pwa-install-overlay.test.tsx b/src/app/chat/components/__tests__/pwa-install-overlay.test.tsx new file mode 100644 index 00000000..d2e24cca --- /dev/null +++ b/src/app/chat/components/__tests__/pwa-install-overlay.test.tsx @@ -0,0 +1,10 @@ +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vitest"; + +import { PwaInstallOverlay } from "../pwa-install-overlay"; + +describe("PwaInstallOverlay", () => { + it("does not render visible markup", () => { + expect(renderToStaticMarkup()).toBe(""); + }); +}); diff --git a/src/app/chat/components/pwa-install-overlay.module.css b/src/app/chat/components/pwa-install-overlay.module.css deleted file mode 100644 index 85554c11..00000000 --- a/src/app/chat/components/pwa-install-overlay.module.css +++ /dev/null @@ -1,5 +0,0 @@ -/* PwaInstallOverlay PWA 安装弹窗触发器样式(无可见 UI,逻辑触发用) */ - -.hidden { - display: none; -} diff --git a/src/app/chat/components/pwa-install-overlay.tsx b/src/app/chat/components/pwa-install-overlay.tsx index 1bc551d9..911ad1b5 100644 --- a/src/app/chat/components/pwa-install-overlay.tsx +++ b/src/app/chat/components/pwa-install-overlay.tsx @@ -22,7 +22,6 @@ import { import { pwaUtil } from "@/utils"; import { PwaInstallDialog } from "./pwa-install-dialog"; -import styles from "./pwa-install-overlay.module.css"; const DEVELOPMENT_DIALOG_DELAY_MS = 1000; const PRODUCTION_DIALOG_DELAY_MS = 1500; @@ -74,7 +73,7 @@ export function PwaInstallOverlay({ enabled }: PwaInstallOverlayProps) { }; }, [enabled]); - return