@@ -26,6 +26,7 @@ interface MapPoint {
2626 activityId : string
2727 location : string
2828 date : string
29+ score : number
2930 url : string | null
3031 color : string
3132 imagePath : string | null
@@ -105,6 +106,7 @@ function toMapPoints(
105106 activityId : s . activityId ,
106107 location : formatLocation ( s ) ?? '' ,
107108 date : s . timestamp . toISOString ( ) . split ( 'T' ) [ 0 ] ?? '' ,
109+ score : s . score ,
108110 url : extractUrl ( s . originalMessage ) ,
109111 color,
110112 imagePath : config . imagePaths ?. get ( s . activityId ) ?? null ,
@@ -155,40 +157,6 @@ function generateMarkersJS(points: readonly MapPoint[]): string {
155157 . join ( '\n' )
156158}
157159
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-
192160/**
193161 * Generate legend HTML.
194162 */
@@ -369,8 +337,10 @@ export function exportToMapHTML(
369337 .modal-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:2000; justify-content:center; align-items:center; }
370338 .modal-overlay.open { display:flex; }
371339 .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; }
340+ .modal-header { padding:20px 24px; border-bottom:1px solid #e5e7eb; display:flex; justify-content:space-between; align-items:center; gap:16px; }
341+ .modal-header h2 { margin:0; font-size:20px; font-weight:600; flex:1; }
342+ .sort-control { display:flex; align-items:center; gap:8px; font-size:14px; color:#6b7280; }
343+ .sort-control select { padding:6px 10px; border:1px solid #d1d5db; border-radius:6px; font-size:14px; background:#fff; cursor:pointer; }
374344 .modal-close { background:none; border:none; font-size:24px; cursor:pointer; color:#6b7280; padding:4px 8px; }
375345 .modal-close:hover { color:#111; }
376346 .modal-body { padding:16px 24px; overflow-y:auto; flex:1; }
@@ -409,11 +379,17 @@ export function exportToMapHTML(
409379 <div class="modal" onclick="event.stopPropagation()">
410380 <div class="modal-header">
411381 <h2>Activity List</h2>
382+ <div class="sort-control">
383+ <label for="sortSelect">Sort by:</label>
384+ <select id="sortSelect" onchange="sortActivities(this.value)">
385+ <option value="score">Most Interesting</option>
386+ <option value="oldest">Oldest</option>
387+ <option value="newest">Newest</option>
388+ </select>
389+ </div>
412390 <button class="modal-close" onclick="closeModal()">×</button>
413391 </div>
414- <div class="modal-body">
415- ${ generateActivityListHTML ( points ) }
416- </div>
392+ <div class="modal-body" id="activityListBody"></div>
417393 </div>
418394 </div>
419395
@@ -445,10 +421,44 @@ export function exportToMapHTML(
445421 map.fitBounds(markersLayer.getBounds(), { padding: [50, 50] });
446422 }
447423
424+ // Activity data for sorting
425+ var activities = ${ JSON . stringify (
426+ points . map ( ( p ) => ( {
427+ id : p . activityId ,
428+ activity : p . activity ,
429+ sender : p . sender . split ( ' ' ) [ 0 ] ?? p . sender ,
430+ location : p . location ,
431+ date : p . date ,
432+ score : p . score ,
433+ imagePath : p . imagePath ,
434+ placeId : p . placeId ,
435+ url : p . url
436+ } ) )
437+ ) } ;
438+
439+ function renderActivityList(sorted) {
440+ var html = sorted.map(function(a) {
441+ var mapsUrl = a.placeId ? 'https://www.google.com/maps/search/?api=1&query=' + encodeURIComponent(a.activity) + '&query_place_id=' + a.placeId : null;
442+ var thumb = a.imagePath ? '<img src="' + a.imagePath + '" class="activity-thumb" alt="" />' : '<div class="activity-thumb-placeholder"></div>';
443+ var links = (mapsUrl ? '<a href="' + mapsUrl + '" target="_blank">Google Maps</a>' : '') + (a.url ? '<a href="' + a.url + '" target="_blank">Source</a>' : '');
444+ return '<div class="activity-row">' + thumb + '<div class="activity-content"><div class="activity-title">' + a.activity + '</div><div class="activity-meta">' + (a.location ? '<span class="activity-location">' + a.location + '</span> · ' : '') + a.sender + ' · ' + a.date + '</div><div class="activity-links">' + links + '</div></div></div>';
445+ }).join('');
446+ document.getElementById('activityListBody').innerHTML = html;
447+ }
448+
449+ function sortActivities(sortBy) {
450+ var sorted = activities.slice();
451+ if (sortBy === 'score') sorted.sort(function(a, b) { return b.score - a.score; });
452+ else if (sortBy === 'oldest') sorted.sort(function(a, b) { return a.date.localeCompare(b.date); });
453+ else if (sortBy === 'newest') sorted.sort(function(a, b) { return b.date.localeCompare(a.date); });
454+ renderActivityList(sorted);
455+ }
456+
448457 // Modal functions
449458 function openModal() {
450459 document.getElementById('activityModal').classList.add('open');
451460 document.body.style.overflow = 'hidden';
461+ sortActivities(document.getElementById('sortSelect').value);
452462 }
453463 function closeModal(e) {
454464 if (!e || e.target === e.currentTarget) {
0 commit comments