import { motion } from 'framer-motion' import { Eye, EyeOff, Heart, X, Disc3 } from '../../lib/icons' import { getBestImage } from '../../api/jellyfin' import type { BaseItemDto } from '../../api/types' /** * Floating ghost that follows the pointer while a drag is in progress. * Shows the moving item count and a label so multi-row drags read clearly. */ export function DragGhost({ count, pointerY, label }: { count: number; pointerY: number; label: string }) { return (

{count > 1 ? `Moving ${count} items` : label || 'Moving item'}

) } interface SelectionToolbarProps { count: number onClear: () => void onRemove: () => void onMarkPlayed: () => void onMarkUnplayed: () => void onToggleFavorite: () => void } /** * Bottom-floating toolbar that appears whenever the user has rows * selected. Bundles the bulk actions (mark watched / unwatched, favorite, * remove) plus a Done button to clear the selection. */ export function SelectionToolbar({ count, onClear, onRemove, onMarkPlayed, onMarkUnplayed, onToggleFavorite, }: SelectionToolbarProps) { return ( {count} selected } label="Mark watched" /> } label="Mark unwatched" /> } label="Favorite" /> } label="Remove" tone="danger" /> ) } function ToolbarButton({ onClick, icon, label, tone, }: { onClick: () => void icon: React.ReactNode label: string tone?: 'danger' }) { return ( ) } /** * 2x2 poster mosaic fallback for playlists that don't have a primary * image. Shows the first 4 item posters in a grid - if fewer than 4 are * available, blanks fill the gaps. Empty state shows a music disc icon. */ export function PosterMosaic({ items, serverUrl }: { items: BaseItemDto[]; serverUrl: string }) { const tiles = items .slice(0, 4) .map(it => getBestImage(serverUrl, it, 'primary', 300)) .filter(Boolean) as string[] return (
{tiles.length > 0 ? ( Array.from({ length: 4 }).map((_, i) => (
{tiles[i] ? ( ) : (
)}
)) ) : (
)}
) }