diff options
Diffstat (limited to 'src/App.tsx')
| -rw-r--r-- | src/App.tsx | 113 |
1 files changed, 108 insertions, 5 deletions
diff --git a/src/App.tsx b/src/App.tsx index a6e3249..966e8e1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,114 @@ +import { useEffect, useState, useCallback } from 'react'; +import { TimerView } from './components/TimerView'; +import { TaskList } from './components/TaskList'; +import { SettingsPanel } from './components/SettingsPanel'; +import { NotificationOverlay } from './components/NotificationOverlay'; +import { useTimerEvents } from './hooks/useTimerEvents'; +import { useTaskStore } from './store/taskStore'; +import { useSettingsStore } from './store/settingsStore'; + +function GearIcon() { + return ( + <svg + width="18" + height="18" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + > + <circle cx="12" cy="12" r="3" /> + <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" /> + </svg> + ); +} + function App() { + const [settingsOpen, setSettingsOpen] = useState(false); + const [notifVisible, setNotifVisible] = useState(false); + const [notifTaskId, setNotifTaskId] = useState<string | null>(null); + + const fetchTasks = useTaskStore((s) => s.fetchTasks); + const fetchSettings = useSettingsStore((s) => s.fetchSettings); + + // Bootstrap data on mount + useEffect(() => { + fetchTasks(); + fetchSettings(); + }, [fetchTasks, fetchSettings]); + + const handleCompleted = useCallback((taskId: string | null) => { + setNotifTaskId(taskId); + setNotifVisible(true); + }, []); + + useTimerEvents(handleCompleted); + return ( - <main className="flex items-center justify-center min-h-screen"> - <div className="text-center"> - <h1 className="font-display text-fg-1 text-4xl mb-2">Solstice</h1> - <p className="text-fg-3">Pomodoro timer with ambient soundscapes.</p> + <div + style={{ + display: 'flex', + width: '100vw', + height: '100vh', + background: 'var(--ink-0)', + overflow: 'hidden', + position: 'relative', + }} + > + {/* Sidebar */} + <TaskList /> + + {/* Main area */} + <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> + {/* Top bar */} + <div + style={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + padding: '12px 16px', + borderBottom: '1px solid var(--line-1)', + }} + > + <button + onClick={() => setSettingsOpen(true)} + title="Settings" + style={{ + display: 'flex', + alignItems: 'center', + padding: '6px', + border: 'none', + background: 'transparent', + color: 'var(--fg-3)', + cursor: 'pointer', + borderRadius: 'var(--r-2)', + transition: 'color 0.15s ease', + }} + onMouseEnter={(e) => { + (e.currentTarget as HTMLButtonElement).style.color = 'var(--fg-1)'; + }} + onMouseLeave={(e) => { + (e.currentTarget as HTMLButtonElement).style.color = 'var(--fg-3)'; + }} + > + <GearIcon /> + </button> + </div> + + {/* Timer */} + <TimerView /> </div> - </main> + + {/* Overlays */} + <SettingsPanel open={settingsOpen} onClose={() => setSettingsOpen(false)} /> + <NotificationOverlay + visible={notifVisible} + taskId={notifTaskId} + onDismiss={() => setNotifVisible(false)} + /> + </div> ); } |
