"use client"; import { type CSSProperties, type ReactNode } from "react"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { GripVertical, MoreHorizontal, Star } from "lucide-react"; import { cn } from "@/lib/utils"; import { type CandidateRow, type StageKey } from "@/lib/schema"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; /** * Pane 2 のステージグループ用、ドラッグ可能な候補者行。 * * - 行全体クリック = 候補者を選択(onSelect 経由) * - 左端のグリップだけが drag listener を持つ。`MoreHorizontal` メニューや * 行クリックとは衝突しない(`activationConstraint: distance` でも吸収済み) * - DragOverlay 描画中は `isDragging` で半透明 + pointer-events 抑止 * * archived グループの行はドラッグさせないため、本コンポーネントは stage グループ * 専用。archived は CandidateListPane 側の通常 `
  • ` で描画する。 */ export function SortableCandidateRow({ cand, stage, selected, onSelect, actions, }: { cand: CandidateRow; stage: StageKey; selected: boolean; onSelect: (id: string) => void; actions: ReactNode; }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: cand.id, data: { containerId: stage, name: cand.name }, }); const style: CSSProperties = { transform: CSS.Transform.toString(transform), transition, }; return (
  • } /> {actions}
  • ); } function ScoreBadge({ avg, selected, }: { avg: number | null; selected: boolean; }) { if (avg === null) { return ( ); } return ( {avg.toFixed(1)} ); }