Spaces:
Runtime error
Runtime error
sara.mesquita commited on
Commit Β·
5e6a147
1
Parent(s): f61af68
feat: 3-dot menu with download option on gallery photos
Browse files- index.html +56 -2
- static/style.css +9 -0
index.html
CHANGED
|
@@ -367,6 +367,14 @@
|
|
| 367 |
</div>
|
| 368 |
</div>
|
| 369 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 370 |
<!-- ββ BOTTOM NAV ββ -->
|
| 371 |
<nav id="bottom-nav">
|
| 372 |
<button class="nav-btn active" data-screen="map"><span class="nav-icon"><i data-lucide="map"></i></span><span>Map</span></button>
|
|
@@ -723,8 +731,17 @@
|
|
| 723 |
const locStr = (s.latitude && s.longitude) ? `${s.latitude.toFixed(3)}, ${s.longitude.toFixed(3)}` : 'Location not recorded';
|
| 724 |
return `
|
| 725 |
<div class="gallery-card">
|
| 726 |
-
<
|
| 727 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
<div class="gallery-card-info">
|
| 729 |
<div class="gallery-card-date">
|
| 730 |
<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
|
@@ -1060,6 +1077,43 @@
|
|
| 1060 |
updateSubmitBtn();
|
| 1061 |
}
|
| 1062 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1063 |
// ββ HELP SHEET ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1064 |
let helpAnimal = null;
|
| 1065 |
|
|
|
|
| 367 |
</div>
|
| 368 |
</div>
|
| 369 |
|
| 370 |
+
<!-- ββ PHOTO CONTEXT MENU ββ -->
|
| 371 |
+
<div id="photo-menu" class="photo-menu hidden">
|
| 372 |
+
<button id="photo-menu-download">
|
| 373 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
| 374 |
+
Download photo
|
| 375 |
+
</button>
|
| 376 |
+
</div>
|
| 377 |
+
|
| 378 |
<!-- ββ BOTTOM NAV ββ -->
|
| 379 |
<nav id="bottom-nav">
|
| 380 |
<button class="nav-btn active" data-screen="map"><span class="nav-icon"><i data-lucide="map"></i></span><span>Map</span></button>
|
|
|
|
| 731 |
const locStr = (s.latitude && s.longitude) ? `${s.latitude.toFixed(3)}, ${s.longitude.toFixed(3)}` : 'Location not recorded';
|
| 732 |
return `
|
| 733 |
<div class="gallery-card">
|
| 734 |
+
<div class="gallery-card-img-wrap">
|
| 735 |
+
<img class="gallery-card-img" src="${s.photo_url}" alt="sighting"
|
| 736 |
+
onerror="this.style.background='#eee';this.src=''"/>
|
| 737 |
+
<button class="gallery-card-menu-btn" data-url="${s.photo_url}" data-date="${dateStr}" aria-label="Options">
|
| 738 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
| 739 |
+
<circle cx="12" cy="5" r="1.2" fill="currentColor" stroke="none"/>
|
| 740 |
+
<circle cx="12" cy="12" r="1.2" fill="currentColor" stroke="none"/>
|
| 741 |
+
<circle cx="12" cy="19" r="1.2" fill="currentColor" stroke="none"/>
|
| 742 |
+
</svg>
|
| 743 |
+
</button>
|
| 744 |
+
</div>
|
| 745 |
<div class="gallery-card-info">
|
| 746 |
<div class="gallery-card-date">
|
| 747 |
<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
|
|
|
| 1077 |
updateSubmitBtn();
|
| 1078 |
}
|
| 1079 |
|
| 1080 |
+
// ββ PHOTO CONTEXT MENU ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1081 |
+
let photoMenuUrl = null;
|
| 1082 |
+
const photoMenu = document.getElementById('photo-menu');
|
| 1083 |
+
|
| 1084 |
+
function openPhotoMenu(btn) {
|
| 1085 |
+
photoMenuUrl = btn.dataset.url;
|
| 1086 |
+
const rect = btn.getBoundingClientRect();
|
| 1087 |
+
const appRect = document.getElementById('app').getBoundingClientRect();
|
| 1088 |
+
photoMenu.classList.remove('hidden');
|
| 1089 |
+
// Position below the button, clamped inside app
|
| 1090 |
+
let top = rect.bottom - appRect.top + 4;
|
| 1091 |
+
let left = rect.right - appRect.left - photoMenu.offsetWidth;
|
| 1092 |
+
if (left < 8) left = 8;
|
| 1093 |
+
photoMenu.style.top = top + 'px';
|
| 1094 |
+
photoMenu.style.left = left + 'px';
|
| 1095 |
+
}
|
| 1096 |
+
|
| 1097 |
+
function closePhotoMenu() { photoMenu.classList.add('hidden'); photoMenuUrl = null; }
|
| 1098 |
+
|
| 1099 |
+
document.getElementById('app').addEventListener('click', e => {
|
| 1100 |
+
const btn = e.target.closest('.gallery-card-menu-btn');
|
| 1101 |
+
if (btn) { e.stopPropagation(); openPhotoMenu(btn); return; }
|
| 1102 |
+
if (!photoMenu.contains(e.target)) closePhotoMenu();
|
| 1103 |
+
});
|
| 1104 |
+
|
| 1105 |
+
document.getElementById('photo-menu-download').addEventListener('click', () => {
|
| 1106 |
+
if (!photoMenuUrl) return;
|
| 1107 |
+
const a = document.createElement('a');
|
| 1108 |
+
a.href = photoMenuUrl;
|
| 1109 |
+
a.download = 'pawmap-photo.jpg';
|
| 1110 |
+
a.target = '_blank';
|
| 1111 |
+
document.body.appendChild(a);
|
| 1112 |
+
a.click();
|
| 1113 |
+
document.body.removeChild(a);
|
| 1114 |
+
closePhotoMenu();
|
| 1115 |
+
});
|
| 1116 |
+
|
| 1117 |
// ββ HELP SHEET ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1118 |
let helpAnimal = null;
|
| 1119 |
|
static/style.css
CHANGED
|
@@ -304,6 +304,15 @@
|
|
| 304 |
/* Adopt button */
|
| 305 |
.btn-adopt svg { width: 18px; height: 18px; stroke: #fff; fill: #fff; }
|
| 306 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
/* ββ Helped banner & events ββ */
|
| 308 |
#profile-helped-banner { display:flex; align-items:center; gap:8px; background:var(--green-soft); border:1px solid var(--green-pale); border-radius:10px; padding:10px 14px; margin:10px 0 4px; font-size:13px; color:var(--green-dark); font-weight:500; }
|
| 309 |
#profile-helped-banner i { flex-shrink:0; }
|
|
|
|
| 304 |
/* Adopt button */
|
| 305 |
.btn-adopt svg { width: 18px; height: 18px; stroke: #fff; fill: #fff; }
|
| 306 |
|
| 307 |
+
/* ββ Gallery card menu ββ */
|
| 308 |
+
.gallery-card-img-wrap { position:relative; }
|
| 309 |
+
.gallery-card-menu-btn { position:absolute; top:6px; right:6px; width:28px; height:28px; background:rgba(0,0,0,.45); border:none; border-radius:50%; display:flex; align-items:center; justify-content:center; cursor:pointer; color:#fff; padding:0; }
|
| 310 |
+
.gallery-card-menu-btn svg { width:14px; height:14px; }
|
| 311 |
+
.photo-menu { position:absolute; z-index:800; background:#fff; border-radius:10px; box-shadow:0 4px 20px rgba(0,0,0,.15); overflow:hidden; min-width:160px; }
|
| 312 |
+
#photo-menu-download { display:flex; align-items:center; gap:10px; padding:13px 16px; font-size:14px; font-weight:500; color:var(--text); background:none; border:none; cursor:pointer; width:100%; }
|
| 313 |
+
#photo-menu-download:active { background:var(--bg); }
|
| 314 |
+
#photo-menu-download svg { width:16px; height:16px; flex-shrink:0; color:var(--text-muted); }
|
| 315 |
+
|
| 316 |
/* ββ Helped banner & events ββ */
|
| 317 |
#profile-helped-banner { display:flex; align-items:center; gap:8px; background:var(--green-soft); border:1px solid var(--green-pale); border-radius:10px; padding:10px 14px; margin:10px 0 4px; font-size:13px; color:var(--green-dark); font-weight:500; }
|
| 318 |
#profile-helped-banner i { flex-shrink:0; }
|