sara.mesquita commited on
Commit
95aa944
Β·
1 Parent(s): 766f51d

Adjusts IA rules

Browse files
Files changed (3) hide show
  1. index.html +5 -4
  2. static/app.js +34 -5
  3. static/style.css +5 -0
index.html CHANGED
@@ -10,6 +10,7 @@
10
  <link rel="stylesheet" href="/static/style.css"/>
11
  <script src="https://cdn.jsdelivr.net/npm/lucide@0.454.0/dist/umd/lucide.min.js"></script>
12
  <script src="https://cdn.jsdelivr.net/npm/lottie-web@5.12.2/build/player/lottie.min.js"></script>
 
13
  </head>
14
  <body>
15
  <div id="desktop-layout">
@@ -196,7 +197,7 @@
196
  <div id="viewfinder">
197
  <div id="gps-pill">
198
  <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
199
- <span id="gps-text">Tap to detect location</span>
200
  </div>
201
  <img id="photo-preview" src="" alt="photo"/>
202
  <div id="camera-placeholder">
@@ -213,12 +214,12 @@
213
  <svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
214
  <textarea id="notes-input" rows="1" placeholder="Add a note (optional)"></textarea>
215
  </div>
216
- <button class="btn-secondary" id="gps-btn">
217
  <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
218
- Add Location
219
  </button>
220
  <button class="btn-primary" id="submit-reg-btn" disabled>
221
- <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
222
  Report Sighting
223
  </button>
224
  </div>
 
10
  <link rel="stylesheet" href="/static/style.css"/>
11
  <script src="https://cdn.jsdelivr.net/npm/lucide@0.454.0/dist/umd/lucide.min.js"></script>
12
  <script src="https://cdn.jsdelivr.net/npm/lottie-web@5.12.2/build/player/lottie.min.js"></script>
13
+ <script src="https://cdn.jsdelivr.net/npm/exifr@7.1.3/dist/full.umd.js"></script>
14
  </head>
15
  <body>
16
  <div id="desktop-layout">
 
197
  <div id="viewfinder">
198
  <div id="gps-pill">
199
  <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
200
+ <span id="gps-text">Add a photo to detect location</span>
201
  </div>
202
  <img id="photo-preview" src="" alt="photo"/>
203
  <div id="camera-placeholder">
 
214
  <svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
215
  <textarea id="notes-input" rows="1" placeholder="Add a note (optional)"></textarea>
216
  </div>
217
+ <button class="btn-locate" id="gps-btn" style="display:none">
218
  <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
219
+ Add Location Manually
220
  </button>
221
  <button class="btn-primary" id="submit-reg-btn" disabled>
222
+ <svg viewBox="0 0 24 24"><path d="M22 2L11 13"/><path d="M22 2l-7 20-4-9-9-4 20-7z"/></svg>
223
  Report Sighting
224
  </button>
225
  </div>
static/app.js CHANGED
@@ -506,9 +506,37 @@
506
  document.getElementById('photo-preview').style.display = 'block';
507
  document.getElementById('camera-placeholder').style.display = 'none';
508
  updateSubmitBtn();
 
509
  });
510
 
511
- document.getElementById('gps-pill').addEventListener('click', requestGPS);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  document.getElementById('gps-btn').addEventListener('click', requestGPS);
513
 
514
  function requestGPS() {
@@ -521,6 +549,7 @@
521
  gpsCoords = { lat: pos.coords.latitude, lng: pos.coords.longitude };
522
  txt.textContent = `${gpsCoords.lat.toFixed(4)}, ${gpsCoords.lng.toFixed(4)}`; txt.classList.add('located');
523
  btn.innerHTML = `<svg viewBox="0 0 24 24" style="width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> Location Added`;
 
524
  btn.classList.add('located'); btn.disabled = false; updateSubmitBtn();
525
  },
526
  err => {
@@ -786,11 +815,12 @@
786
  document.getElementById('photo-input').value = '';
787
  document.getElementById('notes-input').value = '';
788
  document.getElementById('animal-name-input').value = '';
789
- document.getElementById('gps-text').textContent = 'Tap to detect location';
790
  document.getElementById('gps-text').classList.remove('located');
791
  const btn = document.getElementById('gps-btn');
792
- btn.className = 'btn-secondary';
793
- btn.innerHTML = `<svg viewBox="0 0 24 24" style="width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> Add Location`;
 
794
  btn.disabled = false;
795
  document.querySelectorAll('.cond-chip').forEach(c => c.classList.remove('active'));
796
  updateSubmitBtn();
@@ -914,7 +944,6 @@
914
  confirm.classList.remove('open');
915
  setTimeout(() => confirm.classList.add('hidden'), 300);
916
  });
917
-
918
  // ── Photo lightbox ────────────────────────────────────────────────────────
919
  const lightbox = document.getElementById('photo-lightbox');
920
  const lightboxImg = document.getElementById('lightbox-img');
 
506
  document.getElementById('photo-preview').style.display = 'block';
507
  document.getElementById('camera-placeholder').style.display = 'none';
508
  updateSubmitBtn();
509
+ extractPhotoGPS(file);
510
  });
511
 
