
PhotoSite
A gallery website that generates dynamic masonry layout and photo view from folders of images.
Motivation
I do some photography as a hobby and wanted a simple way to share my photos online in a photo portfolio.
Existing solutions all seem to have some drawbacks:
- Photos need to be manually imported
- No control over the layout or information display (based on EXIF data)
- No support for image transformation based on preview and lightbox view
- No support for mobile gestures
- The solution becomes too complex for my needs
- ...
I've checked services like Format and self-hosted solutions like Lychee, Piwigo, and Photoview.
PhotoSite
I decided to make a simple photo portfolio and gallery website that generates dynamic masonry layout and photo view from folders of images.
No manual configuration
Ideally, the server should be able to parse the folder structure and EXIF data of each image to generate gallery layout along with photo views.
Since all data is contained in local folders and photos, the album structure cache and transformed images can be automatically generated from them.
The project was developed in two days using Next.js, Tailwind CSS, and the sharp image library.
Implementation
- Exif data display
- Mobile swipe gestures
- Adaptive preview
- Folder based album generation
- Folder based navbar generation
- Dynamic and responsive masonry layout
- Fade in and out transition
Installation
docker-compose.yml
:
services:
photosite:
image: meinya/photosite:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
- RAW=/raw
- PREVIEW=/preview
volumes:
- ./raw:/raw
- ./preview:/preview
Folder Structure
Place your images in a separate album folder with any name inside preview and raw folders. For instance:
/raw/Toronto/IMG_1.jpg
/preview/Toronto/IMG_1.jpg
The same image should have the same name in both folders.
This will generate an album called Toronto with its own navbar link. All images inside the Toronto folder will be displayed in the album. The EXIF data will be displayed in the corresponding photo view if it exists.




To set a cover page for HTML embeds, place a cover.jpg
in the preview album folder:
/preview/Toronto/cover.jpg
To set a cover page for the root page, place a cover.jpg
in the preview root folder:
/preview/cover.jpg


Photo View
The photo view popup will initially display a preview image, followed by the full-resolution raw image once it has finished loading.
A fade in and out animation is applied to transition from the previous image to the next one when the user swipes.
AVIF/WebP Optimization
By default, the project will NOT generate AVIF/WebP images due to the fact that users may want to download the images and share them. It's not ideal to share the image in AVIF format since Apps like Discord do not support AVIF. The project will use the original image format.
Conversion to AVIF/WebP can be enabled by injecting a procedure to the startup scanning pipeline.
For information on image transformation, you may refer to a script I wrote.
Tags:
Next.js,
TypeScript,
Tailwind CSS,
shadcn,
EXIF,
sharp