Files
ProjectE/app/project-e-app.tsx
T

236 lines
29 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import {
Activity,
BarChart3,
Bell,
Bot,
CalendarDays,
Check,
CheckCircle2,
ChevronDown,
ChevronRight,
Circle,
Clock3,
Command,
FileBarChart,
Flame,
FolderKanban,
GripVertical,
LayoutDashboard,
ListTodo,
Menu,
MoreHorizontal,
NotebookPen,
Pause,
Play,
Plus,
Search,
Settings,
Sparkles,
Target,
TimerReset,
TrendingUp,
X,
type LucideIcon,
} from "lucide-react";
import { useEffect, useMemo, useState } from "react";
type View = "Dashboard" | "Tasks" | "Habits" | "Projects" | "Notes" | "Reports" | "Calendar" | "Analytics" | "Agent Activity" | "Settings";
type Task = { id: number; title: string; project: string; time: string; priority: "Urgent" | "High" | "Normal"; done: boolean; status: "To do" | "In progress" | "Done"; domain: "Personal" | "Work" | "OTS" };
const nav: { label: View; icon: LucideIcon }[] = [
{ label: "Dashboard", icon: LayoutDashboard }, { label: "Tasks", icon: ListTodo },
{ label: "Habits", icon: Flame }, { label: "Projects", icon: FolderKanban },
{ label: "Notes", icon: NotebookPen }, { label: "Reports", icon: FileBarChart },
{ label: "Calendar", icon: CalendarDays }, { label: "Analytics", icon: BarChart3 },
{ label: "Agent Activity", icon: Bot }, { label: "Settings", icon: Settings },
];
const initialTasks: Task[] = [
{ id: 1, title: "Finalize Q3 product brief", project: "Project E", time: "9:00 AM", priority: "Urgent", done: false, status: "In progress", domain: "Work" },
{ id: 2, title: "Review OTS storefront copy", project: "OTS Growth", time: "11:30 AM", priority: "High", done: false, status: "To do", domain: "OTS" },
{ id: 3, title: "30 minute strength session", project: "Personal OS", time: "4:00 PM", priority: "Normal", done: false, status: "To do", domain: "Personal" },
{ id: 4, title: "Map MCP permission model", project: "Project E", time: "Yesterday", priority: "High", done: true, status: "Done", domain: "Work" },
{ id: 5, title: "Archive June campaign assets", project: "OTS Growth", time: "Jul 15", priority: "Normal", done: false, status: "In progress", domain: "OTS" },
{ id: 6, title: "Plan long weekend itinerary", project: "Personal OS", time: "Jul 17", priority: "Normal", done: false, status: "To do", domain: "Personal" },
];
const habits = [
{ id: 1, icon: "↟", name: "Morning walk", streak: 18, color: "mint", done: true },
{ id: 2, icon: "◒", name: "Read 20 pages", streak: 12, color: "blue", done: false },
{ id: 3, icon: "✦", name: "Daily reflection", streak: 7, color: "amber", done: false },
{ id: 4, icon: "⌁", name: "No screens after 10", streak: 4, color: "coral", done: false },
];
const projects = [
{ name: "Project E", domain: "Work", progress: 72, due: "Sep 30", tasks: "18 / 25", color: "#356bff", icon: "E" },
{ name: "OTS Growth", domain: "OTS", progress: 54, due: "Aug 12", tasks: "13 / 24", color: "#ea7658", icon: "O" },
{ name: "Personal OS", domain: "Personal", progress: 81, due: "Ongoing", tasks: "17 / 21", color: "#299667", icon: "P" },
];
const week = [
{ day: "M", value: 58 }, { day: "T", value: 78 }, { day: "W", value: 66 },
{ day: "T", value: 91 }, { day: "F", value: 74 }, { day: "S", value: 42 }, { day: "S", value: 67 },
];
function Logo() {
return <div className="brand"><span className="brand-mark">E</span><span>Project E</span></div>;
}
function Progress({ value, color = "var(--green)" }: { value: number; color?: string }) {
return <div className="progress" aria-label={`${value}% complete`}><span style={{ width: `${value}%`, background: color }} /></div>;
}
function Dashboard({ tasks, onToggleTask, habitDone, onToggleHabit, onNavigate }: { tasks: Task[]; onToggleTask: (id: number) => void; habitDone: Record<number, boolean>; onToggleHabit: (id: number) => void; onNavigate: (view: View) => void }) {
const done = tasks.filter(t => t.done).length;
return <>
<section className="hero-grid">
<article className="focus-card panel">
<div><p className="eyebrow"><Sparkles size={14} /> Focus score</p><h2>Good momentum.</h2><p>Youre ahead of last week. One focused block will close your highest-impact task.</p></div>
<div className="score-ring" aria-label="Focus score 82 out of 100"><strong>82</strong><span>/ 100</span></div>
<button className="primary-button"><Play size={15} fill="currentColor" /> Start focus session</button>
</article>
<article className="metric panel"><span className="metric-icon blue"><CheckCircle2 /></span><div><small>Tasks complete</small><strong>{done + 11}<span>/ 18</span></strong><em><TrendingUp size={13} /> 18% this week</em></div></article>
<article className="metric panel"><span className="metric-icon coral"><Flame /></span><div><small>Best streak</small><strong>18 <span>days</span></strong><em>Morning walk</em></div></article>
<article className="metric panel"><span className="metric-icon mint"><Clock3 /></span><div><small>Focused time</small><strong>14.5 <span>hrs</span></strong><em><TrendingUp size={13} /> 2.1h vs last week</em></div></article>
</section>
<section className="main-grid">
<article className="panel today-panel">
<header className="panel-header"><div><p className="eyebrow">Monday, July 13</p><h2>Todays plan</h2></div><button className="text-button" onClick={() => onNavigate("Tasks")}>All tasks <ChevronRight size={15} /></button></header>
<div className="task-list">
{tasks.slice(0, 4).map(task => <div className={`task-row ${task.done ? "is-done" : ""}`} key={task.id}>
<button className="check-button" onClick={() => onToggleTask(task.id)} aria-label={`${task.done ? "Reopen" : "Complete"} ${task.title}`}>{task.done ? <Check size={15} /> : <Circle size={17} />}</button>
<div className="task-copy"><strong>{task.title}</strong><span><i className={`dot ${task.domain.toLowerCase()}`} />{task.project} · {task.time}</span></div>
<span className={`priority ${task.priority.toLowerCase()}`}>{task.priority}</span><button className="icon-button" aria-label={`More options for ${task.title}`}><MoreHorizontal size={17} /></button>
</div>)}
</div>
<button className="add-row"><Plus size={16} /> Add a task</button>
</article>
<article className="panel habits-panel">
<header className="panel-header"><div><p className="eyebrow">Daily rhythm</p><h2>Habits</h2></div><span className="completion-badge">{Object.values(habitDone).filter(Boolean).length}/4 done</span></header>
<div className="habit-list">
{habits.map(habit => { const isDone = habitDone[habit.id]; return <button className={`habit-row ${isDone ? "is-done" : ""}`} key={habit.id} onClick={() => onToggleHabit(habit.id)}>
<span className={`habit-icon ${habit.color}`}>{habit.icon}</span><span className="habit-copy"><strong>{habit.name}</strong><small><Flame size={12} fill="currentColor" /> {habit.streak} day streak</small></span><span className="habit-check">{isDone && <Check size={15} />}</span>
</button>})}
</div>
</article>
<article className="panel week-panel">
<header className="panel-header"><div><p className="eyebrow">July 713</p><h2>Weekly pulse</h2></div><button className="icon-button" aria-label="Weekly pulse options"><MoreHorizontal size={18} /></button></header>
<div className="chart-summary"><div><strong>76%</strong><span>completion rate</span></div><em><TrendingUp size={14} /> +8% vs last week</em></div>
<div className="bar-chart" aria-label="Weekly completion chart">{week.map((d, i) => <div className="bar-wrap" key={`${d.day}-${i}`}><span className={i === 3 ? "active" : ""} style={{ height: `${d.value}%` }} /><small>{d.day}</small></div>)}</div>
</article>
<article className="panel projects-panel">
<header className="panel-header"><div><p className="eyebrow">Across your life</p><h2>Active projects</h2></div><button className="text-button" onClick={() => onNavigate("Projects")}>View all <ChevronRight size={15} /></button></header>
<div className="project-list">{projects.map(p => <button className="project-row" key={p.name} onClick={() => onNavigate("Projects")}><span className="project-icon" style={{ background: p.color }}>{p.icon}</span><span className="project-copy"><span><strong>{p.name}</strong><small>{p.tasks} tasks</small></span><Progress value={p.progress} color={p.color} /></span><strong className="project-percent">{p.progress}%</strong></button>)}</div>
</article>
<article className="panel agent-panel">
<div className="agent-glow"><Bot size={25} /></div><div><p className="eyebrow">Agent workspace</p><h2>Hermes finished a task</h2><p>Project health brief is ready to review, with 3 risks and 5 next actions.</p></div><button className="secondary-button" onClick={() => onNavigate("Agent Activity")}>Review result <ChevronRight size={15} /></button>
</article>
</section>
</>;
}
function TasksView({ tasks, onToggle }: { tasks: Task[]; onToggle: (id: number) => void }) {
return <section className="view-stack"><div className="view-toolbar"><div className="segmented"><button className="active">Board</button><button>List</button></div><div className="toolbar-actions"><button className="secondary-button"><Search size={15} /> Filter</button><button className="primary-button"><Plus size={15} /> New task</button></div></div><div className="kanban">{(["To do", "In progress", "Done"] as const).map(status => <div className="kanban-column" key={status}><header><span><i className={`status-dot status-${status.replace(" ", "-").toLowerCase()}`} />{status}</span><small>{tasks.filter(t => t.status === status).length}</small><Plus size={15} /></header><div className="kanban-cards">{tasks.filter(t => t.status === status).map(task => <article className={`kanban-card ${task.done ? "is-done" : ""}`} key={task.id}><div className="kanban-top"><GripVertical size={15} /><span className={`priority ${task.priority.toLowerCase()}`}>{task.priority}</span><MoreHorizontal size={16} /></div><button onClick={() => onToggle(task.id)}><span className="task-check">{task.done && <Check size={13} />}</span><strong>{task.title}</strong></button><p>{task.project}</p><footer><span><CalendarDays size={13} /> {task.time}</span><span className={`domain-pill ${task.domain.toLowerCase()}`}>{task.domain}</span></footer></article>)}</div><button className="add-card"><Plus size={15} /> Add task</button></div>)}</div></section>;
}
function HabitsView({ habitDone, onToggle }: { habitDone: Record<number, boolean>; onToggle: (id: number) => void }) {
return <section className="view-stack"><div className="habit-score-banner panel"><div><p className="eyebrow">Your rhythm</p><h2>Consistency is compounding</h2><p>You completed 86% of scheduled habits in the past 30 days.</p></div><div className="score-ring small"><strong>86</strong><span>score</span></div></div><div className="habit-grid">{habits.map(h => <article className="habit-card panel" key={h.id}><div className="habit-card-top"><span className={`habit-icon large ${h.color}`}>{h.icon}</span><button className="icon-button"><MoreHorizontal size={18} /></button></div><h3>{h.name}</h3><p>Every day · Personal</p><div className="streak-line"><Flame size={18} fill="currentColor" /><strong>{h.streak}</strong><span>day streak</span></div><div className="mini-heat">{Array.from({ length: 28 }).map((_, i) => <i className={i % 7 === 5 || i > 24 ? "low" : i % 5 === 0 ? "mid" : "high"} key={i} />)}</div><button className={`habit-complete ${habitDone[h.id] ? "done" : ""}`} onClick={() => onToggle(h.id)}>{habitDone[h.id] ? <><Check size={16} /> Completed today</> : <><Circle size={16} /> Mark complete</>}</button></article>)}</div></section>;
}
function ProjectsView() {
return <section className="view-stack"><div className="view-toolbar"><div className="filter-pills"><button className="active">Active <span>3</span></button><button>Paused <span>1</span></button><button>Archived <span>6</span></button></div><button className="primary-button"><Plus size={15} /> New project</button></div><div className="projects-grid">{projects.map((p, index) => <article className="project-card panel" key={p.name}><header><span className="project-icon large" style={{ background: p.color }}>{p.icon}</span><span className={`domain-pill ${p.domain.toLowerCase()}`}>{p.domain}</span><button className="icon-button"><MoreHorizontal size={18} /></button></header><h2>{p.name}</h2><p>{index === 0 ? "A calm, agent-native system for every commitment." : index === 1 ? "Make the storefront and campaigns work as one growth engine." : "Build routines and systems that create more spacious days."}</p><div className="project-meta"><span><strong>{p.progress}%</strong> complete</span><span>{p.tasks} tasks</span></div><Progress value={p.progress} color={p.color} /><footer><span><CalendarDays size={14} /> {p.due}</span><span className="avatar-stack"><i>M</i><i>H</i></span></footer></article>)}</div></section>;
}
function NotesView() {
const notes = ["Project E — product principles", "July operating review", "OTS campaign concepts", "Reading notes: Slow Productivity"];
const [selected, setSelected] = useState(notes[0]);
return <section className="notes-shell panel"><aside><header><strong>Notes</strong><button className="icon-button"><Plus size={17} /></button></header><label className="notes-search"><Search size={14} /><input placeholder="Search notes…" /></label>{notes.map((n, i) => <button key={n} className={selected === n ? "active" : ""} onClick={() => setSelected(n)}><strong>{n}</strong><span>{i === 0 ? "Updated 18m ago" : `${i + 1} days ago`}</span></button>)}</aside><article className="note-editor"><header><div className="breadcrumb">Notes <ChevronRight size={13} /> <span>Work</span></div><div><button className="icon-button"><Bot size={17} /></button><button className="icon-button"><MoreHorizontal size={17} /></button></div></header><div className="note-body"><p className="eyebrow"># project-e · work · strategy</p><h1>{selected}</h1><p className="note-lede">A personal operating system should reduce cognitive weight, not become another system to maintain.</p><h2>North star</h2><p>Project E brings tasks, habits, projects, and knowledge into one calm surface. The model stays flexible; views do the organizing.</p><blockquote><Sparkles size={18} /> Design for the moment a person returns after a chaotic week. The system should make the next step obvious.</blockquote><h2>Working principles</h2><ul><li><span>01</span> Three equal pillars, never one buried inside another.</li><li><span>02</span> Capture quickly, organize progressively.</li><li><span>03</span> External agents operate through explicit permissions.</li></ul></div></article></section>;
}
function ReportsView() {
const items = [{ icon: BarChart3, title: "Weekly Summary", sub: "Jul 713", color: "blue" }, { icon: CalendarDays, title: "Monthly Review", sub: "June 2026", color: "mint" }, { icon: Target, title: "Project Health", sub: "Project E", color: "coral" }, { icon: Flame, title: "Habit Analysis", sub: "Last 30 days", color: "amber" }];
return <section className="view-stack"><div className="report-hero panel"><div><p className="eyebrow">Reports</p><h2>Turn activity into perspective.</h2><p>Generate a structured review from your actual work, habits, and time.</p></div><button className="primary-button"><Sparkles size={15} /> Generate report</button></div><div className="report-grid">{items.map(({ icon: Icon, ...r }) => <article className="report-card panel" key={r.title}><span className={`metric-icon ${r.color}`}><Icon /></span><div><h3>{r.title}</h3><p>{r.sub}</p></div><span className="report-status">Ready</span><button className="text-button">Open <ChevronRight size={14} /></button></article>)}</div><article className="panel recent-table"><header className="panel-header"><h2>Recent reports</h2><button className="text-button">View archive</button></header>{["Project E weekly health", "June time audit", "OTS campaign retrospective"].map((name, i) => <div className="table-row" key={name}><span className="file-icon"><FileBarChart size={17} /></span><strong>{name}</strong><span>{i === 0 ? "Weekly" : i === 1 ? "Time audit" : "Custom"}</span><span>Jul {13 - i * 4}</span><button className="icon-button"><MoreHorizontal size={17} /></button></div>)}</article></section>;
}
function CalendarView() {
const days = Array.from({ length: 35 }, (_, i) => i - 1);
return <section className="calendar-shell panel"><header><div><button className="secondary-button">Today</button><button className="icon-button"></button><button className="icon-button"></button><h2>July 2026</h2></div><div className="segmented"><button className="active">Month</button><button>Week</button><button>Day</button></div></header><div className="calendar-grid">{["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map(d => <strong className="weekday" key={d}>{d}</strong>)}{days.map((d, i) => <div className={`calendar-day ${d === 13 ? "today" : ""} ${d < 1 || d > 31 ? "muted" : ""}`} key={i}><span>{d < 1 ? 29 + d : d > 31 ? d - 31 : d}</span>{d === 13 && <><em className="event work">9:00 Product brief</em><em className="event ots">11:30 OTS copy</em><em className="event personal">4:00 Strength</em></>}{d === 15 && <em className="event work">Project milestone</em>}{d === 17 && <em className="event personal">Trip planning</em>}</div>)}</div></section>;
}
function AnalyticsView() {
return <section className="view-stack"><div className="analytics-metrics"><article className="panel"><small>Completion rate</small><strong>76%</strong><span className="up"><TrendingUp size={14} /> 8.2%</span></article><article className="panel"><small>Habit consistency</small><strong>86%</strong><span className="up"><TrendingUp size={14} /> 4.1%</span></article><article className="panel"><small>Deep work</small><strong>14.5h</strong><span className="up"><TrendingUp size={14} /> 2.1h</span></article><article className="panel"><small>Active streaks</small><strong>4</strong><span>Best: 18 days</span></article></div><div className="analytics-grid"><article className="panel trend-card"><header className="panel-header"><div><p className="eyebrow">12 week view</p><h2>Productivity trend</h2></div><div className="segmented"><button className="active">Tasks</button><button>Habits</button></div></header><div className="area-chart">{[35, 47, 42, 58, 54, 69, 63, 77, 72, 88, 80, 92].map((v, i) => <i key={i} style={{ height: `${v}%` }}><span>{v}</span></i>)}</div></article><article className="panel distribution-card"><p className="eyebrow">Time distribution</p><h2>Where time went</h2><div className="donut"><div><strong>14.5h</strong><span>tracked</span></div></div><ul><li><i className="work" />Work <strong>48%</strong></li><li><i className="ots" />OTS <strong>31%</strong></li><li><i className="personal" />Personal <strong>21%</strong></li></ul></article></div></section>;
}
function AgentView() {
const events = [{ type: "done", icon: Check, title: "Completed “Project health brief”", agent: "Hermes", time: "12 minutes ago", text: "Created a report with 3 risks, 5 actions, and a milestone forecast." }, { type: "working", icon: Activity, title: "Analyzing OTS campaign performance", agent: "Hermes", time: "Started 28 minutes ago", text: "Reviewing 14 tasks and 3 linked notes." }, { type: "created", icon: Plus, title: "Created note “July research synthesis”", agent: "Claude", time: "Yesterday, 4:18 PM", text: "Generated from 8 source notes with backlinks preserved." }];
return <section className="agent-layout"><article className="panel agent-summary"><div className="agent-avatar"><Bot size={28} /></div><div><p className="eyebrow">Active agent</p><h2>Hermes</h2><p>Planning and analysis partner · Full access</p></div><span className="online"><i /> Online</span><div className="agent-stats"><span><strong>24</strong>actions</span><span><strong>8</strong>tasks</span><span><strong>4</strong>reports</span></div><button className="secondary-button">Open workspace</button></article><article className="panel activity-feed"><header className="panel-header"><div><p className="eyebrow">Audit trail</p><h2>Agent activity</h2></div><button className="secondary-button">All agents <ChevronDown size={14} /></button></header>{events.map(({ icon: Icon, ...event }) => <div className="activity-row" key={event.title}><span className={`activity-icon ${event.type}`}><Icon size={16} /></span><div><strong>{event.title}</strong><p>{event.text}</p><span>{event.agent} · {event.time}</span></div><button className="text-button">Details</button></div>)}</article></section>;
}
function SettingsView() {
return <section className="settings-layout"><aside className="panel"><button className="active">Appearance</button><button>Domains</button><button>Keyboard shortcuts</button><button>Agents & permissions</button><button>Webhooks</button><button>Import & export</button></aside><article className="panel settings-content"><p className="eyebrow">Preferences</p><h2>Appearance</h2><p>Make Project E feel right for the way you work.</p><div className="setting-row"><div><strong>Color mode</strong><span>Use a light or dark interface.</span></div><div className="segmented"><button className="active">Light</button><button>Dark</button><button>System</button></div></div><div className="setting-row"><div><strong>Accent color</strong><span>Used for actions and progress.</span></div><div className="swatches"><button className="active blue" aria-label="Blue" /><button className="green" aria-label="Green" /><button className="coral" aria-label="Coral" /><button className="violet" aria-label="Violet" /></div></div><div className="setting-row"><div><strong>Density</strong><span>Control information spacing.</span></div><div className="segmented"><button>Compact</button><button className="active">Comfortable</button><button>Spacious</button></div></div><div className="setting-row"><div><strong>Reduced motion</strong><span>Minimize interface animation.</span></div><button className="switch" aria-label="Toggle reduced motion"><span /></button></div></article></section>;
}
function CommandPalette({ onClose, onNavigate }: { onClose: () => void; onNavigate: (v: View) => void }) {
const [query, setQuery] = useState("");
const results = nav.filter(n => n.label.toLowerCase().includes(query.toLowerCase()));
return <div className="modal-backdrop" onMouseDown={onClose}><div className="command-modal" role="dialog" aria-modal="true" aria-label="Command palette" onMouseDown={e => e.stopPropagation()}><label><Search size={19} /><input autoFocus value={query} onChange={e => setQuery(e.target.value)} placeholder="Search Project E or run a command…" /><kbd>esc</kbd></label><div className="command-results"><p>Jump to</p>{results.map(({ label, icon: Icon }) => <button key={label} onClick={() => { onNavigate(label); onClose(); }}><Icon size={17} /><span>{label}</span><kbd></kbd></button>)}</div><footer><span><kbd></kbd><kbd></kbd> navigate</span><span><kbd></kbd> open</span></footer></div></div>;
}
export default function ProjectEApp() {
const [view, setView] = useState<View>("Dashboard");
const [tasks, setTasks] = useState(initialTasks);
const [habitDone, setHabitDone] = useState<Record<number, boolean>>({ 1: true, 2: false, 3: false, 4: false });
const [domain, setDomain] = useState("All domains");
const [commandOpen, setCommandOpen] = useState(false);
const [mobileNav, setMobileNav] = useState(false);
const [timerActive, setTimerActive] = useState(false);
useEffect(() => {
const onKey = (event: KeyboardEvent) => {
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") { event.preventDefault(); setCommandOpen(true); }
if (event.key === "Escape") { setCommandOpen(false); setMobileNav(false); }
};
window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey);
}, []);
const filteredTasks = useMemo(() => domain === "All domains" ? tasks : tasks.filter(t => t.domain === domain), [tasks, domain]);
const toggleTask = (id: number) => setTasks(current => current.map(t => t.id === id ? { ...t, done: !t.done, status: !t.done ? "Done" : "To do" } : t));
const navigate = (next: View) => { setView(next); setMobileNav(false); window.scrollTo({ top: 0, behavior: "smooth" }); };
let content;
if (view === "Dashboard") content = <Dashboard tasks={filteredTasks} onToggleTask={toggleTask} habitDone={habitDone} onToggleHabit={id => setHabitDone(v => ({ ...v, [id]: !v[id] }))} onNavigate={navigate} />;
else if (view === "Tasks") content = <TasksView tasks={filteredTasks} onToggle={toggleTask} />;
else if (view === "Habits") content = <HabitsView habitDone={habitDone} onToggle={id => setHabitDone(v => ({ ...v, [id]: !v[id] }))} />;
else if (view === "Projects") content = <ProjectsView />;
else if (view === "Notes") content = <NotesView />;
else if (view === "Reports") content = <ReportsView />;
else if (view === "Calendar") content = <CalendarView />;
else if (view === "Analytics") content = <AnalyticsView />;
else if (view === "Agent Activity") content = <AgentView />;
else content = <SettingsView />;
return <div className="app-shell">
<a href="#main" className="skip-link">Skip to content</a>
<aside className={`sidebar ${mobileNav ? "open" : ""}`}>
<div className="sidebar-top"><Logo /><button className="close-mobile icon-button" onClick={() => setMobileNav(false)} aria-label="Close navigation"><X size={19} /></button></div>
<nav aria-label="Main navigation">{nav.slice(0, 8).map(({ label, icon: Icon }) => <button key={label} className={view === label ? "active" : ""} onClick={() => navigate(label)}><Icon size={18} /><span>{label}</span>{label === "Tasks" && <em>6</em>}</button>)}</nav>
<div className="sidebar-section"><p>Workspace</p>{nav.slice(8).map(({ label, icon: Icon }) => <button key={label} className={view === label ? "active" : ""} onClick={() => navigate(label)}><Icon size={18} /><span>{label}</span>{label === "Agent Activity" && <i className="live-dot" />}</button>)}</div>
<button className={`focus-mini ${timerActive ? "active" : ""}`} onClick={() => setTimerActive(v => !v)}><span className="focus-mini-icon">{timerActive ? <Pause size={17} fill="currentColor" /> : <TimerReset size={18} />}</span><span><strong>{timerActive ? "24:32" : "Focus timer"}</strong><small>{timerActive ? "Project E brief" : "Ready when you are"}</small></span><ChevronRight size={15} /></button>
<div className="profile"><span className="profile-avatar">ME</span><span><strong>Matt</strong><small>Personal workspace</small></span><MoreHorizontal size={17} /></div>
</aside>
{mobileNav && <button className="nav-scrim" aria-label="Close navigation" onClick={() => setMobileNav(false)} />}
<div className="workspace">
<header className="topbar"><button className="mobile-menu icon-button" onClick={() => setMobileNav(true)} aria-label="Open navigation"><Menu size={20} /></button><button className="command-trigger" onClick={() => setCommandOpen(true)}><Search size={16} /><span>Search or jump to</span><kbd><Command size={11} /> K</kbd></button><div className="top-actions"><label className="domain-select"><span className={`dot ${domain === "Work" ? "work" : domain === "OTS" ? "ots" : domain === "Personal" ? "personal" : "all"}`} /><select value={domain} onChange={e => setDomain(e.target.value)} aria-label="Filter by domain"><option>All domains</option><option>Personal</option><option>Work</option><option>OTS</option></select><ChevronDown size={13} /></label><button className="icon-button notification" aria-label="Notifications"><Bell size={18} /><i /></button><button className="quick-add" onClick={() => setCommandOpen(true)}><Plus size={17} /> <span>Quick add</span></button></div></header>
<main id="main"><header className="page-heading"><div><p className="eyebrow">{view === "Dashboard" ? "Your day, at a glance" : "Project E"}</p><h1>{view === "Dashboard" ? "Good morning, Matt." : view}</h1><p>{view === "Dashboard" ? "Monday, July 13 · You have 3 priorities and 4 habits today." : view === "Tasks" ? "Move work forward without losing the thread." : view === "Habits" ? "Small actions, visible momentum." : view === "Projects" ? "Every outcome has a home." : view === "Notes" ? "Connect ideas to the work they shape." : view === "Reports" ? "Step back and see what changed." : view === "Calendar" ? "Your commitments, in time." : view === "Analytics" ? "Patterns behind your progress." : view === "Agent Activity" ? "Every agent action, visible and reversible." : "Tune Project E to fit your work."}</p></div>{view !== "Dashboard" && view !== "Settings" && <button className="primary-button"><Plus size={15} /> New {view === "Agent Activity" ? "agent" : view.replace(/s$/, "").toLowerCase()}</button>}</header>{content}</main>
</div>
{commandOpen && <CommandPalette onClose={() => setCommandOpen(false)} onNavigate={navigate} />}
</div>;
}