Walrus blob · testnet
On-chain registration not yet visible.
The aggregator served this blob, but we couldn't locate a matching BlobRegistered event in our scan window. It may not be certified yet, or live further back than we paged.
Lifecycle data is unavailable until the blob registration is visible on-chain.
'use client';
import { useDroppable } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import clsx from 'clsx';
import type { Task, TaskState } from '@/lib/types';
import { STATE_LABELS, STATE_DOT } from '@/lib/types';
import TaskCard from './TaskCard';
interface Props {
state: TaskState;
tasks: Task[];
onTaskClick: (task: Task) => void;
onAddClick: () => void;
}
const COLUMN_ACCENT: Record<TaskState, string> = {
created: 'border-t-slate-400',
'on-going': 'border-t-lv-500',
blocked: 'border-t-amber-500',
complete: 'border-t-emerald-500',
};
const COLUMN_BG: Record<TaskState, string> = {
created: 'bg-slate-50',
'on-going': 'bg-lv-50/60',
blocked: 'bg-amber-50/60',
complete: 'bg-emerald-50/40',
};
export default function KanbanColumn({ state, tasks, onTaskClick, onAddClick }: Props) {
const { setNodeRef, isOver } = useDroppable({ id: state });
return (
<div
ref={setNodeRef}
className={clsx(
'flex flex-col rounded-xl border border-slate-200 border-t-2 min-h-[200px] transition-all',
COLUMN_ACCENT[state],
COLUMN_BG[state],
isOver && 'ring-2 ring-lv-400/60 ring-offset-1 ring-offset-slate-100',
)}
>
{/* Column header */}
<div className="flex items-center justify-between px-4 py-3 border-b border-slate-200/80">
<div className="flex items-center gap-2">
<span className={clsx('w-2 h-2 rounded-full', STATE_DOT[state])}/>
<h3 className="text-sm font-semibold text-slate-700">{STATE_LABELS[state]}</h3>
<span className="text-xs text-slate-400 bg-white border border-slate-200 px-1.5 py-0.5 rounded-full">
{tasks.length}
</span>
</div>
<button
onClick={onAddClick}
className="w-6 h-6 rounded-md flex items-center justify-center text-slate-400
hover:text-lv-600 hover:bg-white transition-colors"
title={`Add ${STATE_LABELS[state]} task`}
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4"/>
</svg>
</button>
</div>
{/* Cards */}
<div className="flex-1 p-3 flex flex-col gap-2.5 overflow-y-auto">
<SortableContext items={tasks.map(t => t.id)} strategy={verticalListSortingStrategy}>
{tasks.map(task => (
<TaskCard key={task.id} task={task} onClick={onTaskClick}/>
))}
</SortableContext>
{tasks.length === 0 && (
<div className="flex-1 flex flex-col items-center justify-center py-8 text-center">
<div className="w-8 h-8 rounded-lg bg-white border border-slate-200 flex items-center justify-center mb-2 shadow-sm">
<svg className="w-4 h-4 text-slate-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
</svg>
</div>
<p className="text-xs text-slate-400">No tasks</p>
</div>
)}
</div>
</div>
);
}