"use client"; import { GripVertical, PencilLine, PlusIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import type { ComponentProps } from "react"; import { useState, useTransition } from "react"; import { toast } from "sonner"; import { SimpleTooltip } from "@/components/tooltip"; import { Button } from "@/components/ui/button"; import { Kbd, KbdGroup } from "@/components/ui/kbd"; import type { tierlistColumns, tierlistTiers } from "@/lib/db/schema"; import { cn } from "@/lib/utils"; import { reorderFlatItems } from "../components/order"; import { SortableGrid, SortableGridItem } from "../components/sortable-grid"; import { reorderColumns, reorderTiers } from "./actions"; type Tier = typeof tierlistTiers.$inferSelect; type Column = typeof tierlistColumns.$inferSelect; export function LayoutEditor({ tiers: initialTiers, columns: initialColumns, }: { tiers: Tier[]; columns: Column[]; }) { const [tiers, setTiers] = useState(initialTiers); const [columns, setColumns] = useState(initialColumns); const [pending, startTransition] = useTransition(); function commitReorder( items: T[], setItems: (items: T[]) => void, activeId: string, overId: string, persist: (args: { activeId: string; ids: string[] }) => Promise, label: string, ) { const next = reorderFlatItems(items, activeId, overId); if (next === items) return; const previous = items; setItems(next); startTransition(() => { persist({ activeId, ids: next.map((item) => item.id) }).catch((error) => { console.error(error); setItems(previous); toast.error( error instanceof Error ? error.message : `Failed to reorder ${label}.`, ); }); }); } return (
column.id)} onReorder={(activeId, overId) => commitReorder( columns, setColumns, activeId, overId, reorderColumns, "columns", ) } disabled={pending} overlay={(id) => { const column = columns.find((entry) => entry.id === id); return column ? ( ) : null; }} > {columns.length ? ( columns.map((column) => ( {({ attributes, listeners, setNodeRef, style, isDragging, }) => (
)}
)) ) : (
Add your first column
)}
{tiers.length ? ( tier.id)} onReorder={(activeId, overId) => commitReorder( tiers, setTiers, activeId, overId, reorderTiers, "tiers", ) } disabled={pending} overlay={(id) => { const tier = tiers.find((entry) => entry.id === id); return tier ? ( ) : null; }} > {tiers.map((tier) => ( column.id) : ["empty"] } pending={pending} /> ))} ) : ( <>
Add your first tier
{(columns.length ? columns.map((column) => column.id) : ["empty"] ).map((id) => ( ))} )} {(columns.length ? columns.map((column) => column.id) : ["empty"] ).map((id) => ( ))}
); } function TierRow({ tier, columnIds, pending, }: { tier: Tier; columnIds: string[]; pending: boolean; }) { return ( <> {({ attributes, listeners, setNodeRef, style, isDragging }) => (
)}
{columnIds.map((columnId) => ( ))} ); } function BlankCell() { return
; } function ThinCell() { return
; } function AddSlot({ href, label }: { href: string; label: string }) { return ( ); } function LayoutNode({ item, href, dragHandle, orientation, badges, overlay = false, }: { item: { id: string; name: string; image: string | null }; href?: string; dragHandle?: ComponentProps<"button">; orientation: "tier" | "column"; badges?: string[] | null; overlay?: boolean; }) { return (
{href && !overlay && (
)}
{item.image ? ( {item.name} ) : ( {item.name[0] ?? "?"} )}
{item.name}
{item.id}
{orientation === "tier" && (
{badges?.length ? ( {badges.map((badge) => ( {badge} ))} ) : ( No badges )}
)}
); }