Skip to main content
The gallery interface is the central hub of Galey Cloud where users can view, organize, and manage their photos. Built with React and Next.js, it provides a responsive, real-time photo management experience.

Overview

The gallery page is implemented in app/gallery/page.tsx and orchestrates three main components:
  • AlbumSidebar - Navigate between albums and search photos
  • PhotoGrid - Display photos in a responsive grid layout
  • PhotoDetails - View detailed information about selected photos

Core Component Structure

export default function GalleryPage() {
  const [selectedAlbumId, setSelectedAlbumId] = useState<string | null>(null)
  const [selectedPhoto, setSelectedPhoto] = useState<Photo | null>(null)
  const [searchQuery, setSearchQuery] = useState('')
  
  return (
    <div className="flex h-svh overflow-hidden bg-background">
      <AlbumSidebar
        albums={albums}
        selectedAlbumId={selectedAlbumId}
        onSelectAlbum={setSelectedAlbumId}
        onCreateAlbum={handleCreateAlbum}
        onDeleteAlbum={handleDeleteAlbum}
        searchQuery={searchQuery}
        onSearchChange={setSearchQuery}
        onLogout={handleLogout}
      />
      
      <PhotoGrid
        photos={filteredPhotos}
        selectedPhotoId={selectedPhoto?.id ?? null}
        onSelectPhoto={setSelectedPhoto}
        onUpload={handleUpload}
        onDeletePhoto={handleDeletePhoto}
        onMovePhoto={handleMovePhoto}
        albums={albums}
        isUploading={isUploading}
        isLoading={photosLoading || albumsLoading}
      />
      
      <PhotoDetails
        photo={selectedPhoto}
        albumName={selectedAlbumName}
        onClose={() => setSelectedPhoto(null)}
        onDimensionsLoaded={handleDimensionsLoaded}
      />
    </div>
  )
}
Location: app/gallery/page.tsx:16-203

Real-Time Data with SWR

The gallery uses SWR for efficient data fetching and automatic revalidation:
const fetcher = (url: string) => fetch(url).then((r) => r.json())

const { data: albums = [], isLoading: albumsLoading } = useSWR<Album[]>(
  '/api/albums',
  fetcher
)

const { data: allPhotos = [], isLoading: photosLoading } = useSWR<Photo[]>(
  '/api/photos',
  fetcher
)
Location: app/gallery/page.tsx:14-30
SWR automatically revalidates data when the user refocuses the tab or reconnects to the network, ensuring the gallery always displays fresh data.

Photo Filtering

Photos are filtered in real-time based on album selection and search query:
const filteredPhotos = useMemo(() => {
  let photos = allPhotos
  if (selectedAlbumId) {
    photos = photos.filter((p) => p.album_id === selectedAlbumId)
  }
  if (searchQuery.trim()) {
    const q = searchQuery.toLowerCase()
    photos = photos.filter((p) => p.file_name.toLowerCase().includes(q))
  }
  return photos
}, [allPhotos, selectedAlbumId, searchQuery])
Location: app/gallery/page.tsx:32-42

Photo Selection

Users can select photos from the grid to view detailed information:
1

Click a photo in the grid

The PhotoGrid component triggers the onSelectPhoto callback
2

Photo details panel opens

The PhotoDetails component displays on the right side with metadata, dimensions, and dominant colors
3

View or close details

Users can close the panel by clicking the X button or select another photo

Layout Structure

The gallery uses a three-column flexbox layout:

Album Sidebar

Fixed width (256px) on the left for album navigation and search

Photo Grid

Flexible main area that displays photos in a responsive grid

Photo Details

Fixed width (320px) panel on the right for selected photo details

State Management

The gallery manages several pieces of state:
StateTypePurpose
selectedAlbumIdstring | nullCurrently selected album filter
selectedPhotoPhoto | nullCurrently selected photo for details view
searchQuerystringSearch filter for photo filenames
isUploadingbooleanUpload operation in progress

Cache Mutations

When photos or albums are modified, the gallery uses SWR’s mutate function to update the cache:
import { mutate } from 'swr'

// After uploading photos
await Promise.all(uploadPromises)
mutate('/api/photos')

// After deleting an album
mutate('/api/albums')
mutate('/api/photos')  // Photos may have been moved
Locations: app/gallery/page.tsx:70, app/gallery/page.tsx:136-137

Protected Route

The gallery page is protected by authentication middleware that redirects unauthenticated users to the login page. See the Authentication documentation for details.

Albums

Learn about album management in the sidebar

Photos

Explore photo upload, viewing, and management features

Build docs developers (and LLMs) love