feat: safe deletion, album/asset delete, trash, README update
- volume-aware deletion: read-only volumes remove DB only, writable volumes soft-delete to trash with configurable grace period - trash page with restore, worker purge sweep (TRASH_RETENTION_DAYS) - album delete endpoint + sidebar trash icon - asset delete from timeline selection toolbar - all listing queries exclude trashed assets (deleted_at IS NULL) - timeline ordered by EXIF capture date, date-summary endpoint - README rewritten with features, setup, full env var table
This commit is contained in:
@@ -8,7 +8,7 @@ import { ImageViewer } from "./image-viewer"
|
||||
import { AddToAlbumDialog } from "./add-to-album-dialog"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Spinner } from "@/components/ui/spinner"
|
||||
import { ImagePlusIcon, XIcon, CheckSquareIcon } from "lucide-react"
|
||||
import { ImagePlusIcon, XIcon, CheckSquareIcon, Trash2Icon } from "lucide-react"
|
||||
|
||||
interface PhotoGridProps {
|
||||
groups: DateGroup[]
|
||||
@@ -16,6 +16,7 @@ interface PhotoGridProps {
|
||||
hasMore: boolean
|
||||
onLoadMore: () => void
|
||||
onRemoveAsset?: (assetId: string) => void
|
||||
onDeleteAssets?: (assetIds: string[]) => void
|
||||
}
|
||||
|
||||
export function PhotoGrid({
|
||||
@@ -24,6 +25,7 @@ export function PhotoGrid({
|
||||
hasMore,
|
||||
onLoadMore,
|
||||
onRemoveAsset,
|
||||
onDeleteAssets,
|
||||
}: PhotoGridProps) {
|
||||
const sentinelRef = useRef<HTMLDivElement>(null)
|
||||
const [selectedIndex, setSelectedIndex] = useState<number | null>(null)
|
||||
@@ -94,13 +96,26 @@ export function PhotoGrid({
|
||||
{onRemoveAsset && selectedIds.size > 0 && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
selectedIds.forEach((id) => onRemoveAsset(id))
|
||||
exitSelection()
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
Remove from Album
|
||||
</Button>
|
||||
)}
|
||||
{onDeleteAssets && selectedIds.size > 0 && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
onDeleteAssets(Array.from(selectedIds))
|
||||
exitSelection()
|
||||
}}
|
||||
>
|
||||
<Trash2Icon className="mr-1.5 h-3.5 w-3.5" />
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
<Button size="sm" variant="ghost" onClick={exitSelection}>
|
||||
|
||||
Reference in New Issue
Block a user