Image Library
A single-page, backend-free landing page that lists every image in img/,
lets you full-text search by filename, and copies an image's URL to your
clipboard when you click it. Built to be dropped onto an nginx server as plain
static files.
index.html the page
assets/styles.css styling (auto light/dark)
assets/app.js search, rendering, clipboard logic
generate-manifest.py scans img/ -> images.json, then commits
pushAll regenerate + commit + push, in one command
images.json generated manifest the page fetches
img/ put your images here
Why a manifest?
A browser cannot list a directory on its own, and "no backend" rules out an API
that would do it. So the file list is produced by a tiny build step:
generate-manifest.py walks img/ and writes images.json. The page fetches
that file at runtime. Everything the server does is serve static files.
Quick start
# 1. Add images (subfolders are fine)
cp ~/pictures/*.png img/
# 2. Build the manifest (and commit it)
./generate-manifest.py
# 3. Preview locally
python3 -m http.server 8080
# -> open http://localhost:8080
Re-run step 2 whenever you add, rename, or delete images.
Publishing with pushAll
pushAll does the whole publish flow in one command: regenerate the manifest,
commit the changes, and push to the remote.
./pushAll
To run it as pushAll from anywhere, either add this folder to your PATH, or
create a git alias once:
git config alias.pushAll '!./pushAll'
# then:
git pushAll
generate-manifest.py options
./generate-manifest.py # generate + commit
./generate-manifest.py --no-commit # generate only
./generate-manifest.py -m "Add logos" # custom commit message
Features
- Search — case-insensitive, multi-word with AND semantics. Every word must
appear somewhere in the filename; prefix and word-boundary matches rank first.
Matches are highlighted. Press
/to focus the search box,Escto clear. - Click to copy — clicking a card copies the image's absolute URL
(e.g.
https://your-host/img/logo.png). A toast confirms it. - Lazy loading — thumbnails load as you scroll, so large libraries stay fast.
- No dependencies — vanilla JS/CSS, no framework, no build tooling.
Deploying on nginx
Copy the whole project (including the generated images.json) into a web root
and point a server block at it. See nginx.conf.example.
# build the manifest locally, then upload everything
./generate-manifest.py --no-commit
rsync -av --delete ./ user@server:/var/www/image-library/
If you'd rather generate the manifest on the server, install Python 3 there and run the script after uploading images. Python is only needed for that step — nginx never runs it.
Clipboard over plain HTTP
navigator.clipboard only works in a secure context (HTTPS, or
localhost). The app detects this and falls back to a legacy copy method, which
works on plain HTTP in most browsers. For guaranteed behavior on a LAN host,
serve over HTTPS (e.g. a self-signed cert or a reverse proxy) — or just use
http://localhost while testing.
Alternative: nginx autoindex
If you don't want a build step at all, you can enable nginx's directory listing
and have the page parse it, but that requires autoindex on, produces fragile
HTML scraping, and loses the manifest metadata. The manifest approach is
recommended.