chore: post-review hardening + changelog link tooltip
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.
This commit is contained in:
@@ -23,6 +23,7 @@ export function BulkActionBar() {
|
||||
|
||||
const [panel, setPanel] = useState<Panel>(null);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [creatingAlbum, setCreatingAlbum] = useState(false);
|
||||
const [newAlbumName, setNewAlbumName] = useState("");
|
||||
const barRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -67,11 +68,16 @@ export function BulkActionBar() {
|
||||
|
||||
const handleCreateAlbum = async () => {
|
||||
const name = newAlbumName.trim();
|
||||
if (!name) return;
|
||||
const album = await createAlbum(name);
|
||||
await addToAlbum(album.id, ids);
|
||||
setNewAlbumName("");
|
||||
setPanel(null);
|
||||
if (!name || creatingAlbum) return;
|
||||
setCreatingAlbum(true);
|
||||
try {
|
||||
const album = await createAlbum(name);
|
||||
await addToAlbum(album.id, ids);
|
||||
setNewAlbumName("");
|
||||
setPanel(null);
|
||||
} finally {
|
||||
setCreatingAlbum(false);
|
||||
}
|
||||
};
|
||||
|
||||
const btn = "rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors";
|
||||
@@ -187,11 +193,12 @@ export function BulkActionBar() {
|
||||
placeholder="New album…"
|
||||
value={newAlbumName}
|
||||
onChange={(event) => setNewAlbumName(event.target.value)}
|
||||
disabled={creatingAlbum}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-md border border-white/10 bg-white/5 px-2 py-1 text-xs text-gray-300 transition-colors hover:bg-white/10 hover:text-white disabled:opacity-50"
|
||||
disabled={!newAlbumName.trim()}
|
||||
disabled={creatingAlbum || !newAlbumName.trim()}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user