174 lines
4.7 KiB
JavaScript
174 lines
4.7 KiB
JavaScript
import maplibregl from "maplibre-gl";
|
||
|
||
/**
|
||
* Supprime tous les marqueurs
|
||
*/
|
||
export function clearAllMarkers(markersRef, expandedElRef) {
|
||
if (markersRef.current) {
|
||
for (const m of markersRef.current) {
|
||
try {
|
||
m.marker.remove();
|
||
} catch {
|
||
// ignore
|
||
}
|
||
}
|
||
}
|
||
markersRef.current = [];
|
||
if (expandedElRef) {
|
||
expandedElRef.current = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crée un marqueur pour un post :
|
||
* - état compact : petite bulle + pointe
|
||
* - état étendu : gros post (carte) comme sur ton dessin
|
||
*/
|
||
export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||
const map = mapRef.current;
|
||
if (!map) return;
|
||
|
||
// --- coordonnées ---
|
||
const lat =
|
||
typeof post.lat === "number"
|
||
? post.lat
|
||
: typeof post.Lat === "number"
|
||
? post.Lat
|
||
: typeof post.latitude === "number"
|
||
? post.latitude
|
||
: null;
|
||
|
||
const lon =
|
||
typeof post.lon === "number"
|
||
? post.lon
|
||
: typeof post.Lon === "number"
|
||
? post.Lon
|
||
: typeof post.longitude === "number"
|
||
? post.longitude
|
||
: null;
|
||
|
||
if (lat == null || lon == null) {
|
||
console.warn("post sans coordonnée:", post);
|
||
return;
|
||
}
|
||
|
||
const title = (post.title || post.Title || "").trim() || "Untitled";
|
||
const body =
|
||
(post.snippet || post.Snippet || "").trim() ||
|
||
(post.body || post.Body || "").trim() ||
|
||
title;
|
||
|
||
const author = (post.author || post.Author || "").trim() || "unknown";
|
||
const created =
|
||
(post.created_at || post.CreatedAt || "").toString().slice(0, 19);
|
||
const category = (post.category || post.Category || "").toUpperCase() || "";
|
||
const subCat = (post.sub_category || post.SubCategory || "").toString();
|
||
|
||
const root = document.createElement("div");
|
||
root.className = "post-pin post-pin--compact";
|
||
|
||
function renderCompact() {
|
||
root.className = "post-pin post-pin--compact";
|
||
root.innerHTML = `
|
||
<div class="post-pin-bubble">
|
||
<div class="post-pin-dot"></div>
|
||
<div class="post-pin-text">${escapeHtml(title)}</div>
|
||
</div>
|
||
<div class="post-pin-pointer-small"></div>
|
||
`;
|
||
}
|
||
|
||
function renderExpanded() {
|
||
root.className = "post-pin post-pin--expanded";
|
||
root.innerHTML = `
|
||
<div class="post-card">
|
||
<div class="post-card-header">
|
||
<div class="post-card-cat">
|
||
${escapeHtml(category || "NEWS")}
|
||
${subCat ? "· " + escapeHtml(subCat) : ""}
|
||
</div>
|
||
<div class="post-card-time">
|
||
${escapeHtml(created || "")}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="post-card-main">
|
||
<div class="post-card-media">
|
||
<div class="post-card-media-label">
|
||
Image / Vidéo
|
||
</div>
|
||
</div>
|
||
|
||
<div class="post-card-info">
|
||
<div class="post-card-title">
|
||
${escapeHtml(title)}
|
||
</div>
|
||
<div class="post-card-meta">
|
||
by ${escapeHtml(author)} · lat ${lat.toFixed(3)} · lon ${lon.toFixed(3)}
|
||
</div>
|
||
<div class="post-card-body">
|
||
${escapeHtml(body)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="post-card-footer">
|
||
<button class="post-card-btn">Live</button>
|
||
<button class="post-card-btn">Like</button>
|
||
<button class="post-card-btn">Share</button>
|
||
<button class="post-card-btn">Fix</button>
|
||
</div>
|
||
|
||
<div class="post-card-comments">
|
||
Live chat / comments (placeholder)
|
||
</div>
|
||
</div>
|
||
<div class="post-card-pointer"></div>
|
||
`;
|
||
}
|
||
|
||
// état initial : compact
|
||
renderCompact();
|
||
|
||
const marker = new maplibregl.Marker({
|
||
element: root,
|
||
anchor: "bottom", // la pointe touche exactement la coordonnée
|
||
})
|
||
.setLngLat([lon, lat])
|
||
.addTo(map);
|
||
|
||
markersRef.current.push({ id: post.id, marker, el: root, post });
|
||
|
||
root.addEventListener("click", (ev) => {
|
||
ev.stopPropagation();
|
||
|
||
// Fermer l'ancien gros post
|
||
if (expandedElRef.current && expandedElRef.current !== root) {
|
||
expandedElRef.current.__renderCompact &&
|
||
expandedElRef.current.__renderCompact();
|
||
expandedElRef.current = null;
|
||
}
|
||
|
||
// Toggle pour ce post
|
||
const isExpanded = root.classList.contains("post-pin--expanded");
|
||
if (isExpanded) {
|
||
renderCompact();
|
||
expandedElRef.current = null;
|
||
} else {
|
||
renderExpanded();
|
||
expandedElRef.current = root;
|
||
// on garde les fonctions pour pouvoir re-compactifier
|
||
root.__renderCompact = renderCompact;
|
||
}
|
||
});
|
||
}
|
||
|
||
/* petite fonction pour éviter d’injecter du HTML sale */
|
||
function escapeHtml(str) {
|
||
return String(str)
|
||
.replace(/&/g, "&")
|
||
.replace(/</g, "<")
|
||
.replace(/>/g, ">")
|
||
.replace(/"/g, """);
|
||
}
|