import { useState } from "react"; import { Plus, ChevronRight } from "lucide-react"; import { motion, useReducedMotion } from "framer-motion"; import { fadeSlideUp, springs, staggerContainer } from "@/lib/motion"; import { useDroppable } from "@dnd-kit/core"; import { SortableContext, verticalListSortingStrategy, useSortable, } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; import { Button } from "@/components/ui/button"; import { ColumnHeader } from "@/components/board/ColumnHeader"; import { AddCardInput } from "@/components/board/AddCardInput"; import { CardThumbnail } from "@/components/board/CardThumbnail"; import { useBoardStore } from "@/stores/board-store"; import type { Column } from "@/types/board"; const WIDTH_MAP = { narrow: 180, standard: 280, wide: 360, } as const; interface KanbanColumnProps { column: Column; filteredCardIds?: string[]; focusedCardId?: string | null; onCardClick?: (cardId: string) => void; isNew?: boolean; } export function KanbanColumn({ column, filteredCardIds, focusedCardId, onCardClick, isNew }: KanbanColumnProps) { const [showAddCard, setShowAddCard] = useState(false); const board = useBoardStore((s) => s.board); const toggleColumnCollapse = useBoardStore((s) => s.toggleColumnCollapse); const prefersReducedMotion = useReducedMotion(); const width = WIDTH_MAP[column.width]; // Make the column itself sortable (for column reordering) const { attributes, listeners, setNodeRef: setSortableNodeRef, transform, transition, isDragging, } = useSortable({ id: column.id, data: { type: "column" }, }); // Make the column a droppable target so empty columns can receive cards const { setNodeRef: setDroppableNodeRef } = useDroppable({ id: `column-droppable-${column.id}`, data: { type: "column", columnId: column.id }, }); const borderTop = column.color ? `3px solid oklch(55% 0.12 ${column.color})` : board?.color ? `3px solid ${board.color}30` : undefined; const displayCardIds = filteredCardIds ?? column.cardIds; const isFiltering = filteredCardIds != null; const cardCount = column.cardIds.length; const wipTint = column.wipLimit != null ? cardCount > column.wipLimit ? "oklch(70% 0.08 25 / 15%)" : cardCount === column.wipLimit ? "oklch(75% 0.08 70 / 15%)" : undefined : undefined; return ( {column.collapsed ? ( ) : ( {/* The column header is the drag handle for column reordering */}
{/* Card list - wrapped in SortableContext for within-column sorting */} {displayCardIds.map((cardId) => { const card = board?.cards[cardId]; if (!card) return null; return (
  • ); })} {displayCardIds.length === 0 && (
  • {isFiltering ? "No matching cards" : "Drop or add a card"}
  • )}
    {/* Add card section */} {showAddCard ? ( setShowAddCard(false)} /> ) : (
    )}
    )}
    ); }