From aea08337d1625f2d8ce8322e769e5022315a8f73 Mon Sep 17 00:00:00 2001 From: jason Date: Sat, 28 Mar 2026 02:11:31 -0500 Subject: [PATCH] build search global --- frontend/src/pages/Gallery.tsx | 112 ++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/frontend/src/pages/Gallery.tsx b/frontend/src/pages/Gallery.tsx index 24dbf7c..ff9afcb 100644 --- a/frontend/src/pages/Gallery.tsx +++ b/frontend/src/pages/Gallery.tsx @@ -1,5 +1,5 @@ import { useState, useCallback, useEffect } from 'react'; -import { Search, Upload as UploadIcon, X, Share2, Lock, LogOut, Settings } from 'lucide-react'; +import { Search, Upload as UploadIcon, X, Share2, Lock, LogOut, Settings, ChevronLeft, ChevronRight } from 'lucide-react'; import { useMemes, useTags, useCollections } from '../hooks/useMemes'; import { useAuth, useLogout } from '../hooks/useAuth'; import { GalleryGrid } from '../components/GalleryGrid'; @@ -11,11 +11,14 @@ import { CollectionBar } from '../components/CollectionBar'; import { SettingsModal } from '../components/SettingsModal'; import type { Meme } from '../api/client'; +const PAGE_SIZE = 100; + export function Gallery() { const [search, setSearch] = useState(''); const [debouncedSearch, setDebouncedSearch] = useState(''); const [activeTag, setActiveTag] = useState(null); const [activeCollectionId, setActiveCollectionId] = useState(null); + const [page, setPage] = useState(1); const [selectedMemeId, setSelectedMemeId] = useState(null); const [quickShareMeme, setQuickShareMeme] = useState(null); const [showUpload, setShowUpload] = useState(false); @@ -36,14 +39,11 @@ export function Gallery() { } }, [unsorted, activeCollectionId]); - // When on Unsorted, cap at 50 (recent uploads view); other folders show all (paginated) - const isUnsorted = activeCollectionId === unsorted?.id; - const limit = isUnsorted ? 50 : 100; - // Debounce search const [searchTimer, setSearchTimer] = useState | null>(null); function handleSearchChange(val: string) { setSearch(val); + setPage(1); if (searchTimer) clearTimeout(searchTimer); const t = setTimeout(() => setDebouncedSearch(val), 300); setSearchTimer(t); @@ -55,9 +55,13 @@ export function Gallery() { q: debouncedSearch || undefined, parent_only: true, collection_id: isSearching ? undefined : (activeCollectionId ?? undefined), - limit: isSearching ? 200 : limit, + page, + limit: PAGE_SIZE, }); + const total = data?.total ?? 0; + const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE)); + const { data: tags } = useTags(); const handleOpen = useCallback((meme: Meme) => setSelectedMemeId(meme.id), []); @@ -71,11 +75,20 @@ export function Gallery() { function handleCollectionSelect(id: number) { setActiveCollectionId(id); setActiveTag(null); + setPage(1); setSearch(''); setDebouncedSearch(''); } - const activeCollection = collections?.find((c) => c.id === activeCollectionId); + function handleTagSelect(tag: string | null) { + setActiveTag(tag); + setPage(1); + } + + function goToPage(p: number) { + setPage(p); + window.scrollTo({ top: 0, behavior: 'smooth' }); + } return (
@@ -100,7 +113,7 @@ export function Gallery() { /> {search && ( + + {page} / {totalPages} + + +
+ )} {isLoading ? ( @@ -238,6 +269,29 @@ export function Gallery() { onShare={handleShare} /> )} + + {/* Bottom pagination */} + {totalPages > 1 && !isLoading && !isError && ( +
+ + + Page {page} of {totalPages} + + +
+ )} {/* Meme detail modal */}