From 65c0adfd769b9ef11b897c96a3634c61120055b8 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
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 <noreply@anthropic.com>
---
 src/client/components/SyncButton.tsx | 65 ++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 17 deletions(-)

(limited to 'src/client/components/SyncButton.tsx')

diff --git a/src/client/components/SyncButton.tsx b/src/client/components/SyncButton.tsx
index 1ebfa2e..82a6c68 100644
--- a/src/client/components/SyncButton.tsx
+++ b/src/client/components/SyncButton.tsx
@@ -9,13 +9,6 @@ export function SyncButton() {
 
 	const isDisabled = !isOnline || isSyncing;
 
-	const getButtonText = (): string => {
-		if (isSyncing) {
-			return "Syncing...";
-		}
-		return "Sync";
-	};
-
 	return (
 		<button
 			type="button"
@@ -23,17 +16,55 @@ export function SyncButton() {
 			onClick={handleSync}
 			disabled={isDisabled}
 			title={!isOnline ? "Cannot sync while offline" : undefined}
-			style={{
-				padding: "0.25rem 0.5rem",
-				borderRadius: "4px",
-				border: "1px solid #dee2e6",
-				backgroundColor: isDisabled ? "#e9ecef" : "#007bff",
-				color: isDisabled ? "#6c757d" : "white",
-				cursor: isDisabled ? "not-allowed" : "pointer",
-				fontSize: "0.875rem",
-			}}
+			className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-all duration-200 ${
+				isDisabled
+					? "bg-ivory text-muted cursor-not-allowed"
+					: "bg-primary text-white hover:bg-primary-dark active:scale-[0.98]"
+			}`}
 		>
-			{getButtonText()}
+			{isSyncing ? (
+				<>
+					<svg
+						className="w-4 h-4 animate-spin"
+						fill="none"
+						viewBox="0 0 24 24"
+						aria-hidden="true"
+					>
+						<circle
+							className="opacity-25"
+							cx="12"
+							cy="12"
+							r="10"
+							stroke="currentColor"
+							strokeWidth="4"
+						/>
+						<path
+							className="opacity-75"
+							fill="currentColor"
+							d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
+						/>
+					</svg>
+					<span>Syncing...</span>
+				</>
+			) : (
+				<>
+					<svg
+						className="w-4 h-4"
+						fill="none"
+						stroke="currentColor"
+						viewBox="0 0 24 24"
+						aria-hidden="true"
+					>
+						<path
+							strokeLinecap="round"
+							strokeLinejoin="round"
+							strokeWidth={2}
+							d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
+						/>
+					</svg>
+					<span>Sync</span>
+				</>
+			)}
 		</button>
 	);
 }
-- 
cgit v1.2.3-70-g09d2

