diff --git a/packages/board/src/App.tsx b/packages/board/src/App.tsx index 3e2fa41..12e6bd9 100644 --- a/packages/board/src/App.tsx +++ b/packages/board/src/App.tsx @@ -151,7 +151,7 @@ function App() { /> {error && ( -
+
{error}
)} @@ -171,7 +171,7 @@ function App() { )} {connected && ( -
+
+
-
-
- +
+
+
-
-

OGraph Task Board

-

+

+

OGraph Tasks

+

{connected ? `${taskCount} task${taskCount !== 1 ? "s" : ""}` - : "Not connected — configure in Settings"} + : "Not connected"}

-
+
-
diff --git a/packages/board/src/components/KanbanBoard.tsx b/packages/board/src/components/KanbanBoard.tsx index dc75548..8559b09 100644 --- a/packages/board/src/components/KanbanBoard.tsx +++ b/packages/board/src/components/KanbanBoard.tsx @@ -1,4 +1,5 @@ -import { ALL_STATUSES, type Task, type TaskStatus } from "@/types" +import { useState } from "react" +import { ALL_STATUSES, STATUS_CONFIG, type Task, type TaskStatus } from "@/types" import { KanbanColumn } from "@/components/KanbanColumn" interface KanbanBoardProps { @@ -8,30 +9,85 @@ interface KanbanBoardProps { onMoveTask: (taskId: number, status: TaskStatus) => void } -export function KanbanBoard({ tasks, onTaskClick, onAddTask, onMoveTask }: KanbanBoardProps) { - return ( -
- {ALL_STATUSES.map((status) => { - const columnTasks = tasks - .filter((t) => t.status === status) - .sort((a, b) => { - // Sort by priority first (p0 first), then by updatedAt descending - const prioOrder = a.priority.localeCompare(b.priority) - if (prioOrder !== 0) return prioOrder - return b.updatedAt - a.updatedAt - }) +const tabColors: Record = { + zinc: "border-zinc-500 text-zinc-300", + blue: "border-blue-500 text-blue-400", + amber: "border-amber-500 text-amber-400", + purple: "border-purple-500 text-purple-400", + emerald: "border-emerald-500 text-emerald-400", +} - return ( +export function KanbanBoard({ tasks, onTaskClick, onAddTask, onMoveTask }: KanbanBoardProps) { + const [mobileTab, setMobileTab] = useState("todo") + + const getColumnTasks = (status: TaskStatus) => + tasks + .filter((t) => t.status === status) + .sort((a, b) => { + const prioOrder = a.priority.localeCompare(b.priority) + if (prioOrder !== 0) return prioOrder + return b.updatedAt - a.updatedAt + }) + + return ( + <> + {/* Mobile: tab switcher */} +
+
+ {ALL_STATUSES.map((status) => { + const config = STATUS_CONFIG[status] + const count = tasks.filter((t) => t.status === status).length + const isActive = mobileTab === status + return ( + + ) + })} +
+
+ + {/* Mobile: single column view */} +
+ +
+ + {/* Desktop: horizontal kanban */} +
+ {ALL_STATUSES.map((status) => ( - ) - })} -
+ ))} +
+ ) } diff --git a/packages/board/src/components/KanbanColumn.tsx b/packages/board/src/components/KanbanColumn.tsx index dd8abb7..0104fd8 100644 --- a/packages/board/src/components/KanbanColumn.tsx +++ b/packages/board/src/components/KanbanColumn.tsx @@ -9,6 +9,7 @@ interface KanbanColumnProps { onTaskClick: (task: Task) => void onAddTask: (status: TaskStatus) => void onDrop: (taskId: number, status: TaskStatus) => void + mobile?: boolean } const borderColors: Record = { @@ -27,7 +28,7 @@ const countBgColors: Record = { emerald: "bg-emerald-500/15 text-emerald-400", } -export function KanbanColumn({ status, tasks, onTaskClick, onAddTask, onDrop }: KanbanColumnProps) { +export function KanbanColumn({ status, tasks, onTaskClick, onAddTask, onDrop, mobile }: KanbanColumnProps) { const config = STATUS_CONFIG[status] function handleDragOver(e: React.DragEvent) { @@ -43,6 +44,48 @@ export function KanbanColumn({ status, tasks, onTaskClick, onAddTask, onDrop }: } } + if (mobile) { + // Mobile: full-width, no column header (tabs handle that), no fixed width + return ( +
+
+ {tasks.map((task) => ( +
{ + e.dataTransfer.setData("text/plain", String(task.id)) + e.dataTransfer.effectAllowed = "move" + }} + > + +
+ ))} + + {tasks.length === 0 && ( +
+ No tasks +
+ )} +
+ + +
+ ) + } + + // Desktop: fixed-width column return (