diff --git a/ui/src/App.jsx b/ui/src/App.jsx
index c3e532a..e4d4e3f 100644
--- a/ui/src/App.jsx
+++ b/ui/src/App.jsx
@@ -13,7 +13,7 @@ export default function App() {
useEffect(() => { localStorage.setItem('pf_sidebar', sidebarExpanded ? 'expanded' : 'collapsed') }, [sidebarExpanded])
return (
-
+
@@ -25,4 +25,4 @@ export default function App() {
)
-}
+}
\ No newline at end of file
diff --git a/ui/src/components/Sidebar.jsx b/ui/src/components/Sidebar.jsx
index 8f55fa4..788b3c8 100644
--- a/ui/src/components/Sidebar.jsx
+++ b/ui/src/components/Sidebar.jsx
@@ -38,7 +38,6 @@ export default function Sidebar({ view, setView, expanded, setExpanded }) {
className="bg-white border-r border-gray-200 flex flex-col shrink-0 overflow-hidden transition-all duration-150"
style={{ width: expanded ? 200 : 48 }}
>
- {/* Logo / toggle */}
- {/* Nav */}
)
-}
+}
\ No newline at end of file
diff --git a/ui/src/components/StatusBar.jsx b/ui/src/components/StatusBar.jsx
index 6050e16..d1a62dc 100644
--- a/ui/src/components/StatusBar.jsx
+++ b/ui/src/components/StatusBar.jsx
@@ -1,6 +1,10 @@
+import useTheme from '../theme.jsx'
+
export default function StatusBar() {
+ const { dark, setDark } = useTheme()
+
return (
-
+
Source
sales_orders
|
@@ -12,6 +16,23 @@ export default function StatusBar() {
|
Status
open
+
+
+
)
-}
+}
\ No newline at end of file
diff --git a/ui/src/index.css b/ui/src/index.css
index ab0d6a7..86280ca 100644
--- a/ui/src/index.css
+++ b/ui/src/index.css
@@ -1,4 +1,80 @@
@import "tailwindcss";
-body { margin: 0; }
+:root, .light {
+ --bg-primary: #f3f4f6;
+ --bg-secondary: #ffffff;
+ --bg-tertiary: #f9fafb;
+ --text-primary: #1f2937;
+ --text-secondary: #374151;
+ --text-muted: #9ca3af;
+ --border-color: #e5e7eb;
+ --border-light: #f3f4f6;
+ --accent-bg: #eff6ff;
+ --accent-text: #1d4ed8;
+}
+
+.dark {
+ --bg-primary: #111827;
+ --bg-secondary: #1f2937;
+ --bg-tertiary: #374151;
+ --text-primary: #f9fafb;
+ --text-secondary: #e5e7eb;
+ --text-muted: #6b7280;
+ --border-color: #374151;
+ --border-light: #1f2937;
+ --accent-bg: #1e3a5f;
+ --accent-text: #60a5fa;
+}
+
+body { margin: 0; background-color: var(--bg-primary); color: var(--text-primary); }
#root { height: 100vh; display: flex; }
+
+.dark .bg-white { background-color: var(--bg-secondary); }
+.dark .bg-gray-50 { background-color: var(--bg-tertiary); }
+.dark .bg-gray-100 { background-color: var(--bg-tertiary); }
+.dark .bg-gray-200 { background-color: var(--bg-tertiary); }
+.dark .bg-gray-300 { background-color: var(--bg-tertiary); }
+.dark .text-gray-300 { color: var(--text-muted); }
+.dark .text-gray-400 { color: var(--text-muted); }
+.dark .text-gray-500 { color: var(--text-muted); }
+.dark .text-gray-600 { color: var(--text-secondary); }
+.dark .text-gray-700 { color: var(--text-secondary); }
+.dark .text-gray-800 { color: var(--text-primary); }
+.dark .text-gray-900 { color: var(--text-primary); }
+.dark .bg-blue-50 { background-color: var(--accent-bg); }
+.dark .bg-blue-100 { background-color: var(--accent-bg); }
+.dark .text-blue-600 { color: var(--accent-text); }
+.dark .text-blue-700 { color: var(--accent-text); }
+.dark .border-blue-300 { border-color: var(--accent-text); }
+.dark .hover\:bg-blue-50:hover { background-color: var(--accent-bg); }
+.dark .bg-green-50 { background-color: #064e3b; }
+.dark .text-green-600 { color: #34d399; }
+.dark .text-green-700 { color: #34d399; }
+.dark .text-green-400 { color: #34d399; }
+.dark .bg-yellow-50 { background-color: #451a03; }
+.dark .text-yellow-700 { color: #fbbf24; }
+.dark .bg-purple-50 { background-color: #1e1b4b; }
+.dark .text-purple-700 { color: #a78bfa; }
+.dark .bg-red-50 { background-color: #450a0a; }
+.dark .text-red-700 { color: #f87171; }
+.dark .border-gray-100 { border-color: var(--border-light); }
+.dark .border-gray-200 { border-color: var(--border-color); }
+.dark .border-gray-300 { border-color: var(--border-color); }
+.dark .border-b { border-color: var(--border-color); }
+.dark .border-t { border-color: var(--border-color); }
+.dark .border-r { border-color: var(--border-color); }
+.dark .border-l { border-color: var(--border-color); }
+.dark .hover\:bg-gray-50:hover { background-color: var(--bg-tertiary); }
+.dark .hover\:bg-gray-100:hover { background-color: var(--bg-tertiary); }
+.dark .hover\:bg-gray-200:hover { background-color: var(--bg-tertiary); }
+.dark .hover\:text-gray-500:hover { color: var(--text-secondary); }
+.dark .hover\:text-gray-600:hover { color: var(--text-secondary); }
+.dark .hover\:text-gray-800:hover { color: var(--text-primary); }
+.dark .hover\:border-gray-300:hover { border-color: var(--border-color); }
+.dark .hover\:border-gray-400:hover { border-color: var(--border-color); }
+.dark .focus\:border-gray-300:focus { border-color: var(--border-color); }
+.dark ::selection { background-color: var(--accent-bg); color: var(--accent-text); }
+.dark input { background-color: var(--bg-secondary); color: var(--text-primary); }
+.dark select { background-color: var(--bg-secondary); color: var(--text-primary); }
+.dark textarea { background-color: var(--bg-secondary); color: var(--text-primary); }
+.dark .bg-transparent { background-color: transparent; }
diff --git a/ui/src/main.jsx b/ui/src/main.jsx
index b9a1a6d..28ad15f 100644
--- a/ui/src/main.jsx
+++ b/ui/src/main.jsx
@@ -1,10 +1,13 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
+import { ThemeProvider } from './theme.jsx'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
-
+
+
+
,
)
diff --git a/ui/src/theme.jsx b/ui/src/theme.jsx
new file mode 100644
index 0000000..afd26ce
--- /dev/null
+++ b/ui/src/theme.jsx
@@ -0,0 +1,25 @@
+import { createContext, useContext, useState, useEffect } from 'react'
+
+const ThemeContext = createContext()
+
+export function ThemeProvider({ children }) {
+ const [dark, setDark] = useState(() => {
+ const saved = localStorage.getItem('pf_dark')
+ if (saved !== null) return saved === 'true'
+ return window.matchMedia('(prefers-color-scheme: dark)').matches
+ })
+
+ useEffect(() => {
+ localStorage.setItem('pf_dark', dark)
+ document.documentElement.classList.toggle('dark', dark)
+ }, [dark])
+
+ return (
+
+ {children}
+
+ )
+}
+
+const useTheme = () => useContext(ThemeContext)
+export default useTheme
\ No newline at end of file