Tasks
StableThe whole task tracker: a keyboard-first list and board, a detail view, bulk edits, and undo for every change.
TasksApp is the complete tool inside the RChursin_ app window: search and quick filters, a list grouped by status, assignee or priority, a board, a detail view, a create dialog and a shortcuts dialog. Its one prop, hrefFor, says where the window’s links to the other tools go. It saves tasks, view settings and collapsed groups to this browser (localStorage) until you connect a backend; “Reset sample data” brings the twelve sample tasks back.
The tracker
import { useRouter } from '@rchursin/product/lib/router'import type { KitSlug } from '@rchursin/product/shell/pages'import { TasksApp } from '@rchursin/product/tasks'
/** The window's tool links go to each tool's page in this Library (Today has none, so it shows as text) */const toolPages: Partial<Record<KitSlug, string>> = { tasks: '/library/tools/tasks-app', calendar: '/library/tools/calendar-app', timer: '/library/tools/timer-app', notes: '/library/tools/notes-app',}
/** * The whole tracker on sample data. Click into the list, then try J and K, X to select, * S for status, Ctrl+B (⌘B) for the board, or ? for every shortcut. * Changes save to this browser; "Reset sample data" brings the twelve tasks back. */export default function TasksAppExample() { const { href } = useRouter() const hrefFor = (slug: KitSlug) => { const path = toolPages[slug] return path && href(path) } return <TasksApp hrefFor={hrefFor} />}Usage
import { TasksApp } from '@rchursin/product/tasks'<TasksApp />API
TasksApp props
| Prop | Type | Default | Description |
|---|---|---|---|
hrefFor | (slug: KitSlug) => string | undefined | – | Where the window’s tool links (Today, Calendar, Focus, Notes) go: your own pages. The default is the product kit’s own #tasks, #calendar … anchors; return undefined to show a tool as plain text. |
The task store
| Prop | Type | Default | Description |
|---|---|---|---|
useTaskState() | { tasks: Task[]; labels: Label[] } | – | Subscribes to the one task store on the page. labels holds only the labels people created; labelIndex(labels).all adds the six sample ones. |
useTaskActions() | TaskActions | – | setStatus, setPriority, setAssignee, setDue, setEstimate, applyLabels + recordLabels, edit, move, remove, create and undo. Each change updates the screen at once and shows a past-tense toast with Undo (edit is undoable with ⌘Z but has no toast; create returns the task and leaves the toast to you). |
taskStore | object | – | The store itself: get(), subscribe(), commit(label, update), apply(update), record(label, start), undo(id?), canUndo(), nextId(), addLabel(name) and reset(). It saves to this browser under “tasks:items” and “tasks:labels”. |
Accessibility
Keyboard
| Key | What it does |
|---|---|
| JDown arrow | Next task (in the list, ↓ also visits group headers). |
| KUp arrow | Previous task. |
| Enter | Open the highlighted task: a side panel when the window is 860px or wider, a dialog when it is narrower. |
| C | Create a task. |
| / | Focus the search field. |
| XShiftSpace | Select or deselect the highlighted task. |
| ShiftDown arrowShiftUp arrow | Extend the selection (list). |
| CtrlA | Select every task shown. |
| SPAL | Status, priority, assignee or labels picker for the selection, the highlighted task, or the open task. |
| ShiftDShiftE | Due date or estimate picker. |
| I | Assign to me. |
| CtrlBackspace | Delete, with Undo in the toast. |
| CtrlZ | Undo the last change, even after its toast has gone. |
| CtrlB | Switch between list and board. |
| Esc | Clear the selection, then close the side panel. |
| ? | Show every shortcut. |
- The window is a region named “Tasks app (sample workspace)”. Its shortcuts are scoped to it: they only fire while focus is inside, never while you type in a field, and stay quiet while a menu, popover or dialog has focus.
- The list is a data grid with a single Tab stop, and on the board one card at a time is in the Tab order (with its grip and menu); arrows and J / K move inside.
- Every change happens at once and ends in a polite toast with one Undo. Search results are announced once typing settles (“4 tasks shown”), and so are selection changes and the switch between list and board.
- Focus is kept on purpose: when a change moves a task to another group or column, focus follows it; after a delete it moves to the next task; dialogs hand focus back to what opened them.
- Status and priority are drawn as shapes, never colours, and every icon that carries meaning has a name (“Status: In review”).
- The site search also listens for “/” on the whole page, but while focus is inside the window the app’s own “/” runs first (scoped shortcuts win over page-wide ones), so it focuses the Tasks search.
Guidelines
Do
- Give the window about 720px of height, and 860px of width if you want the side panel instead of a dialog.
- Point people to the ? button in the toolbar: it lists every shortcut.
- Pass hrefFor, so the window’s Calendar, Focus and Notes links go to your own pages.
- When you connect a backend, swap the saving in store.ts and keep commit(): every change already goes through it, so Undo keeps working.
Don’t
- Don’t put two TasksApps on one page: they share one store and one saved view, and both windows would carry the same region and navigation names.
- Don’t add an unscoped shortcut for a key the tool uses (/, c, j, k…); give useHotkeys a scope so each tool keeps its keys.
- Don’t ship the sample badge and “Reset sample data” to real users; they are for demos.
In use
Related
- Task listThe task list as a data grid: one Tab stop, arrows to move, pickers in the cells, and groups that collapse.
- Task boardA column per status, with cards moved by dragging, by keys on their grip or from a menu, and every move announced.
- Task detailEverything about one task: an editable title and description, and each property as a picker button.
- Filter barLive search and multi-select quick filters for tasks, and the Display popover for grouping, ordering and properties.
- Create taskThe New task dialog, with a draft that survives Esc, and the dialog that lists every Tasks shortcut.
- useHotkeysSingle-key and modifier shortcuts, Linear style, that wait while you type and can be scoped to one part of the page.
- App windowThe RChursin_ app frame: a sidebar with the tools, a title row with a toolbar, and your tool in the body.
Source
The component’s own files, exactly as they run on this site.
/** * The Tasks tool, inside the RChursin_ app window: search and filters, a list (grid) and a * board, a detail panel, a create dialog, bulk actions, shortcuts and undo for every change. * Shortcuts are scoped to the window, so other demos on the page keep their keys. */import { useEffect, useLayoutEffect, useMemo, useRef, useState, type FocusEvent, type KeyboardEvent, type RefObject,} from "react"import { ME, statuses, type StatusId } from "../data/sample"import { Icon } from "../icons/Icon"import { useAnnounce } from "../lib/announce"import { isTypingTarget, useHotkeys } from "../lib/hotkeys"import { AppWindow } from "../shell/AppWindow"