diff --git a/app/globals.css b/app/globals.css
index 69debcc..92a8651 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -36,6 +36,67 @@
@tailwind components;
@tailwind utilities;
+:root,
+html[data-theme="dark"] {
+ color-scheme: dark;
+ --rah-bg-base: #0a0a0a;
+ --rah-bg-surface: #111111;
+ --rah-bg-subtle: #121212;
+ --rah-bg-panel: #141414;
+ --rah-bg-hover: #151515;
+ --rah-bg-elevated: #161616;
+ --rah-bg-active: #1a1a1a;
+ --rah-bg-modal: #141414;
+ --rah-border: #1a1a1a;
+ --rah-border-strong: #2a2a2a;
+ --rah-border-stronger: #3a3a3a;
+ --rah-scrollbar: #353535;
+ --rah-scrollbar-hover: #4a4a4a;
+ --rah-text-base: #e5e5e5;
+ --rah-text-secondary: #c7c7c7;
+ --rah-text-muted: #7a7a7a;
+ --rah-text-soft: #a3a3a3;
+ --rah-text-active: #f0f0f0;
+ --rah-text-inverse: #0a0a0a;
+ --rah-accent-green: #22c55e;
+ --rah-accent-green-hover: #16a34a;
+ --rah-accent-green-soft: rgba(34, 197, 94, 0.14);
+ --rah-accent-green-soft-strong: rgba(34, 197, 94, 0.22);
+ --rah-backdrop: rgba(0, 0, 0, 0.85);
+ --rah-shadow-modal: 0 8px 32px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.05);
+ --rah-shadow-floating: 0 4px 12px rgba(0, 0, 0, 0.4);
+}
+
+html[data-theme="light"] {
+ color-scheme: light;
+ --rah-bg-base: #ffffff;
+ --rah-bg-surface: #fafafa;
+ --rah-bg-subtle: #f7f7f7;
+ --rah-bg-panel: #f5f5f5;
+ --rah-bg-hover: #f0f0f0;
+ --rah-bg-elevated: #ececec;
+ --rah-bg-active: #e8e8e8;
+ --rah-bg-modal: #ffffff;
+ --rah-border: #e5e5e5;
+ --rah-border-strong: #d4d4d4;
+ --rah-border-stronger: #bdbdbd;
+ --rah-scrollbar: #d4d4d4;
+ --rah-scrollbar-hover: #b5b5b5;
+ --rah-text-base: #111111;
+ --rah-text-secondary: #333333;
+ --rah-text-muted: #6b7280;
+ --rah-text-soft: #4b5563;
+ --rah-text-active: #000000;
+ --rah-text-inverse: #ffffff;
+ --rah-accent-green: #16a34a;
+ --rah-accent-green-hover: #15803d;
+ --rah-accent-green-soft: rgba(22, 163, 74, 0.12);
+ --rah-accent-green-soft-strong: rgba(22, 163, 74, 0.2);
+ --rah-backdrop: rgba(0, 0, 0, 0.5);
+ --rah-shadow-modal: 0 10px 36px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.04);
+ --rah-shadow-floating: 0 6px 20px rgba(0, 0, 0, 0.16);
+}
+
/* Modern Clean Design System - RA-H */
* {
margin: 0;
@@ -46,8 +107,8 @@
html, body {
height: 100%;
overflow: hidden;
- background-color: #0a0a0a;
- color: #e5e5e5;
+ background-color: var(--rah-bg-base);
+ color: var(--rah-text-base);
/* Geist Sans for optimal reading/writing experience */
font-family: 'Geist', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 14px;
@@ -71,21 +132,21 @@ html, body {
}
::-webkit-scrollbar-track {
- background: #0a0a0a;
+ background: var(--rah-bg-base);
}
::-webkit-scrollbar-thumb {
- background: #353535;
+ background: var(--rah-scrollbar);
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
- background: #4a4a4a;
+ background: var(--rah-scrollbar-hover);
}
/* Utility classes */
.border-divider {
- border-color: #1a1a1a;
+ border-color: var(--rah-border);
}
.text-muted {
diff --git a/app/layout.tsx b/app/layout.tsx
index bbad70a..b5b29f0 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -13,7 +13,31 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
+
+
+
+
diff --git a/src/components/layout/LeftToolbar.tsx b/src/components/layout/LeftToolbar.tsx
index 2a98cc5..edeb3a2 100644
--- a/src/components/layout/LeftToolbar.tsx
+++ b/src/components/layout/LeftToolbar.tsx
@@ -13,8 +13,11 @@ import {
Settings,
PanelLeftClose,
PanelLeftOpen,
+ Sun,
+ Moon,
} from 'lucide-react';
import type { PaneType } from '../panes/types';
+import type { Theme } from '@/hooks/useTheme';
interface LeftToolbarProps {
onSearchClick: () => void;
@@ -26,6 +29,8 @@ interface LeftToolbarProps {
onToggleExpanded: () => void;
openTabTypes: Set;
activeTabType: PaneType | null;
+ theme: Theme;
+ onThemeToggle: () => void;
}
const NAV_WIDTH_COLLAPSED = 50;
@@ -57,7 +62,7 @@ function NavButton({
activeTone?: 'neutral' | 'green';
}) {
const [hovered, setHovered] = useState(false);
- const activeColor = activeTone === 'green' ? '#22c55e' : '#f0f0f0';
+ const activeColor = activeTone === 'green' ? 'var(--rah-accent-green)' : 'var(--rah-text-active)';
return (
-
+
{VIEW_ITEMS.map((item) => (
-
diff --git a/src/components/layout/ThreePanelLayout.tsx b/src/components/layout/ThreePanelLayout.tsx
index 3968dae..1b5dea3 100644
--- a/src/components/layout/ThreePanelLayout.tsx
+++ b/src/components/layout/ThreePanelLayout.tsx
@@ -6,6 +6,7 @@ import SearchModal from '../nodes/SearchModal';
import { Node } from '@/types/database';
import { DatabaseEvent } from '@/services/events';
import { usePersistentState } from '@/hooks/usePersistentState';
+import { useTheme } from '@/hooks/useTheme';
// ChatMessage import removed - chat disabled in rah-light
// Stub type for delegation (delegation system removed in rah-light)
@@ -40,6 +41,8 @@ import QuickAddInput from '../agents/QuickAddInput';
import type { PaneType, SlotState, PaneAction } from '../panes/types';
export default function ThreePanelLayout() {
+ const [theme, toggleTheme] = useTheme();
+
// Container ref for resize calculations
const containerRef = useRef
(null);
@@ -1014,7 +1017,7 @@ export default function ThreePanelLayout() {
display: 'flex',
height: '100vh',
width: '100vw',
- background: '#0a0a0a',
+ background: 'var(--rah-bg-base)',
overflow: 'hidden'
}}
>
@@ -1032,6 +1035,8 @@ export default function ThreePanelLayout() {
openTabTypes={new Set([slotA?.type, slotB?.type].filter((t): t is PaneType => t != null))}
activeTabType={activePane === 'A' ? slotA?.type ?? null : slotB?.type ?? null}
onRefreshClick={handleRefreshAll}
+ theme={theme}
+ onThemeToggle={toggleTheme}
/>
{/* Main content area */}
diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts
new file mode 100644
index 0000000..bf3490b
--- /dev/null
+++ b/src/hooks/useTheme.ts
@@ -0,0 +1,28 @@
+"use client";
+
+import { useEffect } from 'react';
+import { usePersistentState } from './usePersistentState';
+
+export type Theme = 'dark' | 'light';
+
+function getInitialTheme(): Theme {
+ if (typeof document === 'undefined') {
+ return 'dark';
+ }
+
+ return document.documentElement.getAttribute('data-theme') === 'light' ? 'light' : 'dark';
+}
+
+export function useTheme(): [Theme, () => void] {
+ const [theme, setTheme] = usePersistentState('ui.theme', getInitialTheme());
+
+ useEffect(() => {
+ document.documentElement.setAttribute('data-theme', theme);
+ }, [theme]);
+
+ const toggleTheme = () => {
+ setTheme((prev) => (prev === 'dark' ? 'light' : 'dark'));
+ };
+
+ return [theme, toggleTheme];
+}