feat(gallery): add-to-album submenu on the image right-click menu

Right-clicking an image in the Gallery or Timeline now offers an
"Add to Album" submenu listing all albums with their counts — the first
use of the new SubMenu primitive. Filing a single image away no longer
requires starting a multi-select.
This commit is contained in:
2026-07-03 23:54:40 +01:00
parent 83081928f6
commit 5d46ee5b94
2 changed files with 24 additions and 4 deletions
+7 -3
View File
@@ -56,12 +56,16 @@ aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
from whatever collection you are already browsing. Videos are skipped, controls from whatever collection you are already browsing. Videos are skipped, controls
tuck themselves away after a few seconds, and Settings lets you pick the pace tuck themselves away after a few seconds, and Settings lets you pick the pace
and whether playback follows the current order or goes random. and whether playback follows the current order or goes random.
- **Add to album from the right-click menu** — right-click any image in the
Gallery or Timeline and file it straight into an album from the new "Add to
Album" submenu. One image, one click, zero ceremony.
### Changed ### Changed
- **Consistent right-click menus** — the folder, album, image, and theme menus - **Right-click menus got their act together** — images, folders, albums, and
now share one look and behavior: they stay inside the window instead of the theme switcher now share one menu style with one set of manners: they
spilling off the edge, close on Escape, and support proper submenus. stay on screen instead of wandering off the edge, all close on Escape, and
they can do proper submenus now.
- **Neater lightbox details** — image and video metadata now sits in two columns, - **Neater lightbox details** — image and video metadata now sits in two columns,
so the info panel shows more at a glance with less scrolling. so the info panel shows more at a glance with less scrolling.
- **Faster Explore revisits** — returning to a folder's visual clusters should - **Faster Explore revisits** — returning to a folder's visual clusters should
+17 -1
View File
@@ -1,5 +1,5 @@
import { ImageRecord, useGalleryStore } from "../store"; import { ImageRecord, useGalleryStore } from "../store";
import { ContextMenu, MenuItem, MenuLabel, MenuSeparator } from "./menu"; import { ContextMenu, MenuItem, MenuLabel, MenuSeparator, SubMenu } from "./menu";
import { Tooltip } from "./Tooltip"; import { Tooltip } from "./Tooltip";
/** Right-click menu for an image tile. Shared by the Gallery grid and the Timeline. */ /** Right-click menu for an image tile. Shared by the Gallery grid and the Timeline. */
@@ -17,6 +17,8 @@ export function ImageContextMenu({
const openImage = useGalleryStore((state) => state.openImage); const openImage = useGalleryStore((state) => state.openImage);
const updateImageDetails = useGalleryStore((state) => state.updateImageDetails); const updateImageDetails = useGalleryStore((state) => state.updateImageDetails);
const findSimilar = useGalleryStore((state) => state.findSimilar); const findSimilar = useGalleryStore((state) => state.findSimilar);
const albums = useGalleryStore((state) => state.albums);
const addToAlbum = useGalleryStore((state) => state.addToAlbum);
const canFindSimilar = image.embedding_status === "ready"; const canFindSimilar = image.embedding_status === "ready";
return ( return (
@@ -31,6 +33,20 @@ export function ImageContextMenu({
disabled={!canFindSimilar} disabled={!canFindSimilar}
onSelect={() => findSimilar(image.id, image.folder_id)} onSelect={() => findSimilar(image.id, image.folder_id)}
/> />
<SubMenu label="Add to Album" panelClassName="max-h-64 overflow-y-auto">
{albums.length === 0 ? (
<MenuItem label="No albums yet" disabled />
) : (
albums.map((album) => (
<MenuItem
key={album.id}
label={album.name}
hint={album.image_count.toLocaleString()}
onSelect={() => void addToAlbum(album.id, [image.id])}
/>
))
)}
</SubMenu>
<MenuSeparator /> <MenuSeparator />
<MenuLabel>Rating</MenuLabel> <MenuLabel>Rating</MenuLabel>
<div className="flex items-center gap-0.5 px-2 pb-1.5"> <div className="flex items-center gap-0.5 px-2 pb-1.5">