diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-02-13 08:45:49 +0100 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-02-13 08:45:49 +0100 |
| commit | 17be2fcb106ddc9c36628e9f5dece28369affc30 (patch) | |
| tree | 4f3cb1d2fade5467f6c79a9a1abe1da0852a61d0 /templates/gallery.html | |
Extract gallery app from perso/vps into standalone project
Extracted all gallery-related files from ~/perso/vps:
- gallery.go, gallery_test.go (Go source + tests)
- templates/ (index, login, gallery HTML)
- static/style.css
- go.mod/go.sum (renamed module to github.com/kagamino/kagapics)
- Caddyfile.example (gallery-only Caddy config)
- DESIGN.md (from galery.md)
Diffstat (limited to 'templates/gallery.html')
| -rw-r--r-- | templates/gallery.html | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/templates/gallery.html b/templates/gallery.html new file mode 100644 index 0000000..4991a11 --- /dev/null +++ b/templates/gallery.html @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>{{.Name}}</title> +<style>{{.CSS}}</style> +</head> +<body> +<div class="container"> +<h1>📷 {{.Name}}</h1> + +<div class="actions"> +<a href="/" class="btn btn-back">← Back</a> +<a href="/g/{{.Name}}/zip" class="btn">⬇ Download all as ZIP</a> +</div> + +<!-- Upload --> +<div class="upload-area" id="upload-area"> +<p>Drag & drop photos here, or <label for="file-input" class="link">browse</label></p> +<input type="file" id="file-input" multiple accept="image/*" hidden> +<div id="upload-progress"></div> +</div> + +<!-- Gallery grid --> +<div class="grid"> +{{range .Photos}} +<div class="grid-item" onclick="openLightbox('/g/{{$.Name}}/photo/{{.}}')"> +<img src="/g/{{$.Name}}/{{$.ThumbPrefix}}/{{.}}" alt="{{.}}" loading="lazy"> +</div> +{{end}} +</div> +{{if not .Photos}}<p class="empty">No photos yet. Upload some!</p>{{end}} +</div> + +<!-- Lightbox --> +<div id="lightbox" class="lightbox" onclick="closeLightbox()"> +<img id="lightbox-img" src=""> +<a id="lightbox-download" class="lightbox-download" download onclick="event.stopPropagation()">⬇</a> +</div> + +<script> +const galleryName = {{.Name}}; +const uploadArea = document.getElementById('upload-area'); +const fileInput = document.getElementById('file-input'); +const progress = document.getElementById('upload-progress'); + +uploadArea.addEventListener('dragover', e => { e.preventDefault(); uploadArea.classList.add('dragover'); }); +uploadArea.addEventListener('dragleave', () => uploadArea.classList.remove('dragover')); +uploadArea.addEventListener('drop', e => { + e.preventDefault(); + uploadArea.classList.remove('dragover'); + uploadFiles(e.dataTransfer.files); +}); +fileInput.addEventListener('change', () => uploadFiles(fileInput.files)); + +function uploadFiles(files) { + if (!files.length) return; + const fd = new FormData(); + for (const f of files) fd.append('photos', f); + + progress.textContent = 'Uploading ' + files.length + ' file(s)…'; + + const xhr = new XMLHttpRequest(); + xhr.open('POST', '/g/' + galleryName + '/upload'); + + xhr.upload.onprogress = e => { + if (e.lengthComputable) { + const pct = Math.round(e.loaded / e.total * 100); + progress.textContent = 'Uploading… ' + pct + '%'; + } + }; + xhr.onload = () => { + if (xhr.status === 200) { + const resp = JSON.parse(xhr.responseText); + progress.textContent = resp.uploaded + ' file(s) uploaded ✓'; + setTimeout(() => location.reload(), 800); + } else { + progress.textContent = 'Upload failed: ' + xhr.statusText; + } + }; + xhr.onerror = () => { progress.textContent = 'Upload failed (network error)'; }; + xhr.send(fd); +} + +function openLightbox(src) { + document.getElementById('lightbox-img').src = src; + document.getElementById('lightbox-download').href = src; + document.getElementById('lightbox').classList.add('active'); +} +function closeLightbox() { + document.getElementById('lightbox').classList.remove('active'); + document.getElementById('lightbox-img').src = ''; +} +document.addEventListener('keydown', e => { if (e.key === 'Escape') closeLightbox(); }); +</script> +</body> +</html> |
