dawarich/app/javascript/maps_maplibre/components/popup_factory.js

115 lines
4.2 KiB
JavaScript
Raw Normal View History

0.36.2 (#2007) * fix: move foreman to global gems to fix startup crash (#1971) * Update exporting code to stream points data to file in batches to red… (#1980) * Update exporting code to stream points data to file in batches to reduce memory usage * Update changelog * Update changelog * Feature/maplibre frontend (#1953) * Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet * Implement phase 1 * Phases 1-3 + part of 4 * Fix e2e tests * Phase 6 * Implement fog of war * Phase 7 * Next step: fix specs, phase 7 done * Use our own map tiles * Extract v2 map logic to separate manager classes * Update settings panel on v2 map * Update v2 e2e tests structure * Reimplement location search in maps v2 * Update speed routes * Implement visits and places creation in v2 * Fix last failing test * Implement visits merging * Fix a routes e2e test and simplify the routes layer styling. * Extract js to modules from maps_v2_controller.js * Implement area creation * Fix spec problem * Fix some e2e tests * Implement live mode in v2 map * Update icons and panel * Extract some styles * Remove unused file * Start adding dark theme to popups on MapLibre maps * Make popups respect dark theme * Move v2 maps to maplibre namespace * Update v2 references to maplibre * Put place, area and visit info into side panel * Update API to use safe settings config method * Fix specs * Fix method name to config in SafeSettings and update usages accordingly * Add missing public files * Add handling for real time points * Fix remembering enabled/disabled layers of the v2 map * Fix lots of e2e tests * Add settings to select map version * Use maps/v2 as main path for MapLibre maps * Update routing * Update live mode * Update maplibre controller * Update changelog * Remove some console.log statements --------- Co-authored-by: Robin Tuszik <mail@robin.gg>
2025-12-06 14:54:49 -05:00
import { formatTimestamp } from '../utils/geojson_transformers'
import { getCurrentTheme, getThemeColors } from '../utils/popup_theme'
/**
* Factory for creating map popups
*/
export class PopupFactory {
/**
* Create popup for a point
* @param {Object} properties - Point properties
* @returns {string} HTML for popup
*/
static createPointPopup(properties) {
const { id, timestamp, altitude, battery, accuracy, velocity } = properties
// Get theme colors
const theme = getCurrentTheme()
const colors = getThemeColors(theme)
return `
<div class="point-popup" style="color: ${colors.textPrimary};">
<div class="popup-header" style="border-bottom: 1px solid ${colors.border};">
<strong>Point #${id}</strong>
</div>
<div class="popup-body">
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Time:</span>
<span class="value" style="color: ${colors.textPrimary};">${formatTimestamp(timestamp)}</span>
</div>
${altitude ? `
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Altitude:</span>
<span class="value" style="color: ${colors.textPrimary};">${Math.round(altitude)}m</span>
</div>
` : ''}
${battery ? `
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Battery:</span>
<span class="value" style="color: ${colors.textPrimary};">${battery}%</span>
</div>
` : ''}
${accuracy ? `
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Accuracy:</span>
<span class="value" style="color: ${colors.textPrimary};">${Math.round(accuracy)}m</span>
</div>
` : ''}
${velocity ? `
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Speed:</span>
<span class="value" style="color: ${colors.textPrimary};">${Math.round(velocity * 3.6)} km/h</span>
</div>
` : ''}
</div>
</div>
`
}
/**
* Create popup for a place
* @param {Object} properties - Place properties
* @returns {string} HTML for popup
*/
static createPlacePopup(properties) {
const { id, name, latitude, longitude, note, tags } = properties
// Get theme colors
const theme = getCurrentTheme()
const colors = getThemeColors(theme)
// Parse tags if they're stringified
let parsedTags = tags
if (typeof tags === 'string') {
try {
parsedTags = JSON.parse(tags)
} catch (e) {
parsedTags = []
}
}
// Format tags as badges
const tagsHtml = parsedTags && Array.isArray(parsedTags) && parsedTags.length > 0
? parsedTags.map(tag => `
<span class="badge badge-sm" style="background-color: ${tag.color}; color: white;">
${tag.icon} #${tag.name}
</span>
`).join(' ')
: `<span class="badge badge-sm badge-outline" style="border-color: ${colors.border}; color: ${colors.textMuted};">Untagged</span>`
return `
<div class="place-popup" style="color: ${colors.textPrimary};">
<div class="popup-header" style="border-bottom: 1px solid ${colors.border};">
<strong>${name || `Place #${id}`}</strong>
</div>
<div class="popup-body">
${note ? `
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Note:</span>
<span class="value" style="color: ${colors.textPrimary};">${note}</span>
</div>
` : ''}
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Tags:</span>
<div class="value">${tagsHtml}</div>
</div>
<div class="popup-row">
<span class="label" style="color: ${colors.textMuted};">Coordinates:</span>
<span class="value" style="color: ${colors.textPrimary};">${latitude.toFixed(5)}, ${longitude.toFixed(5)}</span>
</div>
</div>
</div>
`
}
}