161 lines
4.8 KiB
TypeScript
161 lines
4.8 KiB
TypeScript
import { Badge } from '@/components/ui/badge'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Kanban, KanbanBoard, KanbanColumn, KanbanColumnHandle, KanbanItem, KanbanOverlay } from '@/components/ui/kanban'
|
|
import { createFileRoute } from '@tanstack/react-router'
|
|
import { GripVertical } from 'lucide-react'
|
|
|
|
import { useState } from 'react'
|
|
|
|
export const Route = createFileRoute('/_sidebar/kanban')({
|
|
component: RouteComponent,
|
|
beforeLoad: () => {
|
|
return {
|
|
breadcrumb: 'Kanban',
|
|
}
|
|
},
|
|
})
|
|
|
|
const kanbanboard = {
|
|
columns: [
|
|
{
|
|
id: 0,
|
|
name: 'Backlog'
|
|
},
|
|
{
|
|
id: 1,
|
|
name: 'Todo'
|
|
},
|
|
{
|
|
id: 2,
|
|
name: 'Doing'
|
|
},
|
|
{
|
|
id: 3,
|
|
name: 'Done'
|
|
},
|
|
{
|
|
id: 4,
|
|
name: 'Backlog'
|
|
},
|
|
{
|
|
id: 5,
|
|
name: 'Todo'
|
|
},
|
|
{
|
|
id: 6,
|
|
name: 'Doing'
|
|
},
|
|
{
|
|
id: 7,
|
|
name: 'Done'
|
|
},
|
|
],
|
|
}
|
|
|
|
interface Task {
|
|
id: string;
|
|
title: string;
|
|
priority: "low" | "medium" | "high";
|
|
assignee?: string;
|
|
dueDate?: string;
|
|
}
|
|
|
|
const COLUMN_TITLES: Record<string, string> = {
|
|
backlog: "Backlog",
|
|
inProgress: "In Progress",
|
|
done: "Done",
|
|
};
|
|
|
|
function RouteComponent() {
|
|
// const [columns, setColumns] = useState(kanbanboard.columns)
|
|
|
|
const [columns, setColumns] = useState<string[]>([
|
|
"backlog",
|
|
"inProgress",
|
|
"done",
|
|
"sprintbacl",
|
|
"toStart",
|
|
"notDone",
|
|
]);
|
|
|
|
return (
|
|
<div className="h-full w-full">
|
|
<Kanban value={columns} onValueChange={setColumns} getItemValue={(c) => c.id}>
|
|
<KanbanBoard className="flex min-w-full overflow-scroll">
|
|
{Object.entries(columns).map(([columnValue]) => (
|
|
<KanbanColumn key={columnValue} value={columnValue} className='min-w-md'>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<span className="font-semibold text-sm">
|
|
{COLUMN_TITLES[columnValue]}
|
|
</span>
|
|
<Badge
|
|
variant="secondary"
|
|
className="pointer-events-none rounded-sm"
|
|
>
|
|
0
|
|
</Badge>
|
|
</div>
|
|
<KanbanColumnHandle asChild>
|
|
<Button variant="ghost" size="icon">
|
|
<GripVertical className="h-4 w-4" />
|
|
</Button>
|
|
</KanbanColumnHandle>
|
|
</div>
|
|
<div className="flex flex-col gap-2 p-0.5">
|
|
{/* List Tasks using Tanstack Query
|
|
|
|
{tasks.map((task) => (
|
|
<KanbanItem key={task.id} value={task.id} asHandle asChild>
|
|
<div className="rounded-md border bg-card p-3 shadow-xs">
|
|
<div className="flex flex-col gap-2">
|
|
<div className="flex items-center justify-between gap-2">
|
|
<span className="line-clamp-1 font-medium text-sm">
|
|
{task.title}
|
|
</span>
|
|
<Badge
|
|
variant={
|
|
task.priority === "high"
|
|
? "destructive"
|
|
: task.priority === "medium"
|
|
? "default"
|
|
: "secondary"
|
|
}
|
|
className="pointer-events-none h-5 rounded-sm px-1.5 text-[11px] capitalize"
|
|
>
|
|
{task.priority}
|
|
</Badge>
|
|
</div>
|
|
<div className="flex items-center justify-between text-muted-foreground text-xs">
|
|
{task.assignee && (
|
|
<div className="flex items-center gap-1">
|
|
<div className="size-2 rounded-full bg-primary/20" />
|
|
<span className="line-clamp-1">
|
|
{task.assignee}
|
|
</span>
|
|
</div>
|
|
)}
|
|
{task.dueDate && (
|
|
<time className="text-[10px] tabular-nums">
|
|
{task.dueDate}
|
|
</time>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</KanbanItem>
|
|
))}
|
|
|
|
*/}
|
|
</div>
|
|
</KanbanColumn>
|
|
))}
|
|
</KanbanBoard>
|
|
<KanbanOverlay>
|
|
<div className="size-full rounded-md bg-primary/10" />
|
|
</KanbanOverlay>
|
|
</Kanban>
|
|
</div>
|
|
)
|
|
}
|