512
+ // Try to read GPS straight from the photo's EXIF metadata. If found, we use it
513
+ // automatically; if not, we reveal the manual "Add Location" button as a fallback.
514
+ async function extractPhotoGPS(file) {
515
+ const txt = document.getElementById('gps-text');
516
+ const locBtn = document.getElementById('gps-btn');
517
+ locBtn.style.display = 'none';
518
+ txt.textContent = 'Reading photo location…'; txt.classList.remove('located');
519
+ try {
520
+ const gps = (typeof exifr !== 'undefined') ? await exifr.gps(file) : null;
521
+ if (gps && Number.isFinite(gps.latitude) && Number.isFinite(gps.longitude)) {
522
+ gpsCoords = { lat: gps.latitude, lng: gps.longitude };
523
+ txt.textContent = `${gpsCoords.lat.toFixed(4)}, ${gpsCoords.lng.toFixed(4)} Β· from photo`;
524
+ txt.classList.add('located');
525
+ return;
526
+ }
527
+ } catch (err) {
528
+ console.warn('EXIF GPS read failed:', err);
529
+ }
530
+ // No usable metadata β€” fall back to manual detection.
531
+ gpsCoords = null;
532
+ txt.textContent = 'No location in photo β€” add it manually';
533
+ txt.classList.remove('located');
534
+ locBtn.style.display = 'flex';
535
+ }
536
+
537
+ document.getElementById('gps-pill').addEventListener('click', () => {
538
+ if (document.getElementById('gps-btn').style.display !== 'none') requestGPS();
539
+ });
540
  document.getElementById('gps-btn').addEventListener('click', requestGPS);
541
 
542
  function requestGPS() {
 
549
  gpsCoords = { lat: pos.coords.latitude, lng: pos.coords.longitude };
550
  txt.textContent = `${gpsCoords.lat.toFixed(4)}, ${gpsCoords.lng.toFixed(4)}`; txt.classList.add('located');
551
  btn.innerHTML = `<svg viewBox="0 0 24 24" style="width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> Location Added`;
552
+ txt.textContent = `${gpsCoords.lat.toFixed(4)}, ${gpsCoords.lng.toFixed(4)} Β· current location`;
553
  btn.classList.add('located'); btn.disabled = false; updateSubmitBtn();
554
  },
555
  err => {
 
815
  document.getElementById('photo-input').value = '';
816
  document.getElementById('notes-input').value = '';
817
  document.getElementById('animal-name-input').value = '';
818
+ document.getElementById('gps-text').textContent = 'Add a photo to detect location';
819
  document.getElementById('gps-text').classList.remove('located');
820
  const btn = document.getElementById('gps-btn');
821
+ btn.className = 'btn-locate';
822
+ btn.style.display = 'none';
823
+ btn.innerHTML = `<svg viewBox="0 0 24 24" style="width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> Add Location Manually`;
824
  btn.disabled = false;
825
  document.querySelectorAll('.cond-chip').forEach(c => c.classList.remove('active'));
826
  updateSubmitBtn();
 
944
  confirm.classList.remove('open');
945
  setTimeout(() => confirm.classList.add('hidden'), 300);
946
  });
 
947
  // ── Photo lightbox ────────────────────────────────────────────────────────
948
  const lightbox = document.getElementById('photo-lightbox');
949
  const lightboxImg = document.getElementById('lightbox-img');
static/style.css CHANGED
@@ -130,6 +130,11 @@
130
  .btn-secondary svg { width:18px; height:18px; fill:none; stroke:var(--green); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
131
  .btn-secondary.located { background:var(--green); color:#fff; border-color:var(--green); }
132
  .btn-secondary.located svg { stroke:#fff; }
 
 
 
 
 
133
  .btn-primary { width:100%; padding:15px; border-radius:12px; font-size:15px; font-weight:700; font-family:inherit; cursor:pointer; transition:all .15s; display:flex; align-items:center; justify-content:center; gap:8px; background:var(--green); color:#fff; border:none; }
134
  .btn-primary:hover { background:var(--green-dark); }
135
  .btn-primary:disabled { background:#ccc; cursor:not-allowed; }
 
130
  .btn-secondary svg { width:18px; height:18px; fill:none; stroke:var(--green); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
131
  .btn-secondary.located { background:var(--green); color:#fff; border-color:var(--green); }
132
  .btn-secondary.located svg { stroke:#fff; }
133
+ .btn-locate { width:100%; padding:14px; border-radius:12px; font-size:15px; font-weight:600; font-family:inherit; cursor:pointer; transition:all .15s; margin-bottom:10px; display:flex; align-items:center; justify-content:center; gap:8px; background:#FFF3E0; color:var(--orange); border:1.5px solid #FFD9A8; }
134
+ .btn-locate:hover { background:#FFE8C9; border-color:var(--orange); }
135
+ .btn-locate svg { width:18px; height:18px; fill:none; stroke:var(--orange); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
136
+ .btn-locate.located { background:var(--green); color:#fff; border-color:var(--green); }
137
+ .btn-locate.located svg { stroke:#fff; }
138
  .btn-primary { width:100%; padding:15px; border-radius:12px; font-size:15px; font-weight:700; font-family:inherit; cursor:pointer; transition:all .15s; display:flex; align-items:center; justify-content:center; gap:8px; background:var(--green); color:#fff; border:none; }
139
  .btn-primary:hover { background:var(--green-dark); }
140
  .btn-primary:disabled { background:#ccc; cursor:not-allowed; }