style: format frontend with prettier
Mechanical one-shot pass of pnpm format over src/, tests/, tools/, and root configs. No functional changes; build and type-check verified.
This commit is contained in:
+71
-64
@@ -1,50 +1,54 @@
|
||||
import { useEffect, useLayoutEffect, useRef, useCallback, useMemo, useState } from "react";
|
||||
import { useVirtualizer } from "@tanstack/react-virtual";
|
||||
import { ImageRecord, parseSearchValue, tileSizeForZoom, useGalleryStore } from "../store";
|
||||
import { BulkActionBar } from "./BulkActionBar";
|
||||
import { ImageContextMenu } from "./ImageContextMenu";
|
||||
import { GalleryEmptyState, GalleryLoadingState } from "./gallery/GalleryEmptyState";
|
||||
import { ImageTile } from "./gallery/ImageTile";
|
||||
import { useEffect, useLayoutEffect, useRef, useCallback, useMemo, useState } from 'react'
|
||||
import { useVirtualizer } from '@tanstack/react-virtual'
|
||||
import { ImageRecord, parseSearchValue, tileSizeForZoom, useGalleryStore } from '../store'
|
||||
import { BulkActionBar } from './BulkActionBar'
|
||||
import { ImageContextMenu } from './ImageContextMenu'
|
||||
import { GalleryEmptyState, GalleryLoadingState } from './gallery/GalleryEmptyState'
|
||||
import { ImageTile } from './gallery/ImageTile'
|
||||
|
||||
const GAP = 6;
|
||||
const GAP = 6
|
||||
|
||||
export function Gallery() {
|
||||
const images = useGalleryStore((state) => state.images);
|
||||
const loadMoreImages = useGalleryStore((state) => state.loadMoreImages);
|
||||
const openImage = useGalleryStore((state) => state.openImage);
|
||||
const totalImages = useGalleryStore((state) => state.totalImages);
|
||||
const loadingImages = useGalleryStore((state) => state.loadingImages);
|
||||
const zoomPreset = useGalleryStore((state) => state.zoomPreset);
|
||||
const search = useGalleryStore((state) => state.search);
|
||||
const collectionTitle = useGalleryStore((state) => state.collectionTitle);
|
||||
const imageLoadError = useGalleryStore((state) => state.imageLoadError);
|
||||
const galleryScrollResetKey = useGalleryStore((state) => state.galleryScrollResetKey);
|
||||
const isSimilarResults = collectionTitle === "Similar Images";
|
||||
const parsedSearch = parseSearchValue(search);
|
||||
const images = useGalleryStore((state) => state.images)
|
||||
const loadMoreImages = useGalleryStore((state) => state.loadMoreImages)
|
||||
const openImage = useGalleryStore((state) => state.openImage)
|
||||
const totalImages = useGalleryStore((state) => state.totalImages)
|
||||
const loadingImages = useGalleryStore((state) => state.loadingImages)
|
||||
const zoomPreset = useGalleryStore((state) => state.zoomPreset)
|
||||
const search = useGalleryStore((state) => state.search)
|
||||
const collectionTitle = useGalleryStore((state) => state.collectionTitle)
|
||||
const imageLoadError = useGalleryStore((state) => state.imageLoadError)
|
||||
const galleryScrollResetKey = useGalleryStore((state) => state.galleryScrollResetKey)
|
||||
const isSimilarResults = collectionTitle === 'Similar Images'
|
||||
const parsedSearch = parseSearchValue(search)
|
||||
|
||||
const parentRef = useRef<HTMLDivElement>(null);
|
||||
const [containerWidth, setContainerWidth] = useState(0);
|
||||
const [contextMenu, setContextMenu] = useState<{ x: number; y: number; image: ImageRecord } | null>(null);
|
||||
const parentRef = useRef<HTMLDivElement>(null)
|
||||
const [containerWidth, setContainerWidth] = useState(0)
|
||||
const [contextMenu, setContextMenu] = useState<{
|
||||
x: number
|
||||
y: number
|
||||
image: ImageRecord
|
||||
} | null>(null)
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const el = parentRef.current;
|
||||
if (!el) return;
|
||||
setContainerWidth(el.clientWidth);
|
||||
const el = parentRef.current
|
||||
if (!el) return
|
||||
setContainerWidth(el.clientWidth)
|
||||
const ro = new ResizeObserver((entries) => {
|
||||
setContainerWidth(entries[0].contentRect.width);
|
||||
});
|
||||
ro.observe(el);
|
||||
return () => ro.disconnect();
|
||||
}, []);
|
||||
setContainerWidth(entries[0].contentRect.width)
|
||||
})
|
||||
ro.observe(el)
|
||||
return () => ro.disconnect()
|
||||
}, [])
|
||||
|
||||
const tileSize = tileSizeForZoom(zoomPreset);
|
||||
const tileSize = tileSizeForZoom(zoomPreset)
|
||||
const cols = useMemo(
|
||||
() => Math.max(1, Math.floor((containerWidth - GAP) / (tileSize + GAP))),
|
||||
[containerWidth, tileSize],
|
||||
);
|
||||
const rowCount = Math.ceil(images.length / cols);
|
||||
[containerWidth, tileSize]
|
||||
)
|
||||
const rowCount = Math.ceil(images.length / cols)
|
||||
|
||||
const estimateSize = useCallback(() => tileSize + GAP, [tileSize]);
|
||||
const estimateSize = useCallback(() => tileSize + GAP, [tileSize])
|
||||
|
||||
const virtualizer = useVirtualizer({
|
||||
count: rowCount,
|
||||
@@ -52,36 +56,39 @@ export function Gallery() {
|
||||
estimateSize,
|
||||
overscan: 3,
|
||||
paddingStart: GAP,
|
||||
});
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
virtualizer.measure();
|
||||
}, [cols, virtualizer]);
|
||||
virtualizer.measure()
|
||||
}, [cols, virtualizer])
|
||||
|
||||
useEffect(() => {
|
||||
parentRef.current?.scrollTo({ top: 0, left: 0 });
|
||||
}, [galleryScrollResetKey]);
|
||||
parentRef.current?.scrollTo({ top: 0, left: 0 })
|
||||
}, [galleryScrollResetKey])
|
||||
|
||||
const handleScroll = useCallback(() => {
|
||||
const el = parentRef.current;
|
||||
if (!el) return;
|
||||
if (el.scrollTop < 24) return;
|
||||
const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 600;
|
||||
const el = parentRef.current
|
||||
if (!el) return
|
||||
if (el.scrollTop < 24) return
|
||||
const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 600
|
||||
if (nearBottom && !loadingImages && images.length < totalImages) {
|
||||
void loadMoreImages();
|
||||
void loadMoreImages()
|
||||
}
|
||||
}, [images.length, loadMoreImages, loadingImages, totalImages]);
|
||||
}, [images.length, loadMoreImages, loadingImages, totalImages])
|
||||
|
||||
useEffect(() => {
|
||||
const el = parentRef.current;
|
||||
if (!el) return;
|
||||
el.addEventListener("scroll", handleScroll, { passive: true });
|
||||
return () => el.removeEventListener("scroll", handleScroll);
|
||||
}, [handleScroll]);
|
||||
const el = parentRef.current
|
||||
if (!el) return
|
||||
el.addEventListener('scroll', handleScroll, { passive: true })
|
||||
return () => el.removeEventListener('scroll', handleScroll)
|
||||
}, [handleScroll])
|
||||
|
||||
return (
|
||||
<div className="relative min-h-0 flex-1">
|
||||
<div ref={parentRef} className="absolute inset-0 overflow-y-auto overflow-x-hidden bg-gray-950">
|
||||
<div
|
||||
ref={parentRef}
|
||||
className="absolute inset-0 overflow-x-hidden overflow-y-auto bg-gray-950"
|
||||
>
|
||||
{images.length === 0 && loadingImages ? (
|
||||
<GalleryLoadingState isSimilarResults={isSimilarResults} parsedSearch={parsedSearch} />
|
||||
) : images.length === 0 && !loadingImages ? (
|
||||
@@ -91,25 +98,25 @@ export function Gallery() {
|
||||
parsedSearch={parsedSearch}
|
||||
/>
|
||||
) : (
|
||||
<div style={{ height: virtualizer.getTotalSize(), position: "relative" }}>
|
||||
<div style={{ height: virtualizer.getTotalSize(), position: 'relative' }}>
|
||||
{virtualizer.getVirtualItems().map((virtualRow) => {
|
||||
const startIndex = virtualRow.index * cols;
|
||||
const rowImages = images.slice(startIndex, startIndex + cols);
|
||||
const startIndex = virtualRow.index * cols
|
||||
const rowImages = images.slice(startIndex, startIndex + cols)
|
||||
return (
|
||||
<div
|
||||
key={virtualRow.key}
|
||||
style={{
|
||||
position: "absolute",
|
||||
position: 'absolute',
|
||||
top: virtualRow.start,
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
height: virtualRow.size,
|
||||
display: "grid",
|
||||
display: 'grid',
|
||||
gridTemplateColumns: `repeat(${cols}, ${tileSize}px)`,
|
||||
gap: GAP,
|
||||
paddingLeft: GAP,
|
||||
paddingRight: GAP,
|
||||
paddingBottom: GAP,
|
||||
boxSizing: "border-box",
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{rowImages.map((image) => (
|
||||
@@ -118,13 +125,13 @@ export function Gallery() {
|
||||
image={image}
|
||||
onClick={() => openImage(image)}
|
||||
onContextMenu={(event) => {
|
||||
event.preventDefault();
|
||||
setContextMenu({ x: event.clientX, y: event.clientY, image });
|
||||
event.preventDefault()
|
||||
setContextMenu({ x: event.clientX, y: event.clientY, image })
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
@@ -149,5 +156,5 @@ export function Gallery() {
|
||||
container so it stays put while the grid scrolls. */}
|
||||
<BulkActionBar />
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user