diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/photos-app.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/photos-app.js | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/photos-app.js b/packages/meshbay-hub/src/meshbay_hub/static/photos-app.js index 00bc288..afc815a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/photos-app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/photos-app.js @@ -10,6 +10,8 @@ import { transfers } from './transfers.js'; import { MediaThumb, LazyTile } from './media-tiles.js'; import { SourceTag } from './group-name.js'; import { CastButton, castSession, useCastDevice, showPhoto } from './cast-session.js'; +import { Menu, useMenu } from './menu.js'; +import { copyLink } from './copy-link.js'; // ── Photos ─────────────────────────────────────────────────────────────────── // @@ -118,11 +120,11 @@ function AlbumLanding({ albums, transportRef, gekRef, onOpen }) { // ── open album: grid of its own photos ────────────────────────────────────── -function PhotoTile({ entry, transportRef, gekRef, onOpen }) { +function PhotoTile({ entry, transportRef, gekRef, onOpen, onMenu }) { const tRef = entry._tRef || transportRef; const gRef = entry._gRef || gekRef; return html` - <div class="photo-tile" onClick=${onOpen}> + <div class="photo-tile" onClick=${onOpen} onContextMenu=${onMenu}> <${MediaThumb} thumbHash=${entry.thumb_hash} alt=${entry.name} cls="photo-tile-thumb" transportRef=${tRef} gekRef=${gRef} emptyIcon="image" /> @@ -153,7 +155,7 @@ const ZOOM_MAX = 400; // a slow node must not skip a photo nobody saw. const SLIDESHOW_MS = 5000; -function Lightbox({ photos, index, transportRef, gekRef, onClose, onNav }) { +function Lightbox({ photos, index, transportRef, gekRef, onClose, onNav, linkFor }) { const entry = photos[index]; const tRef = entry._tRef || transportRef; const gRef = entry._gRef || gekRef; @@ -284,6 +286,10 @@ function Lightbox({ photos, index, transportRef, gekRef, onClose, onNav }) { aria-pressed=${slideshow ? 'true' : 'false'}> <${Icon} name=${slideshow ? 'pause' : 'play'} /></button> <${CastButton} variant="overlay" cls="video-close" /> + ${linkFor && linkFor(entry) && html` + <button class="video-close" onClick=${() => copyLink(linkFor(entry))} + title=${t('link.copy')} aria-label=${t('link.copy')}> + <${Icon} name="link" /></button>`} <button class="video-close" onClick=${onClose} title=${t('video.close')}> <${Icon} name="close" /></button> </div> @@ -311,8 +317,16 @@ function Lightbox({ photos, index, transportRef, gekRef, onClose, onNav }) { `; } -function AlbumView({ album, entries, transportRef, gekRef, setError, onBack, readOnly }) { +function AlbumView({ album, entries, transportRef, gekRef, setError, onBack, readOnly, linkFor }) { const [lightboxIndex, setLightboxIndex] = useState(null); + // Right-click a photo for its link. A tile has no dots to press, so on a + // touchscreen the link is in the lightbox's bar instead. + const { menu, openAt, close: closeMenu } = useMenu(); + const onTileMenu = (e, entry) => { + const link = linkFor ? linkFor(entry) : null; + if (!link) return; + openAt(e, [{ label: t('link.copy'), icon: 'link', onSelect: () => copyLink(link) }]); + }; const zip = useCallback(async () => { const transport = transportRef.current; @@ -352,15 +366,16 @@ function AlbumView({ album, entries, transportRef, gekRef, setError, onBack, rea ${album.photos.map((e, i) => html` <${LazyTile} key=${e.id} cls="photo-tile-slot"> <${PhotoTile} entry=${e} transportRef=${transportRef} gekRef=${gekRef} - onOpen=${() => setLightboxIndex(i)} /> + onOpen=${() => setLightboxIndex(i)} onMenu=${(ev) => onTileMenu(ev, e)} /> </${LazyTile}> `)} </div> ${lightboxIndex !== null && html` <${Lightbox} photos=${album.photos} index=${lightboxIndex} transportRef=${transportRef} gekRef=${gekRef} - onClose=${() => setLightboxIndex(null)} onNav=${navigate} /> + onClose=${() => setLightboxIndex(null)} onNav=${navigate} linkFor=${linkFor} /> `} + ${menu && html`<${Menu} ...${menu} onClose=${closeMenu} />`} `; } @@ -369,7 +384,7 @@ function AlbumView({ album, entries, transportRef, gekRef, setError, onBack, rea function PhotosApp({ groupId, transportRef, gekRef, status, entries, availableEntries, photoDirectories, setError, - hideFilter, readOnly, + hideFilter, readOnly, linkFor, }) { const [openDir, setOpenDir] = useState(null); const [filter, setFilter] = useState(''); @@ -423,7 +438,7 @@ function PhotosApp({ ${status === 'connected' && openAlbum && html` <${AlbumView} album=${openAlbum} entries=${entries} transportRef=${transportRef} gekRef=${gekRef} setError=${setError} - onBack=${() => setOpenDir(null)} readOnly=${readOnly} /> + onBack=${() => setOpenDir(null)} readOnly=${readOnly} linkFor=${linkFor} /> `} `; } |