feat: Albums view, auto albums, EXIF details, download, bulk select

Albums tab with manual album CRUD (create/delete, cover photo grid)
and Smart Albums auto-generated by year, city, and camera model using
SQLite window functions — no extra storage, computed from existing data.

Lightbox gets a download-original button (streams raw file with
Content-Disposition: attachment).

DetailPanel Camera section expands to show ISO, aperture, shutter speed,
focal length, and lens model extracted at ingest time; five new DB columns
added via safe ALTER TABLE migration.

Bulk selection: hover a photo to reveal a circle checkbox; selecting
any photo activates a floating action bar for star/unstar and add-to-album
across the whole selection. PhotoCard wrapped in React.memo to limit
re-renders to only affected cards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-08-18 15:02:52 -04:00
1 parent f8b32dd440
commit 51c752602a
11 files changed
+598 -31

No files matched your search

+22
View File
@@ -130,6 +130,28 @@ export function fetchMemories() {
return api(`/api/memories/today?date=${date}`);
}
// Albums
export function fetchAlbums() {
return api('/api/albums');
}
export function renameCollection(id, name) {
return api(`/api/collections/${id}`, { method: 'PATCH', ...json({ name }) });
}
export function deleteCollection(id) {
return api(`/api/collections/${id}`, { method: 'DELETE' });
}
// Bulk operations
export function bulkStar(ids, starred) {
return api('/api/photos/bulk', { method: 'PATCH', ...json({ ids, starred }) });
}
export function bulkAddToCollection(ids, collectionId) {
return api('/api/photos/bulk/collections', { method: 'POST', ...json({ ids, collectionId }) });
}
// Duplicates
export function fetchDuplicates() {
return api('/api/duplicates');