- 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>
42 lines
1.1 KiB
TypeScript
42 lines
1.1 KiB
TypeScript
import type { Task, GraphData, CreateTaskInput, UpdateTaskInput } from './types';
|
|
|
|
const BASE = '/api';
|
|
|
|
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
headers: { 'Content-Type': 'application/json', ...init?.headers },
|
|
...init,
|
|
});
|
|
if (!res.ok) {
|
|
const text = await res.text().catch(() => res.statusText);
|
|
throw new Error(`API error ${res.status}: ${text}`);
|
|
}
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
export async function getTasks(): Promise<Task[]> {
|
|
return request<Task[]>('/tasks');
|
|
}
|
|
|
|
export async function createTask(input: CreateTaskInput): Promise<Task> {
|
|
return request<Task>('/tasks', {
|
|
method: 'POST',
|
|
body: JSON.stringify(input),
|
|
});
|
|
}
|
|
|
|
export async function updateTask(id: number, input: UpdateTaskInput): Promise<Task> {
|
|
return request<Task>(`/tasks/${id}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(input),
|
|
});
|
|
}
|
|
|
|
export async function deleteTask(id: number): Promise<void> {
|
|
await fetch(`${BASE}/tasks/${id}`, { method: 'DELETE' });
|
|
}
|
|
|
|
export async function getGraph(): Promise<GraphData> {
|
|
return request<GraphData>('/graph');
|
|
}
|