dnd-use-sortable

ui

src

cn.ts

ts
// npm i clsx tailwind-merge

import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
    return twMerge(clsx(inputs));
}

sortable.tsx

tsx
// npm i @dnd-kit/react

"use client"

import { ReactElement } from "react";
import { useSortable } from "@dnd-kit/react/sortable";
import { cn } from "@/lib/tailwind";

interface SortableProps {
    id: number;
    index: number;
    className?: string;
    children: ReactElement;
}

export function Sortable({ id, index, className, children }: SortableProps) {

    const { ref, isDragging } = useSortable({ id, index });

    return (
        <li ref={ ref } className={ cn(className, isDragging && "z-50 shadow-2xl blur-xs duration-300") }>
            { children }
        </li>
    )
}

page.tsx

tsx
import { Sortable } from "@/examples/dnd-use-sortable/Sortable";

export default function Page() {

    const images = [
        {
            id: 1,
            url: "https://cdn.pixabay.com/photo/2023/10/25/19/25/blue-8341156_1280.jpg"
        },
        {
            id: 2,
            url: "https://cdn.pixabay.com/photo/2020/02/05/22/37/seagulls-4822595_1280.jpg"
        },
        {
            id: 3,
            url: "https://cdn.pixabay.com/photo/2017/08/07/08/23/sea-2601374_1280.jpg"
        },
        {
            id: 4,
            url: "https://cdn.pixabay.com/photo/2022/09/07/18/25/stone-7439317_1280.jpg"
        },
        {
            id: 5,
            url: "https://cdn.pixabay.com/photo/2019/06/01/09/58/water-4243762_1280.jpg"
        },
        {
            id: 6,
            url: "https://cdn.pixabay.com/photo/2020/02/11/10/24/lake-4839058_1280.jpg"
        }
    ];

    return (
        <ul className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
            {
                images.map(({ url, id }, i) => (
                    <Sortable id={ id } index={ i } key={ id }>
                        <img className="w-full aspect-video cursor-pointer" src={ url } alt=""/>
                    </Sortable>
                ))
            }
        </ul>
    )

}

video