// App shell + Tweaks panel + Windows chrome const { useState, useEffect, useRef, useMemo } = window.React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accentHue": 88, "islandGap": 14, "islandRadius": 14, "grainOpacity": 0.035, "density": "comfy", "sidebarWidth": 260 }/*EDITMODE-END*/; const HUE_PRESETS = [ { name: 'Moss', h: 88 }, { name: 'Sea', h: 200 }, { name: 'Peat', h: 60 }, { name: 'Heather', h: 310 }, { name: 'Rust', h: 30 }, ]; const TweaksPanel = ({ open, onClose, tweaks, setTweaks }) => { const update = (k, v) => { const next = { ...tweaks, [k]: v }; setTweaks(next); try { window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [k]: v } }, '*'); } catch (e) {} }; return (
Tweaks
Accent H {tweaks.accentHue}
{HUE_PRESETS.map((p) => (
update('accentHue', p.h)} /> ))} update('accentHue', +e.target.value)} style={{ flex: 1, marginLeft: 6 }} />
Gap update('islandGap', +e.target.value)} /> {tweaks.islandGap}px
Radius update('islandRadius', +e.target.value)} /> {tweaks.islandRadius}px
Grain update('grainOpacity', +e.target.value)} /> {tweaks.grainOpacity.toFixed(3)}
Sidebar update('sidebarWidth', +e.target.value)} /> {tweaks.sidebarWidth}
Density
); }; // Windows chrome const TitleBar = ({ search }) => { return (
ClaudeDo · Rider Island
); }; const Taskbar = () => { const [clock, setClock] = useState(() => { const n = new Date(); return { time: n.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), date: n.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }), }; }); useEffect(() => { const id = setInterval(() => { const n = new Date(); setClock({ time: n.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), date: n.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }), }); }, 30000); return () => clearInterval(id); }, []); const icons = ['windows', 'search', 'folder', 'inbox', 'note', 'calendar']; return (
{icons.map((ic, i) => (
))}
{clock.time}
{clock.date}
); }; // ---------- App ---------- const App = () => { const [tweaks, setTweaks] = useState(TWEAK_DEFAULTS); const [tweaksOpen, setTweaksOpen] = useState(false); const [editMode, setEditMode] = useState(false); const [tasks, setTasks] = useState(SEED_TASKS); const [activeList, setActiveList] = useState('myday'); const [selectedId, setSelectedId] = useState('t1'); const [search, setSearch] = useState(''); const [showCompleted, setShowCompleted] = useState(true); const [leavingIds, setLeavingIds] = useState([]); const [enteringIds, setEnteringIds] = useState([]); const [diffTaskId, setDiffTaskId] = useState(null); const [worktreeTaskId, setWorktreeTaskId] = useState(null); // Apply CSS tweaks useEffect(() => { const r = document.documentElement; r.style.setProperty('--accent-h', tweaks.accentHue); r.style.setProperty('--island-gap', tweaks.islandGap + 'px'); r.style.setProperty('--island-radius', tweaks.islandRadius + 'px'); r.style.setProperty('--grain-opacity', tweaks.grainOpacity); r.style.setProperty('--sidebar-w', tweaks.sidebarWidth + 'px'); r.style.setProperty('--density', tweaks.density === 'comfy' ? 1 : 0.82); }, [tweaks]); // Tweaks host protocol useEffect(() => { const onMsg = (e) => { const d = e.data; if (!d || typeof d !== 'object') return; if (d.type === '__activate_edit_mode') { setEditMode(true); setTweaksOpen(true); } if (d.type === '__deactivate_edit_mode') { setEditMode(false); setTweaksOpen(false); } }; window.addEventListener('message', onMsg); try { window.parent.postMessage({ type: '__edit_mode_available' }, '*'); } catch (e) {} return () => window.removeEventListener('message', onMsg); }, []); // Counts per list const counts = useMemo(() => { const c = {}; c.myday = tasks.filter((t) => t.myDay && !t.done).length; c.important = tasks.filter((t) => t.starred && !t.done).length; c.planned = tasks.filter((t) => t.due && !t.done).length; c.assigned = 0; c.flagged = 0; c.all = tasks.filter((t) => !t.done).length; SEED_USER_LISTS.forEach((l) => { c[l.id] = tasks.filter((t) => t.list === l.id && !t.done).length; }); return c; }, [tasks]); // Filter tasks const visibleTasks = useMemo(() => { let ts = tasks; if (activeList === 'myday') ts = ts.filter((t) => t.myDay); else if (activeList === 'important') ts = ts.filter((t) => t.starred); else if (activeList === 'planned') ts = ts.filter((t) => t.due); else if (activeList === 'all') ts = ts; else if (activeList === 'assigned' || activeList === 'flagged') ts = []; else ts = ts.filter((t) => t.list === activeList); if (search) { const q = search.toLowerCase(); ts = ts.filter((t) => t.title.toLowerCase().includes(q) || (t.notes || '').toLowerCase().includes(q)); } return ts; }, [tasks, activeList, search]); const selected = tasks.find((t) => t.id === selectedId); // Actions const toggleTask = (id) => { setTasks((prev) => prev.map((t) => t.id === id ? { ...t, done: !t.done, completedAt: !t.done ? new Date().toISOString() : null } : t )); }; const starTask = (id) => { setTasks((prev) => prev.map((t) => t.id === id ? { ...t, starred: !t.starred } : t)); }; const updateTask = (next) => { setTasks((prev) => prev.map((t) => t.id === next.id ? next : t)); }; const deleteTask = (id) => { setLeavingIds((l) => [...l, id]); setTimeout(() => { setTasks((prev) => prev.filter((t) => t.id !== id)); setLeavingIds((l) => l.filter((x) => x !== id)); if (selectedId === id) setSelectedId(null); }, 280); }; const addTask = (title) => { const id = 't' + Date.now(); const newTask = { id, title, list: ['myday','important','planned','running','review','all'].includes(activeList) ? 'claudedo' : activeList, myDay: true, starred: false, due: new Date().toISOString(), notes: '', tags: [], subtasks: [], created: new Date().toISOString(), done: false, agent: { status: 'idle', model: 'claude-sonnet-4.5', worktree: `~/worktrees/${activeList}/new-task-${id.slice(1,6)}`, branch: `agent/new-task-${id.slice(1,6)}`, baseBranch: 'main', commits: 0, diff: { files: 0, additions: 0, deletions: 0 }, turns: 0, tokens: 0, log: [{ t: new Date().toISOString(), k: 'sys', m: 'Worktree ready. Agent not yet dispatched.' }], }, }; setTasks((prev) => [newTask, ...prev]); setEnteringIds((l) => [...l, id]); setSelectedId(id); setTimeout(() => setEnteringIds((l) => l.filter((x) => x !== id)), 300); }; const agentAction = (id, action) => { setTasks((prev) => prev.map((t) => { if (t.id !== id || !t.agent) return t; if (action === 'start') { return { ...t, agent: { ...t.agent, status: 'running', startedAt: new Date().toISOString(), log: [...(t.agent.log || []), { t: new Date().toISOString(), k: 'sys', m: 'Agent dispatched.' }] } }; } if (action === 'stop') { return { ...t, agent: { ...t.agent, status: 'review', finishedAt: new Date().toISOString(), log: [...(t.agent.log || []), { t: new Date().toISOString(), k: 'sys', m: 'Stopped by operator.' }] } }; } return t; })); }; const agentInput = (id, msg) => { setTasks((prev) => prev.map((t) => { if (t.id !== id || !t.agent) return t; return { ...t, agent: { ...t.agent, log: [...(t.agent.log || []), { t: new Date().toISOString(), k: 'msg', m: '[you] ' + msg }] } }; })); }; return (
{ setActiveList(id); }} counts={counts} search={search} setSearch={setSearch} />
setDiffTaskId(id)} onOpenWorktree={(id) => setWorktreeTaskId(id)} />
{diffTaskId && ( t.id === diffTaskId)} onClose={() => setDiffTaskId(null)} /> )} {worktreeTaskId && ( t.id === worktreeTaskId)} onClose={() => setWorktreeTaskId(null)} /> )} {/* Tweaks: FAB (when edit mode is off) or panel (when toggled) */} {editMode && ( setTweaksOpen(false)} tweaks={tweaks} setTweaks={setTweaks} /> )}
); }; // The inner window shouldn't render TitleBar twice — fix: // Actually we want ONE window with one titlebar. Remove the outer TitleBar. const AppFixed = () => ; ReactDOM.createRoot(document.getElementById('root')).render();