From 65c0adfd769b9ef11b897c96a3634c61120055b8 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 8 Dec 2025 00:18:03 +0900 Subject: feat(client): redesign frontend with TailwindCSS v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace inline styles with TailwindCSS, implementing a cohesive Japanese-inspired design system with custom colors (cream, teal primary), typography (Fraunces, DM Sans), and animations. Update all pages and components with consistent styling, improve accessibility by adding aria-hidden to decorative SVGs, and configure Biome for Tailwind CSS syntax support. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/client/components/CreateCardModal.test.tsx | 20 +-- src/client/components/CreateCardModal.tsx | 163 +++++++++++------------- src/client/components/CreateDeckModal.test.tsx | 20 +-- src/client/components/CreateDeckModal.tsx | 160 +++++++++++------------ src/client/components/DeleteCardModal.tsx | 122 +++++++++--------- src/client/components/DeleteDeckModal.tsx | 125 +++++++++--------- src/client/components/EditCardModal.test.tsx | 24 ++-- src/client/components/EditCardModal.tsx | 169 +++++++++++-------------- src/client/components/EditDeckModal.test.tsx | 24 ++-- src/client/components/EditDeckModal.tsx | 164 +++++++++++------------- src/client/components/OfflineBanner.test.tsx | 3 +- src/client/components/OfflineBanner.tsx | 31 ++--- src/client/components/SyncButton.tsx | 65 +++++++--- src/client/components/SyncStatusIndicator.tsx | 116 ++++++++++++----- 14 files changed, 617 insertions(+), 589 deletions(-) (limited to 'src/client/components') diff --git a/src/client/components/CreateCardModal.test.tsx b/src/client/components/CreateCardModal.test.tsx index 6b429c8..7244824 100644 --- a/src/client/components/CreateCardModal.test.tsx +++ b/src/client/components/CreateCardModal.test.tsx @@ -84,7 +84,7 @@ describe("CreateCardModal", () => { expect(screen.getByLabelText("Front")).toBeDefined(); expect(screen.getByLabelText("Back")).toBeDefined(); expect(screen.getByRole("button", { name: "Cancel" })).toBeDefined(); - expect(screen.getByRole("button", { name: "Create" })).toBeDefined(); + expect(screen.getByRole("button", { name: "Create Card" })).toBeDefined(); }); it("disables create button when front is empty", async () => { @@ -93,7 +93,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Back"), "Answer"); - const createButton = screen.getByRole("button", { name: "Create" }); + const createButton = screen.getByRole("button", { name: "Create Card" }); expect(createButton).toHaveProperty("disabled", true); }); @@ -103,7 +103,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), "Question"); - const createButton = screen.getByRole("button", { name: "Create" }); + const createButton = screen.getByRole("button", { name: "Create Card" }); expect(createButton).toHaveProperty("disabled", true); }); @@ -114,7 +114,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), "Question"); await user.type(screen.getByLabelText("Back"), "Answer"); - const createButton = screen.getByRole("button", { name: "Create" }); + const createButton = screen.getByRole("button", { name: "Create Card" }); expect(createButton).toHaveProperty("disabled", false); }); @@ -181,7 +181,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), "What is 2+2?"); await user.type(screen.getByLabelText("Back"), "4"); - await user.click(screen.getByRole("button", { name: "Create" })); + await user.click(screen.getByRole("button", { name: "Create Card" })); await waitFor(() => { expect( @@ -213,7 +213,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), " Question "); await user.type(screen.getByLabelText("Back"), " Answer "); - await user.click(screen.getByRole("button", { name: "Create" })); + await user.click(screen.getByRole("button", { name: "Create Card" })); await waitFor(() => { expect( @@ -241,7 +241,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), "Question"); await user.type(screen.getByLabelText("Back"), "Answer"); - await user.click(screen.getByRole("button", { name: "Create" })); + await user.click(screen.getByRole("button", { name: "Create Card" })); expect(screen.getByRole("button", { name: "Creating..." })).toBeDefined(); expect(screen.getByRole("button", { name: "Creating..." })).toHaveProperty( @@ -271,7 +271,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), "Question"); await user.type(screen.getByLabelText("Back"), "Answer"); - await user.click(screen.getByRole("button", { name: "Create" })); + await user.click(screen.getByRole("button", { name: "Create Card" })); await waitFor(() => { expect(screen.getByRole("alert").textContent).toContain( @@ -291,7 +291,7 @@ describe("CreateCardModal", () => { await user.type(screen.getByLabelText("Front"), "Question"); await user.type(screen.getByLabelText("Back"), "Answer"); - await user.click(screen.getByRole("button", { name: "Create" })); + await user.click(screen.getByRole("button", { name: "Create Card" })); await waitFor(() => { expect(screen.getByRole("alert").textContent).toContain( @@ -358,7 +358,7 @@ describe("CreateCardModal", () => { // Create a card await user.type(screen.getByLabelText("Front"), "Question"); await user.type(screen.getByLabelText("Back"), "Answer"); - await user.click(screen.getByRole("button", { name: "Create" })); + await user.click(screen.getByRole("button", { name: "Create Card" })); await waitFor(() => { expect(onClose).toHaveBeenCalled(); diff --git a/src/client/components/CreateCardModal.tsx b/src/client/components/CreateCardModal.tsx index c28cf0f..3913e82 100644 --- a/src/client/components/CreateCardModal.tsx +++ b/src/client/components/CreateCardModal.tsx @@ -83,18 +83,7 @@ export function CreateCardModal({ role="dialog" aria-modal="true" aria-labelledby="create-card-title" - style={{ - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0, 0, 0, 0.5)", - display: "flex", - alignItems: "center", - justifyContent: "center", - zIndex: 1000, - }} + className="fixed inset-0 bg-ink/40 backdrop-blur-sm flex items-center justify-center z-50 p-4 animate-fade-in" onClick={(e) => { if (e.target === e.currentTarget) { handleClose(); @@ -106,88 +95,82 @@ export function CreateCardModal({ } }} > -
-

- Create New Card -

+
+
+

+ Create New Card +

-
- {error && ( -
- {error} -
- )} + + {error && ( +
+ {error} +
+ )} -
- -