import { useEffect, useRef, useState } from "react"; import { useGalleryStore } from "../store"; import { AlbumPicker } from "./AlbumPicker"; import { BulkTagPopover } from "./bulk/BulkTagPopover"; import { useDismissable } from "./menu"; import { Tooltip } from "./Tooltip" import { CloseIcon, StarIcon, WarningIcon } from "./icons"; type Panel = "tag" | "rating" | "album" | "delete" | null; export function BulkActionBar() { const selectedCount = useGalleryStore((state) => state.gallerySelectedIds.size); const selectedIds = useGalleryStore((state) => state.gallerySelectedIds); const clearGallerySelection = useGalleryStore((state) => state.clearGallerySelection); const selectAllGallery = useGalleryStore((state) => state.selectAllGallery); const loadedCount = useGalleryStore((state) => state.loadedCount); const totalImages = useGalleryStore((state) => state.totalImages); const bulkSetFavorite = useGalleryStore((state) => state.bulkSetFavorite); const bulkSetRating = useGalleryStore((state) => state.bulkSetRating); const bulkDeleteSelected = useGalleryStore((state) => state.bulkDeleteSelected); const activeView = useGalleryStore((state) => state.activeView); const selectedAlbumId = useGalleryStore((state) => state.selectedAlbumId); const addToAlbum = useGalleryStore((state) => state.addToAlbum); const removeFromAlbum = useGalleryStore((state) => state.removeFromAlbum); const [panel, setPanel] = useState(null); const [deleting, setDeleting] = useState(false); const barRef = useRef(null); // Close any open popover when clicking outside the bar or pressing Escape. useDismissable(barRef, () => setPanel(null), panel !== null); // Reset transient UI whenever the selection empties. useEffect(() => { if (selectedCount === 0) setPanel(null); }, [selectedCount]); if (selectedCount === 0) return null; const ids = Array.from(selectedIds); const inAlbumView = activeView === "album" && selectedAlbumId !== null; const togglePanel = (next: Exclude) => setPanel((current) => (current === next ? null : next)); const handleDelete = async () => { setDeleting(true); try { await bulkDeleteSelected(); } finally { setDeleting(false); setPanel(null); } }; const handlePickAlbum = async (albumId: number) => { await addToAlbum(albumId, ids); setPanel(null); }; const btn = "rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors"; const btnIdle = `${btn} text-gray-300 hover:bg-white/10 hover:text-white`; const btnActive = `${btn} bg-white/10 text-white`; return (
event.stopPropagation()} >
{selectedCount} selected {loadedCount < totalImages || loadedCount > selectedCount ? ( ) : null}
{panel === "tag" ? setPanel(null)} /> : null}
{panel === "rating" ? (
{Array.from({ length: 5 }, (_, index) => { const rating = index + 1; return ( ); })}
) : null}
{panel === "album" ? (
) : null}
{inAlbumView ? ( ) : null}
{panel === "delete" ? (

Delete from disk

Permanently delete {selectedCount} file{selectedCount === 1 ? "" : "s"} from your computer. This removes the actual file{selectedCount === 1 ? "" : "s"} from disk and cannot be undone.

) : null}
); }