aboutsummaryrefslogtreecommitdiff
path: root/templates
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-02-13 08:45:49 +0100
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-02-13 08:45:49 +0100
commit17be2fcb106ddc9c36628e9f5dece28369affc30 (patch)
tree4f3cb1d2fade5467f6c79a9a1abe1da0852a61d0 /templates
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')
-rw-r--r--templates/gallery.html98
-rw-r--r--templates/index.html21
-rw-r--r--templates/login.html19
3 files changed, 138 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>
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..357a8a8
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Photo Gallery</title>
+<style>{{.CSS}}</style>
+</head>
+<body>
+<div class="container">
+<h1>📷 Photo Gallery</h1>
+{{if .Names}}
+<ul class="gallery-list">
+{{range .Names}}<li><a href="/g/{{.}}">{{.}}</a></li>{{end}}
+</ul>
+{{else}}
+<p>No galleries yet.</p>
+{{end}}
+</div>
+</body>
+</html>
diff --git a/templates/login.html b/templates/login.html
new file mode 100644
index 0000000..7c06fbc
--- /dev/null
+++ b/templates/login.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>{{.Name}} — Login</title>
+<style>{{.CSS}}</style>
+</head>
+<body>
+<div class="container">
+<h1>🔒 {{.Name}}</h1>
+{{if .Error}}<p class="error">{{.Error}}</p>{{end}}
+<form method="POST" action="/g/{{.Name}}">
+<input type="password" name="password" placeholder="Password" autofocus required>
+<button type="submit">Enter</button>
+</form>
+</div>
+</body>
+</html>