// Brain Zips — quick capture for an ADHD brain. // Tabs: All (active) / Zips / Ideas / Done // Each item: checkbox to mark done, flag to mark "priority/important", // promote-to-priority action moves it into a weekly priority slot. // // Persistence: all items stored to localStorage via the store provider. function BrainDump() { const { state, addBrainItem, deleteBrainItem, promoteBrainItem, toggleBrainDone, toggleBrainFlag } = useStore(); const [tab, _setTab] = React.useState('all'); // all | dump | idea | done const [draft, setDraft] = React.useState(''); const [kind, setKind] = React.useState('dump'); const inputRef = React.useRef(null); // Switching tabs sets the default save-kind so typing on the Ideas tab // saves as an idea, typing on the Zips tab saves as a zip. (User can // still flip the toggle manually.) const setTab = (next) => { _setTab(next); if (next === 'idea') setKind('idea'); else if (next === 'dump') setKind('dump'); else if (next === 'all') setKind('dump'); // sensible default on All }; const submit = (e) => { e?.preventDefault(); if (!draft.trim()) return; addBrainItem(draft.trim(), kind); setDraft(''); // If user is staring at the Ideas tab, they're clearly capturing ideas — // don't whisk it away to All. Jump them to wherever it landed. if (kind === 'idea' && tab !== 'idea' && tab !== 'all') _setTab('idea'); if (kind === 'dump' && tab !== 'dump' && tab !== 'all') _setTab('dump'); inputRef.current?.focus(); }; // Filter logic — fixes the previous "ideas leak everywhere" issue. // "All" shows everything that's NOT done (mix of zips + ideas) // "Zips" shows only kind=dump, not done // "Ideas" shows only kind=idea, not done // "Done" shows done items regardless of kind const items = state.braindump.filter((b) => { if (tab === 'done') return b.done; if (b.done) return false; if (tab === 'all') return true; return b.kind === tab; }); // Flagged items float to the top within each list items.sort((a, b) => (b.flagged ? 1 : 0) - (a.flagged ? 1 : 0)); const counts = { all: state.braindump.filter((b) => !b.done).length, dump: state.braindump.filter((b) => !b.done && b.kind === 'dump').length, idea: state.braindump.filter((b) => !b.done && b.kind === 'idea').length, done: state.braindump.filter((b) => b.done).length, }; const promoteDisabled = state.priorities.length >= 4; return (
Brain zips
setDraft(e.target.value)} placeholder={kind === 'idea' ? 'New idea…' : 'Zip it out of your head…'} />
{items.length === 0 && (
{tab === 'done' ? 'Nothing checked off yet.' : 'Empty. Capture now, sort later — ↵ saves.'}
)} {items.map((b) => { const age = relTime(b.at); return (
toggleBrainDone(b.id)} title={b.done ? 'Mark as not done' : 'Mark as done'}> {b.done && } {b.kind === 'idea' ? : } {b.text} {age}
); })}
{counts.all} active · {counts.idea} ideas · {counts.done} done = priority
); } function relTime(iso) { const then = new Date(iso); const now = new Date(); const days = Math.floor((now - then) / 86400000); if (days <= 0) return 'today'; if (days === 1) return '1d'; if (days < 7) return days + 'd'; if (days < 30) return Math.floor(days / 7) + 'w'; return Math.floor(days / 30) + 'mo'; } Object.assign(window, { BrainDump });