feat(library): close the mobile preview on the frame the reader swiped to, selected in the thumb grid
This commit is contained in:
@@ -332,6 +332,12 @@
|
||||
contain-intrinsic-size: 110px 110px;
|
||||
}
|
||||
|
||||
/* The frame the reader stopped at in the preview, lit up in the grid. */
|
||||
.mob-lib-thumb-cell.selected {
|
||||
outline: 2px solid #f59e0b;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.mob-lib-thumb-cell img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -115,6 +115,9 @@ export function MobileLibrary({
|
||||
const [tab, setTab] = useState<MobileTab>('photos');
|
||||
const [selectedAlbum, setSelectedAlbum] = useState<string | null>(null);
|
||||
const [selectedPhoto, setSelectedPhoto] = useState<LibraryPhoto | null>(null);
|
||||
// The frame the reader stopped at: it outlives the preview, so closing the
|
||||
// picture lights that frame up in the thumb grid.
|
||||
const [activeId, setActiveId] = useState<string | null>(null);
|
||||
const [shot, setShot] = useState<{ line: string; lat: number | null; lng: number | null; place: string | null } | null>(null);
|
||||
|
||||
// Read photo EXIF specifications and GPS (similar to Desktop UI)
|
||||
@@ -573,6 +576,19 @@ export function MobileLibrary({
|
||||
const next = i < 0 ? undefined : searchResults[i + d];
|
||||
if (next) setSelectedPhoto(next);
|
||||
};
|
||||
|
||||
// Every frame the preview shows — opened or swiped to — is the one the reader
|
||||
// stopped at.
|
||||
useEffect(() => {
|
||||
if (selectedPhoto) setActiveId(selectedPhoto.id);
|
||||
}, [selectedPhoto]);
|
||||
|
||||
// Closing the frame in the one-at-a-time list hands the reader to the thumb
|
||||
// grid, which opens on the frame they stopped at.
|
||||
const closePhoto = () => {
|
||||
setSelectedPhoto(null);
|
||||
if (viewMode === 'single') setViewMode('grid');
|
||||
};
|
||||
// Where the finger went down: only the distance it travelled matters, and only
|
||||
// once it has lifted.
|
||||
const swipeFrom = useRef<{ x: number; y: number } | null>(null);
|
||||
@@ -631,6 +647,13 @@ export function MobileLibrary({
|
||||
sortOrder,
|
||||
]);
|
||||
|
||||
// Landing on that frame: the grid brings it under the eye rather than leaving
|
||||
// the reader to hunt for it.
|
||||
useEffect(() => {
|
||||
if (viewMode !== 'grid' || !activeId) return;
|
||||
scrollContainerRef.current?.querySelector('.mob-lib-thumb-cell.selected')?.scrollIntoView({ block: 'center' });
|
||||
}, [viewMode, activeId]);
|
||||
|
||||
// Available years from photos & server timeline buckets
|
||||
const availableYears = useMemo(() => {
|
||||
const years = new Set<number>();
|
||||
@@ -1367,7 +1390,7 @@ export function MobileLibrary({
|
||||
return (
|
||||
<div
|
||||
key={photo.id}
|
||||
className="mob-lib-thumb-cell"
|
||||
className={`mob-lib-thumb-cell ${activeId === photo.id ? 'selected' : ''}`}
|
||||
onClick={() => setSelectedPhoto(photo)}
|
||||
>
|
||||
<img
|
||||
@@ -1767,7 +1790,7 @@ export function MobileLibrary({
|
||||
{searchResults.map((photo) => (
|
||||
<div
|
||||
key={photo.id}
|
||||
className="mob-lib-thumb-cell"
|
||||
className={`mob-lib-thumb-cell ${activeId === photo.id ? 'selected' : ''}`}
|
||||
onClick={() => setSelectedPhoto(photo)}
|
||||
>
|
||||
<img src={remoteUrl('thumbnail', photo)} alt={photo.name} loading="lazy" />
|
||||
@@ -2217,7 +2240,7 @@ export function MobileLibrary({
|
||||
<button
|
||||
type="button"
|
||||
className="mob-lib-status-btn"
|
||||
onClick={() => setSelectedPhoto(null)}
|
||||
onClick={closePhoto}
|
||||
style={{ fontSize: '18px', padding: '6px' }}
|
||||
aria-label="Close"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user