# 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 ```sh # 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. ```sh ./pushAll ``` To run it as `pushAll` from anywhere, either add this folder to your `PATH`, or create a git alias once: ```sh git config alias.pushAll '!./pushAll' # then: git pushAll ``` ### `generate-manifest.py` options ```sh ./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, `Esc` to 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`](nginx.conf.example). ```sh # 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.