diff --git a/app/templates/capture.html b/app/templates/capture.html
index b5d17c5..a5b3b34 100644
--- a/app/templates/capture.html
+++ b/app/templates/capture.html
@@ -14,7 +14,11 @@
📷 Take Photo
-
+
+
+
+
+
+
@@ -98,6 +111,19 @@
cursor: not-allowed;
}
+.btn-upload {
+ font-size: 1.1rem;
+ padding: 1rem;
+ margin: 0.5rem 0;
+ background: var(--bg-secondary);
+ color: var(--text-primary);
+ border: 1px solid var(--bg-tertiary);
+}
+
+.btn-upload:disabled {
+ opacity: 0.6;
+}
+
.recent-photos {
margin-top: 3rem;
padding-bottom: 2rem;
@@ -364,6 +390,43 @@ cameraInput.addEventListener('change', async function(e) {
e.target.value = '';
});
+// ---- Upload from library ----
+const uploadBtn = document.getElementById('upload-btn');
+const uploadInput = document.getElementById('upload-input');
+
+uploadBtn.addEventListener('click', function() {
+ uploadInput.click();
+});
+
+uploadInput.addEventListener('change', async function(e) {
+ const files = Array.from(e.target.files);
+ if (files.length === 0) return;
+
+ uploadBtn.disabled = true;
+ uploadBtn.textContent = '⏳ Processing 0/' + files.length + '...';
+
+ let saved = 0;
+ for (const file of files) {
+ try {
+ const jpegBlob = await convertToJPEG(file);
+ await savePhoto(jpegBlob);
+ saved++;
+ uploadBtn.textContent = '⏳ Processing ' + saved + '/' + files.length + '...';
+ } catch (err) {
+ console.error('Failed to process file:', file.name, err);
+ }
+ }
+
+ uploadBtn.textContent = '✓ ' + saved + ' photo' + (saved !== 1 ? 's' : '') + ' added';
+ loadRecentPhotos();
+ setTimeout(() => {
+ uploadBtn.disabled = false;
+ uploadBtn.textContent = '🖼️ Upload from Library';
+ }, 1500);
+
+ e.target.value = '';
+});
+
// ---- Live camera viewfinder ----
async function openCamera() {
sessionCount = 0;