'use client'; import * as React from 'react'; import { Pin } from 'lucide-react'; import { motion, LayoutGroup, AnimatePresence, type HTMLMotionProps, type Transition, } from 'motion/react'; import { cn } from '@workspace/ui/lib/utils'; type PinListItem = { id: number; name: string; info: string; icon: React.ElementType; pinned: boolean; }; type PinListProps = { items: PinListItem[]; labels?: { pinned?: string; unpinned?: string; }; transition?: Transition; labelMotionProps?: HTMLMotionProps<'p'>; className?: string; labelClassName?: string; pinnedSectionClassName?: string; unpinnedSectionClassName?: string; zIndexResetDelay?: number; } & HTMLMotionProps<'div'>; function PinList({ items, labels = { pinned: 'Pinned Items', unpinned: 'All Items' }, transition = { stiffness: 320, damping: 20, mass: 0.8, type: 'spring' }, labelMotionProps = { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.22, ease: 'easeInOut' }, }, className, labelClassName, pinnedSectionClassName, unpinnedSectionClassName, zIndexResetDelay = 500, ...props }: PinListProps) { const [listItems, setListItems] = React.useState(items); const [togglingGroup, setTogglingGroup] = React.useState< 'pinned' | 'unpinned' | null >(null); const pinned = listItems.filter((u) => u.pinned); const unpinned = listItems.filter((u) => !u.pinned); const toggleStatus = (id: number) => { const item = listItems.find((u) => u.id === id); if (!item) return; setTogglingGroup(item.pinned ? 'pinned' : 'unpinned'); setListItems((prev) => { const idx = prev.findIndex((u) => u.id === id); if (idx === -1) return prev; const updated = [...prev]; const [item] = updated.splice(idx, 1); if (!item) return prev; const toggled = { ...item, pinned: !item.pinned }; if (toggled.pinned) updated.push(toggled); else updated.unshift(toggled); return updated; }); // Reset group z-index after the animation duration (keep in sync with animation timing) setTimeout(() => setTogglingGroup(null), zIndexResetDelay); }; return (
{pinned.length > 0 && ( {labels.pinned} )} {pinned.length > 0 && (
{pinned.map((item) => ( toggleStatus(item.id)} transition={transition} className="flex items-center justify-between gap-5 rounded-2xl bg-neutral-200 dark:bg-neutral-800 p-2" >
{item.name}
{item.info}
))}
)}
{unpinned.length > 0 && ( {labels.unpinned} )} {unpinned.length > 0 && (
{unpinned.map((item) => ( toggleStatus(item.id)} transition={transition} className="flex items-center justify-between gap-5 rounded-2xl bg-neutral-200 dark:bg-neutral-800 p-2 group" >
{item.name}
{item.info}
))}
)}
); } export { PinList, type PinListProps, type PinListItem };