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/pages/DeckDetailPage.tsx | 452 +++++++++++++++++++++++------------- 1 file changed, 291 insertions(+), 161 deletions(-) (limited to 'src/client/pages/DeckDetailPage.tsx') diff --git a/src/client/pages/DeckDetailPage.tsx b/src/client/pages/DeckDetailPage.tsx index 3d7ffb5..cb1e3fb 100644 --- a/src/client/pages/DeckDetailPage.tsx +++ b/src/client/pages/DeckDetailPage.tsx @@ -31,6 +31,13 @@ const CardStateLabels: Record = { 3: "Relearning", }; +const CardStateColors: Record = { + 0: "bg-info/10 text-info", + 1: "bg-warning/10 text-warning", + 2: "bg-success/10 text-success", + 3: "bg-error/10 text-error", +}; + export function DeckDetailPage() { const { deckId } = useParams<{ deckId: string }>(); const [deck, setDeck] = useState(null); @@ -114,195 +121,318 @@ export function DeckDetailPage() { if (!deckId) { return ( -
-

Invalid deck ID

- Back to decks +
+
+

Invalid deck ID

+ + Back to decks + +
); } return ( -
-
- - ← Back to Decks - -
- - {isLoading &&

Loading...

} - - {error && ( -
- {error} - + + Back to Decks +
- )} + - {!isLoading && !error && deck && ( -
-
-

{deck.name}

- {deck.description && ( -

- {deck.description} -

- )} + {/* Main Content */} +
+ {/* Loading State */} + {isLoading && ( +
+
+ )} + {/* Error State */} + {error && (
- + {error} + +
+ )} + + {/* Deck Content */} + {!isLoading && !error && deck && ( +
+ {/* Deck Header */} +
+

+ {deck.name} +

+ {deck.description && ( +

{deck.description}

+ )} +
+ + {/* Study Button */} +
+ + + Study Now + +
+ + {/* Cards Section */} +
+

+ Cards{" "} + ({cards.length}) +

- -
- -
-

Cards ({cards.length})

- -
- - {cards.length === 0 && ( -
-

This deck has no cards yet.

-

Add cards to start studying!

- )} - - {cards.length > 0 && ( -
    - {cards.map((card) => ( -
  • +
    + +
    +

    + No cards yet +

    +

    + Add cards to start studying +

    + +
+ )} + + {/* Card List */} + {cards.length > 0 && ( +
+ {cards.map((card, index) => (
-
-
-
- Front: -

- {card.front} -

+
+
+ {/* Front/Back Preview */} +
+
+ + Front + +

+ {card.front} +

+
+
+ + Back + +

+ {card.back} +

+
-
- Back: -

+ - {card.back} -

+ {CardStateLabels[card.state] || "Unknown"} + + + {card.reps} reviews + + {card.lapses > 0 && ( + + {card.lapses} lapses + + )}
-
- - State: {CardStateLabels[card.state] || "Unknown"} - - Reviews: {card.reps} - Lapses: {card.lapses} + + {/* Actions */} +
+ +
-
- - -
- - ))} - - )} -
- )} + ))} +
+ )} +
+ )} + + {/* Modals */} {deckId && (