diff --git a/frontend/src/App.css b/frontend/src/App.css index 90a6398..93737ad 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -2,6 +2,31 @@ @tailwind components; @tailwind utilities; +/* Theme CSS Variables */ +:root { + --bg-primary: #0f172a; + --bg-card: #1e293b; + --bg-secondary: #1f2937; + --bg-tertiary: #374151; + --text-primary: #f3f4f6; + --text-secondary: #9ca3af; + --text-muted: #6b7280; + --border-color: #374151; + --border-light: #4b5563; +} + +.light { + --bg-primary: #f8fafc; + --bg-card: #ffffff; + --bg-secondary: #f1f5f9; + --bg-tertiary: #e2e8f0; + --text-primary: #1e293b; + --text-secondary: #64748b; + --text-muted: #94a3b8; + --border-color: #e2e8f0; + --border-light: #cbd5e1; +} + body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', @@ -9,6 +34,8 @@ body { sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + background-color: var(--bg-primary); + color: var(--text-primary); } code { @@ -17,7 +44,9 @@ code { } .card { - @apply bg-maza-gray rounded-lg shadow-lg p-6 mb-4; + background-color: var(--bg-card); + border: 1px solid var(--border-color); + @apply rounded-lg shadow-lg p-6 mb-4; } .btn { @@ -29,15 +58,22 @@ code { } .btn-secondary { - @apply bg-gray-600 text-white hover:bg-gray-700; + background-color: var(--bg-tertiary); + color: var(--text-primary); + @apply hover:opacity-80; } .input { - @apply w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg text-gray-100 focus:outline-none focus:border-maza-blue; + background-color: var(--bg-secondary); + border: 1px solid var(--border-color); + color: var(--text-primary); + @apply w-full px-4 py-3 rounded-lg focus:outline-none focus:border-maza-blue; } .stat-card { - @apply bg-gradient-to-br from-maza-gray to-gray-800 rounded-lg p-4 shadow-lg; + background: linear-gradient(to bottom right, var(--bg-card), var(--bg-secondary)); + border: 1px solid var(--border-color); + @apply rounded-lg p-4 shadow-lg; } .hash { @@ -51,3 +87,33 @@ code { .error { @apply bg-red-900/30 border border-red-700 text-red-300 px-4 py-3 rounded-lg; } + +.light .error { + @apply bg-red-50 border-red-300 text-red-700; +} + +/* Theme-aware utility classes */ +.bg-theme-primary { background-color: var(--bg-primary); } +.bg-theme-card { background-color: var(--bg-card); } +.bg-theme-secondary { background-color: var(--bg-secondary); } +.bg-theme-tertiary { background-color: var(--bg-tertiary); } +.text-theme-primary { color: var(--text-primary); } +.text-theme-secondary { color: var(--text-secondary); } +.text-theme-muted { color: var(--text-muted); } +.border-theme { border-color: var(--border-color); } + +/* Toast animation */ +@keyframes slide-in { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +.animate-slide-in { + animation: slide-in 0.3s ease-out; +} diff --git a/frontend/src/App.js b/frontend/src/App.js index 66f9f6f..97b11c8 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,5 +1,7 @@ import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import { ThemeProvider } from './contexts/ThemeContext'; +import { ToastProvider } from './components/Toast'; import Header from './components/Header'; import Footer from './components/Footer'; import Home from './pages/Home'; @@ -13,23 +15,27 @@ import './App.css'; function App() { return ( - -
-
-
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
-
-
+ + + +
+
+
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+
+
+
+
); } diff --git a/frontend/src/components/CopyButton.js b/frontend/src/components/CopyButton.js new file mode 100644 index 0000000..6fb92aa --- /dev/null +++ b/frontend/src/components/CopyButton.js @@ -0,0 +1,37 @@ +import React, { useState } from 'react'; +import { Copy, Check } from 'lucide-react'; +import { useToast } from './Toast'; + +function CopyButton({ text, className = '' }) { + const [copied, setCopied] = useState(false); + const toast = useToast(); + + const handleCopy = async (e) => { + e.preventDefault(); + e.stopPropagation(); + try { + await navigator.clipboard.writeText(text); + setCopied(true); + toast('Copied to clipboard!', 'success'); + setTimeout(() => setCopied(false), 2000); + } catch { + toast('Failed to copy', 'error'); + } + }; + + return ( + + ); +} + +export default CopyButton; diff --git a/frontend/src/components/Footer.js b/frontend/src/components/Footer.js index 84359e2..2e798de 100644 --- a/frontend/src/components/Footer.js +++ b/frontend/src/components/Footer.js @@ -2,9 +2,9 @@ import React from 'react'; function Footer() { return ( -