106 lines
3.5 KiB
Markdown
106 lines
3.5 KiB
Markdown
# 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.
|