Add side panels, task selection, graph animation, and project docs

- Foldable left panel (user profile) and right panel (task details)
- Clicking a task in the list or graph node selects it and shows details
- Both views (task list + graph) always mounted via absolute inset-0 for
  correct canvas dimensions; tabs toggle visibility with opacity
- Graph node selection animation: other nodes repel outward (charge -600),
  then selected node smoothly slides to center (500ms cubic ease-out),
  then charge restores to -120 and graph stabilizes
- Graph re-fits on tab switch and panel resize via ResizeObserver
- Fix UUID string IDs throughout (backend returns UUIDs, not integers)
- Add TaskDetailPanel, UserPanel components
- Add CLAUDE.md project documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alvis
2026-04-08 11:23:06 +00:00
parent 5c7edd4bbc
commit f1d51b8cc8
23998 changed files with 3242708 additions and 0 deletions

86
CLAUDE.md Normal file
View File

@@ -0,0 +1,86 @@
# Taskpile
A task manager with force-directed graph visualization.
## Architecture
- **Frontend**: Next.js 14 (App Router) + React 18 + Tailwind CSS 3 + TypeScript
- **Backend**: Rust (Axum 0.7) + SQLite (via SQLx)
- **Graph**: `react-force-graph-2d` for force-directed visualization
## Project Structure
```
frontend/
src/app/page.tsx — Main page: tabs, panels, task state management
src/app/layout.tsx — Root layout
src/components/
GraphView.tsx — Force graph with node selection, drag-to-center
TaskList.tsx — Pending/completed task list with selection
TaskItem.tsx — Individual task card
AddTaskForm.tsx — New task form
TaskDetailPanel.tsx — Right panel: selected task details
UserPanel.tsx — Left panel: user profile (example data)
ForceGraphClient.tsx — ForceGraph2D ref wrapper for dynamic import
src/lib/
api.ts — API client (fetch wrappers)
types.ts — TypeScript interfaces
src/__tests__/
unit/ — Jest unit tests (API, TaskItem)
e2e/ — Jest integration tests (full user flows)
backend/
src/main.rs — Axum server on port 3001
src/models.rs — Task, GraphNode, GraphEdge structs
src/db.rs — SQLite pool + migrations
src/graph.rs — Deterministic edge generation (~30% pairs)
src/routes/tasks.rs — CRUD: GET/POST /api/tasks, PATCH/DELETE /api/tasks/:id
src/routes/graph.rs — GET /api/graph
tests/integration_test.rs — Axum integration tests
```
## Running
```bash
# Backend (port 3001)
cd backend && cargo run
# Frontend (port 3003, proxies /api to backend)
cd frontend && npm run dev -- -p 3003
```
Port 3000 is used by Gitea on this machine — use 3003 for the frontend.
## Testing
```bash
# Frontend tests
cd frontend && npx jest
# Backend tests
cd backend && cargo test
```
## Key Design Decisions
- Task IDs are UUIDs (TEXT in SQLite, string from backend). Frontend `Task.id` is typed as `number` but actually receives strings — selection uses string comparison throughout.
- Graph tab and task list are switched via tabs in the center area. Left panel (user info) and right panel (task details) are independently foldable.
- Selecting a task (from list or graph node click) animates the node to the center of the viewport (drag-style, not camera pan). The node stays pinned until a different task is selected.
- `ForceGraph2D` canvas dimensions are driven by a `ResizeObserver` on a container div that always renders. The canvas is only mounted after the first measurement to avoid a 300x300 default.
- Panel transitions are 300ms CSS; graph re-fit/re-center delays 350ms to wait for the transition.
## API
All endpoints under `/api`:
| Method | Path | Description |
|--------|------|-------------|
| GET | /tasks | List all tasks |
| POST | /tasks | Create task `{title, description?}` |
| PATCH | /tasks/:id | Update task `{title?, description?, completed?}` |
| DELETE | /tasks/:id | Delete task |
| GET | /graph | Get nodes + weighted edges |
## Proxy
Do not use system proxy env vars when testing the app locally — `curl --noproxy '*'` or equivalent.