Files
memer/frontend/src/components/CollectionBar.tsx
2026-03-28 01:34:27 -05:00

102 lines
4.1 KiB
TypeScript

import { useState } from 'react';
import { FolderOpen, Inbox, FolderPlus, Pencil, Trash2 } from 'lucide-react';
import { useDeleteCollection } from '../hooks/useMemes';
import { CollectionModal } from './CollectionModal';
import type { Collection } from '../api/client';
interface Props {
collections: Collection[];
activeId: number | null;
onSelect: (id: number) => void;
isAdmin: boolean;
}
export function CollectionBar({ collections, activeId, onSelect, isAdmin }: Props) {
const [showCreate, setShowCreate] = useState(false);
const [renaming, setRenaming] = useState<Collection | null>(null);
const deleteCollection = useDeleteCollection();
async function handleDelete(col: Collection) {
if (!confirm(`Delete folder "${col.name}"? Its memes will be moved to Unsorted.`)) return;
// If the deleted folder is active, switch to Unsorted first
if (activeId === col.id) {
const unsorted = collections.find((c) => c.is_default);
if (unsorted) onSelect(unsorted.id);
}
await deleteCollection.mutateAsync(col.id);
}
return (
<>
<div className="flex gap-2 overflow-x-auto pb-0.5 scrollbar-none items-stretch">
{collections.map((col) => {
const isActive = activeId === col.id;
const isDefault = col.is_default === 1;
return (
<div key={col.id} className="relative group flex-shrink-0">
<button
onClick={() => onSelect(col.id)}
className={`flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium transition-all border ${
isActive
? 'bg-accent/15 border-accent/50 text-purple-200'
: 'bg-zinc-900 border-zinc-800 text-zinc-400 hover:border-zinc-600 hover:text-zinc-200 hover:bg-zinc-800/80'
}`}
>
{isDefault ? (
<Inbox size={15} className={isActive ? 'text-accent' : 'text-zinc-500'} />
) : (
<FolderOpen size={15} className={isActive ? 'text-accent' : 'text-zinc-500'} />
)}
<span className="whitespace-nowrap">{col.name}</span>
<span className={`text-xs ${isActive ? 'text-purple-400' : 'text-zinc-600'}`}>
{col.meme_count}
</span>
</button>
{/* Admin controls — appear on hover for non-default collections */}
{isAdmin && !isDefault && (
<div className="absolute -top-2 -right-1 hidden group-hover:flex gap-0.5 z-10">
<button
onClick={(e) => { e.stopPropagation(); setRenaming(col); }}
className="p-1 rounded bg-zinc-800 border border-zinc-700 text-zinc-400 hover:text-zinc-200 hover:bg-zinc-700 transition-colors"
title="Rename folder"
>
<Pencil size={11} />
</button>
<button
onClick={(e) => { e.stopPropagation(); handleDelete(col); }}
className="p-1 rounded bg-zinc-800 border border-zinc-700 text-zinc-400 hover:text-red-400 hover:bg-zinc-700 transition-colors"
title="Delete folder"
>
<Trash2 size={11} />
</button>
</div>
)}
</div>
);
})}
{/* New folder button (admin only) */}
{isAdmin && (
<button
onClick={() => setShowCreate(true)}
className="flex-shrink-0 flex items-center gap-1.5 px-3 py-2.5 rounded-xl text-sm text-zinc-600 border border-dashed border-zinc-700 hover:border-zinc-500 hover:text-zinc-400 transition-colors"
title="New folder"
>
<FolderPlus size={15} />
<span className="whitespace-nowrap hidden sm:inline">New folder</span>
</button>
)}
</div>
{showCreate && (
<CollectionModal mode="create" onClose={() => setShowCreate(false)} />
)}
{renaming && (
<CollectionModal mode="rename" collection={renaming} onClose={() => setRenaming(null)} />
)}
</>
);
}