@@ -155,6 +155,40 @@ function generateMarkersJS(points: readonly MapPoint[]): string {
155155 . join ( '\n' )
156156}
157157
158+ /**
159+ * Generate activity list HTML for modal.
160+ */
161+ function generateActivityListHTML ( points : readonly MapPoint [ ] ) : string {
162+ return points
163+ . map ( ( p ) => {
164+ const senderName = p . sender . split ( ' ' ) [ 0 ] ?? p . sender
165+ const mapsUrl = p . placeId
166+ ? `https://www.google.com/maps/search/?api=1&query=${ encodeURIComponent ( p . activity ) } &query_place_id=${ p . placeId } `
167+ : null
168+ const thumbnail = p . imagePath
169+ ? `<img src="${ escapeJS ( p . imagePath ) } " class="activity-thumb" alt="" />`
170+ : '<div class="activity-thumb-placeholder"></div>'
171+
172+ return `
173+ <div class="activity-row">
174+ ${ thumbnail }
175+ <div class="activity-content">
176+ <div class="activity-title">${ escapeJS ( p . activity ) } </div>
177+ <div class="activity-meta">
178+ ${ p . location ? `<span class="activity-location">${ escapeJS ( p . location ) } </span> · ` : '' }
179+ ${ escapeJS ( senderName ) } · ${ p . date }
180+ </div>
181+ <div class="activity-links">
182+ ${ mapsUrl ? `<a href="${ escapeJS ( mapsUrl ) } " target="_blank">Google Maps</a>` : '' }
183+ ${ p . url ? `<a href="${ escapeJS ( p . url ) } " target="_blank">Source</a>` : '' }
184+ </div>
185+ </div>
186+ </div>
187+ `
188+ } )
189+ . join ( '' )
190+ }
191+
158192/**
159193 * Generate legend HTML.
160194 */
@@ -330,6 +364,28 @@ export function exportToMapHTML(
330364 border: 2px solid white;
331365 box-shadow: 0 1px 3px rgba(0,0,0,0.3);
332366 }
367+ .view-list-link { display:inline-block; margin-top:10px; color:#2563eb; cursor:pointer; font-weight:500; }
368+ .view-list-link:hover { text-decoration:underline; }
369+ .modal-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:2000; justify-content:center; align-items:center; }
370+ .modal-overlay.open { display:flex; }
371+ .modal { background:#fff; border-radius:12px; width:90%; max-width:700px; max-height:85vh; display:flex; flex-direction:column; box-shadow:0 20px 50px rgba(0,0,0,0.3); }
372+ .modal-header { padding:20px 24px; border-bottom:1px solid #e5e7eb; display:flex; justify-content:space-between; align-items:center; }
373+ .modal-header h2 { margin:0; font-size:20px; font-weight:600; }
374+ .modal-close { background:none; border:none; font-size:24px; cursor:pointer; color:#6b7280; padding:4px 8px; }
375+ .modal-close:hover { color:#111; }
376+ .modal-body { padding:16px 24px; overflow-y:auto; flex:1; }
377+ .activity-row { display:flex; gap:16px; padding:12px 0; border-bottom:1px solid #f3f4f6; }
378+ .activity-row:last-child { border-bottom:none; }
379+ .activity-thumb, .activity-thumb-placeholder { width:64px; height:64px; border-radius:8px; flex-shrink:0; }
380+ .activity-thumb { object-fit:cover; }
381+ .activity-thumb-placeholder { background:#f3f4f6; }
382+ .activity-content { flex:1; min-width:0; }
383+ .activity-title { font-weight:500; color:#111; margin-bottom:4px; }
384+ .activity-meta { font-size:13px; color:#6b7280; margin-bottom:6px; }
385+ .activity-location { color:#2563eb; }
386+ .activity-links { display:flex; gap:12px; font-size:13px; }
387+ .activity-links a { color:#2563eb; text-decoration:none; }
388+ .activity-links a:hover { text-decoration:underline; }
333389 </style>
334390</head>
335391<body>
@@ -342,12 +398,25 @@ export function exportToMapHTML(
342398 Click markers to see details.<br>
343399 Zoom in to see individual pins.
344400 </p>
401+ <a class="view-list-link" onclick="openModal()">View Activity List →</a>
345402 </div>
346403
347404 <div class="legend">
348405 ${ legendHTML }
349406 </div>
350407
408+ <div class="modal-overlay" id="activityModal" onclick="closeModal(event)">
409+ <div class="modal" onclick="event.stopPropagation()">
410+ <div class="modal-header">
411+ <h2>Activity List</h2>
412+ <button class="modal-close" onclick="closeModal()">×</button>
413+ </div>
414+ <div class="modal-body">
415+ ${ generateActivityListHTML ( points ) }
416+ </div>
417+ </div>
418+ </div>
419+
351420 <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
352421 <script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
353422 <script>
@@ -375,6 +444,21 @@ export function exportToMapHTML(
375444 if (markersLayer.getLayers().length > 0) {
376445 map.fitBounds(markersLayer.getBounds(), { padding: [50, 50] });
377446 }
447+
448+ // Modal functions
449+ function openModal() {
450+ document.getElementById('activityModal').classList.add('open');
451+ document.body.style.overflow = 'hidden';
452+ }
453+ function closeModal(e) {
454+ if (!e || e.target === e.currentTarget) {
455+ document.getElementById('activityModal').classList.remove('open');
456+ document.body.style.overflow = '';
457+ }
458+ }
459+ document.addEventListener('keydown', function(e) {
460+ if (e.key === 'Escape') closeModal();
461+ });
378462 </script>
379463</body>
380464</html>`
0 commit comments