The ten most-duplicated inline SVGs (Check, Close, ChevronDown/Right,
Plus, Photo, Folder, Warning, Star, Play) become shared components --
34+ copies across 15 files replaced. Stroke icons take a per-site
strokeWidth since weights legitimately differ by context; icons that
appear once or use variant path data stay inline.
The album popover body (album list + create-new-album form) moves to
its own component. The host supplies onPick, which both an existing
album row and a freshly created album route through -- BulkActionBar
adds the selection and closes the panel. Ready for reuse anywhere else
an album needs picking (e.g. the context menu submenu later).
Replaces the hand-rolled outside-pointerdown listeners with the shared
hook. Both popovers now also close on Escape, and listeners only attach
while a panel is actually open.
Wrap app controls with the shared Tooltip component and use cursor-positioned tooltip placement for icon buttons, chips, path labels, and media controls.
Leave native title attributes on the window chrome buttons so Minimize, Maximize, and Close keep platform-style behavior.
Security / robustness / a11y polish on top of the color-search + tooltips work:
- URL opening: route through validated backend commands (open_map_location
with lat/lon bounds-checking, open_changelog_url with a fixed URL) instead
of the frontend opener:allow-open-url capability, which is now removed.
- EXIF GPS parsing: validate coordinate ranges and require the correct
N/S/E/W hemisphere ref byte, then clamp.
- Guard double-submit on album create / add-to-album (Lightbox, BulkActionBar,
Sidebar) and discard stale autocomplete responses in the bulk tag editor.
- Gallery tile: stop nesting <button>s — non-interactive tile div with an
overlay button for open/toggle; checkbox and Similar promoted with z-index
+ focus rings.
- Accessibility: keyboard handlers, focus-visible rings, and aria on album
rows, tag-manage actions, and tile controls; Tooltip uses a block <div>
wrapper in block mode and aria-hidden when hidden.
- Show the destination URL in a tooltip on the "Full changelog" link so the
user can see where it goes before clicking.
- Toolbar "All" filter also clears the color filter; color-filtered views no
longer get unfiltered newly-indexed images injected.
- Sidebar reorder: bail if the album set changed mid-drag.
- Tooling: add cargo fmt scripts; alphabetize package.json scripts.
Albums (manual collections):
- New albums/album_images tables with FK cascades; DB functions and Tauri
commands for create/rename/delete/delete-many/reorder/list, add/remove
images, and paginated get_album_images.
- Distinct sidebar "ALBUMS" section with cover thumbnails, create/rename/
delete, and a Manage multi-select mode for bulk album deletion.
- Album view reuses the gallery grid (activeView "album" + selectedAlbumId);
spans folders; add from the bulk bar or the lightbox, remove from within.
Gallery multi-select + bulk actions:
- gallerySelectedIds selection model with a top-left corner checkbox that
reveals on corner hover; click-to-toggle in selection mode, double-click
to open.
- Floating BulkActionBar: tag (inline autocomplete popover), rating,
favorite, add-to-album, and a delete with an explicit "from disk"
confirmation. Batch commands bulk_update_details/bulk_add_tags/
bulk_remove_tag.
Also:
- Duplicate Finder delete now requires confirmation with clear "from disk"
wording (was single-click fire-and-forget).
- CPU/CUDA build-variant badge in Settings (get_build_variant).
- Rating/favorite no longer re-sorts derived collections (similar/region/
semantic/tag/album results); single and bulk paths replace in place there.
- Album-aware indexed-images/media-updated handlers so thumbnails paint and
newly-indexed files don't leak into an album view.
- CHANGELOG updated.