"use client";
import {
Column,
gentleSpring,
type ColumnData,
type ColumnStatus,
type DragState,
} from "@/components/ui/kanban-board";
import { useCallback, useState } from "react";
import { MotionConfig } from "motion/react";
const SAMPLE_COLUMNS: ColumnData[] = [
{
id: "todo",
title: "Backlog",
status: "todo",
cards: [
{
id: "1",
title: "Draft Q2 nurture email series",
tags: [{ label: "Campaign", variant: "feature" }],
assignee: {
name: "Méschac Irung",
avatar: "https://cdn.21st.dev/assets/mirror/ac/ac9c53a00de9dbc0d8733c544cb6f33f58bfe72943ec1c90f235716887ade7fa.jpg",
},
date: "Jan 8",
},
{
id: "2",
title: "Fix broken UTMs on paid search ads",
tags: [{ label: "Tracking", variant: "bug" }],
assignee: {
name: "Bernard Ngandu",
avatar: "https://cdn.21st.dev/assets/mirror/51/511e8a28ad384d1692e249771c5da88414ce778aec74ea21451d519db92e0038.jpg",
},
date: "Jan 5",
},
{
id: "6",
title: "Refresh one-pager for enterprise pitch",
tags: [{ label: "Collateral", variant: "docs" }],
assignee: { name: "Anika Patel" },
date: "Jan 9",
},
],
},
{
id: "in-progress",
title: "In flight",
status: "in-progress",
cards: [
{
id: "3",
title: "Homepage hero & social proof block",
tags: [{ label: "Creative", variant: "design" }],
assignee: {
name: "Théo Balick",
avatar: "https://cdn.21st.dev/assets/mirror/6b/6bfe57db510ea4a7faa6b39f90b7ec15658233f079d0bac3ef425859f211b0b2.jpg",
},
date: "Jan 6",
},
{
id: "7",
title: "A/B test LinkedIn lead-gen forms",
tags: [{ label: "Growth", variant: "improvement" }],
assignee: {
name: "Liam Chen",
avatar: "https://cdn.21st.dev/assets/mirror/2b/2b7b08655f93dbb0d950da430b1e251dcfede184e47d81a2c425514cd529b0fe.jpg",
},
date: "Jan 7",
},
],
},
{
id: "done",
title: "Launched",
status: "done",
cards: [
{
id: "4",
title: "Spring launch landing page live",
tags: [{ label: "Launch", variant: "done" }],
assignee: {
name: "Méschac Irung",
avatar: "https://cdn.21st.dev/assets/mirror/ac/ac9c53a00de9dbc0d8733c544cb6f33f58bfe72943ec1c90f235716887ade7fa.jpg",
},
date: "Jan 3",
},
],
},
];
function KanbanBoardDemo() {
const [columns, setColumns] = useState<ColumnData[]>(SAMPLE_COLUMNS);
const [dragState, setDragState] = useState<DragState>(null);
const handleDrop = useCallback(
(cardId: string, fromColumnId: ColumnStatus, toColumnId: ColumnStatus) => {
if (fromColumnId === toColumnId) {
return;
}
setColumns((prev) => {
const fromCol = prev.find((c) => c.id === fromColumnId);
const card = fromCol?.cards.find((c) => c.id === cardId);
if (!card) {
return prev;
}
return prev.map((col) => {
if (col.id === fromColumnId) {
return {
...col,
cards: col.cards.filter((c) => c.id !== cardId),
};
}
if (col.id === toColumnId) {
return { ...col, cards: [...col.cards, card] };
}
return col;
});
});
},
[],
);
return (
<MotionConfig transition={gentleSpring}>
<div
className="flex min-h-[500px] w-full max-w-4xl items-start justify-center bg-[#f0f0f0]/20 px-6 py-12 antialiased dark:bg-transparent"
style={{
fontFamily:
'-apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, sans-serif',
WebkitFontSmoothing: "antialiased",
}}
>
<div className="w-full max-w-[520px]">
<div className="grid grid-cols-3 gap-5">
{columns.map((col) => (
<Column
column={col}
dragState={dragState}
key={col.id}
onDrop={handleDrop}
setDragState={setDragState}
/>
))}
</div>
</div>
</div>
</MotionConfig>
);
}
export default KanbanBoardDemo;