feat(web): fold duplicates+inbox into /review; sidebar UX cleanup
- /duplicates and /inbox routes removed and folded into /review as additional tabs alongside cause tabs; /duplicates keeps a redirect for bookmarks. - LeftSidebar: drop import/inbox tile and favorites; show per-user BasePath label at the folder root. - RightSidebar: split file header into read-only path over editable basename (matches sidecar rename contract); date field switches to plain-text ISO YYYY-MM-DD (no native datetime picker) with strict validation and revert-on-invalid-blur; preserves original hour. - BulkMetadataSidebar: same ISO-only date input with invalid-state styling and apply-button gating. - BulkActionBar: drop redundant Restore and Undo buttons; ⌘Z still reachable via gridKeyNav. - gridKeyNav: remove favorite toggle (F) alongside the favorites view retirement. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,9 +7,7 @@ import {
|
||||
batchArchive,
|
||||
batchDelete,
|
||||
batchRestore,
|
||||
likePhoto,
|
||||
removeFromHeap,
|
||||
unlikePhoto,
|
||||
type PpAlbum
|
||||
} from '$lib/services/photoprism';
|
||||
import { queryClient } from '$lib/queryClient';
|
||||
@@ -55,7 +53,7 @@ export interface GridKeyNavParams {
|
||||
* - Arrow-key focus navigation (with shift-extend) inside the visible grid
|
||||
* - Click + shift/ctrl click selection mutations
|
||||
* - Window-level shortcuts mirroring mule-image's keyboard layer:
|
||||
* x archive-toggle, u restore, f favorite-toggle, s + (1–9) add to
|
||||
* x archive-toggle, u restore, s + (1–9) add to
|
||||
* heap N (bare s adds to the currently-viewed heap), b/Tab toggles
|
||||
* left sidebar, i toggles right sidebar, space/enter opens preview,
|
||||
* esc clears, ⌘Z undoes, ⌘A selects all visible.
|
||||
@@ -302,46 +300,6 @@ export function gridKeyNav(node: HTMLElement, params: GridKeyNavParams = {}) {
|
||||
toast.success(`Kept ${ids.length}`);
|
||||
}
|
||||
|
||||
/** Flip the Favorite (heart) flag on cull targets. Reads the first
|
||||
* target's cached `Favorite` to decide direction so a mixed selection
|
||||
* resolves to "make them all favorited" when the first isn't, mirroring
|
||||
* the way `toggleArchive('toggle')` works. */
|
||||
async function toggleFavoriteOnTargets() {
|
||||
const ids = cullTargets();
|
||||
if (ids.length === 0) {
|
||||
toast.message('Nothing to favorite', {
|
||||
description: 'Click a photo or select some first'
|
||||
});
|
||||
return;
|
||||
}
|
||||
const first = cachedPhoto(ids[0]);
|
||||
const next = !(first?.Favorite ?? false);
|
||||
const { updated, errors } = await batchEdit(ids, (id) =>
|
||||
next ? likePhoto(id) : unlikePhoto(id)
|
||||
);
|
||||
void queryClient.invalidateQueries({ queryKey: ['photos'] });
|
||||
for (const id of ids) {
|
||||
void queryClient.invalidateQueries({ queryKey: ['photo', id] });
|
||||
}
|
||||
const verb = next ? 'Favorited' : 'Unfavorited';
|
||||
if (errors.length) {
|
||||
// Surface the actual first error message — silent failures here are
|
||||
// the #1 reason `f` "doesn't work" (e.g. permission, network, 404).
|
||||
toast.error(`${verb} ${updated.length}; ${errors.length} failed`, {
|
||||
description: errors[0].message
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast.success(`${verb} ${ids.length}`);
|
||||
pushUndo(`${verb} ${ids.length}`, async () => {
|
||||
await batchEdit(ids, (id) => (next ? unlikePhoto(id) : likePhoto(id)));
|
||||
void queryClient.invalidateQueries({ queryKey: ['photos'] });
|
||||
for (const id of ids) {
|
||||
void queryClient.invalidateQueries({ queryKey: ['photo', id] });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── S chord (add-to-heap) ────────────────────────────────────────────
|
||||
// Press S: arm a short timer. A digit 1–9 within the window adds the
|
||||
// cull targets to the Nth heap in the heap list. Any other key cancels
|
||||
@@ -548,12 +506,6 @@ export function gridKeyNav(node: HTMLElement, params: GridKeyNavParams = {}) {
|
||||
e.preventDefault();
|
||||
void toggleArchive('restore');
|
||||
return;
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (meta || shift) return;
|
||||
e.preventDefault();
|
||||
void toggleFavoriteOnTargets();
|
||||
return;
|
||||
case 's':
|
||||
case 'S':
|
||||
if (meta || shift) return;
|
||||
|
||||
Reference in New Issue
Block a user