A Next.js app that visualizes your ClickUp workspace as an interactive mind map.
- Copy the example env file and add your ClickUp token:
cp .env.example .env.local-
Set
CLICKUP_TOKENin.env.local(starts withpk_).Get it from: ClickUp → Avatar → Settings → Apps → API Token
-
Install dependencies and run:
npm install
npm run devOpen http://localhost:3000.
- Hierarchy view — Workspace → Space → Folder → List → Task → Subtask
- Lazy loading — Children load on expand; large lists prompt before fetching
- Task details — Status, priority, due date, assignees on each node
- Inline editing — Rename tasks, update status and priority (syncs to ClickUp)
- Navigation — Zoom, pan, fit-to-view, center selected node
- Keyboard shortcuts —
+/-zoom,0fit,fcenter,Enterexpand,Escdeselect - Dark mode — Toggle in toolbar (persists in localStorage)
src/
├── app/ # Next.js routes + API handlers
├── components/
│ ├── mindmap/ # Canvas, toolbar, detail panel, nodes
│ └── ui/ # Small UI primitives
├── lib/
│ ├── clickup/ # ClickUp API client + transforms
│ └── mindmap/ # Graph building + dagre layout
├── types/ # Shared TypeScript types
└── hooks/ # Keyboard shortcuts
Data flow: Client canvas → /api/clickup/* route handlers → ClickUp API v2. The API token never leaves the server.
State: All UI state lives in MindMapCanvas — expanded nodes, selection, and a client-side cache. No external state library.
| Package | Purpose |
|---|---|
@xyflow/react |
Pan, zoom, custom nodes, graph rendering |
dagre |
Hierarchical tree layout |
Everything else uses Next.js, React, and Tailwind CSS.
The app is publicly readable. Anyone with the URL can view the mind map and related pages.
Editing (create / update / delete tasks) requires unlocking with ADMIN_PIN via the lock icon in the toolbar. Write APIs reject requests without a valid admin session cookie.
| Variable | Required | Description |
|---|---|---|
CLICKUP_TOKEN |
Yes | Personal API token from ClickUp settings |
ADMIN_PIN |
Yes (for editing) | Server-only PIN to unlock task create/update/delete. Editing is disabled if unset. |