From b1e9e4379b351c26acf69c2395b0e46dd35615c0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 9 Dec 2025 06:24:47 +0000 Subject: [PATCH] Auto deploy: 2025-12-09 06:24:43 --- src/components/Map/markerManager.js | 131 ++++++++++++++++++-------- src/styles/mapMarkers.css | 138 ++++++++++++++++++++++++---- 2 files changed, 214 insertions(+), 55 deletions(-) diff --git a/src/components/Map/markerManager.js b/src/components/Map/markerManager.js index 92f7100..f632aec 100644 --- a/src/components/Map/markerManager.js +++ b/src/components/Map/markerManager.js @@ -1,13 +1,13 @@ import maplibregl from "maplibre-gl"; /** - * Retire tous les marqueurs existants + * Supprime tous les marqueurs */ export function clearAllMarkers(markersRef, expandedElRef) { if (markersRef.current) { - for (const item of markersRef.current) { + for (const m of markersRef.current) { try { - item.marker.remove(); + m.marker.remove(); } catch { // ignore } @@ -20,14 +20,15 @@ export function clearAllMarkers(markersRef, expandedElRef) { } /** - * Crée un marqueur "pin" avec bulle + pointe. - * Position verrouillée sur [lon, lat] via MapLibre (anchor: 'bottom'). + * 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 --- + // --- coordonnées --- const lat = typeof post.lat === "number" ? post.lat @@ -52,63 +53,121 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) { } const title = (post.title || post.Title || "").trim() || "Untitled"; - const snippet = + const body = (post.snippet || post.Snippet || "").trim() || (post.body || post.Body || "").trim() || title; - // --- DOM du pin --- + 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"; + root.className = "post-pin post-pin--compact"; - const bubble = document.createElement("div"); - bubble.className = "post-pin-bubble"; + function renderCompact() { + root.className = "post-pin post-pin--compact"; + root.innerHTML = ` +
+
+
${escapeHtml(title)}
+
+
+ `; + } - const dot = document.createElement("div"); - dot.className = "post-pin-dot"; + function renderExpanded() { + root.className = "post-pin post-pin--expanded"; + root.innerHTML = ` +
+
+
+ ${escapeHtml(category || "NEWS")} + ${subCat ? "· " + escapeHtml(subCat) : ""} +
+
+ ${escapeHtml(created || "")} +
+
- const text = document.createElement("div"); - text.className = "post-pin-text"; - text.textContent = title; +
+
+
+ Image / Vidéo +
+
- bubble.appendChild(dot); - bubble.appendChild(text); +
+
+ ${escapeHtml(title)} +
+
+ by ${escapeHtml(author)} · lat ${lat.toFixed(3)} · lon ${lon.toFixed(3)} +
+
+ ${escapeHtml(body)} +
+
+
- const pointer = document.createElement("div"); - pointer.className = "post-pin-pointer"; +
+ + + + +
- root.appendChild(bubble); - root.appendChild(pointer); +
+ Live chat / comments (placeholder) +
+
+
+ `; + } + + // état initial : compact + renderCompact(); - // --- Marker MapLibre : position = [lon, lat], ancré en bas --- const marker = new maplibregl.Marker({ element: root, - anchor: "bottom", // la pointe touche la coordonnée + anchor: "bottom", // la pointe touche exactement la coordonnée }) .setLngLat([lon, lat]) .addTo(map); - const entry = { id: post.id, marker, el: root, post }; - markersRef.current.push(entry); + markersRef.current.push({ id: post.id, marker, el: root, post }); - // --- Gestion du mode "agrandi" --- root.addEventListener("click", (ev) => { ev.stopPropagation(); - // Fermer l'ancien agrandi + // Fermer l'ancien gros post if (expandedElRef.current && expandedElRef.current !== root) { - expandedElRef.current.classList.remove("post-pin-expanded"); + expandedElRef.current.__renderCompact && + expandedElRef.current.__renderCompact(); + expandedElRef.current = null; } - // Toggle sur ce pin - const isExpanded = root.classList.toggle("post-pin-expanded"); - expandedElRef.current = isExpanded ? root : null; - - // Mettre à jour le texte (plus long si agrandi) + // Toggle pour ce post + const isExpanded = root.classList.contains("post-pin--expanded"); if (isExpanded) { - text.textContent = snippet; + renderCompact(); + expandedElRef.current = null; } else { - text.textContent = title; + 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, """); +} diff --git a/src/styles/mapMarkers.css b/src/styles/mapMarkers.css index 8415fbb..e53a68c 100644 --- a/src/styles/mapMarkers.css +++ b/src/styles/mapMarkers.css @@ -1,4 +1,4 @@ -/* Le conteneur du pin : MapLibre gère la position/transform */ +/* MapLibre gère la position/transform, on ne touche pas */ .post-pin { display: flex; flex-direction: column; @@ -6,9 +6,9 @@ pointer-events: auto; } -/* ===== PETIT POST (compact) ===== */ +/* ===== ÉTAT COMPACT : petite bulle + petite pointe ===== */ -.post-pin-bubble { +.post-pin--compact .post-pin-bubble { display: inline-flex; align-items: center; padding: 4px 8px; @@ -36,31 +36,131 @@ text-overflow: ellipsis; } -/* PETITE POINTE sous la bulle – pointe exactement sur la coordonnée */ -.post-pin-pointer { +/* petite pointe */ +.post-pin-pointer-small { width: 0; height: 0; margin-top: 2px; border-left: 7px solid transparent; border-right: 7px solid transparent; - border-top: 9px solid rgba(6, 40, 80, 0.95); /* couleur de la bulle */ - filter: drop-shadow(0 1px 3px rgba(0,0,0,0.6)); + border-top: 9px solid rgba(6, 40, 80, 0.95); + filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6)); } -/* ===== GROS POST (quand on clique) ===== */ +/* ===== ÉTAT ÉTENDU : gros post (carte) ===== */ -.post-pin.post-pin-expanded .post-pin-bubble { - padding: 8px 10px; - border-radius: 12px; - max-width: 260px; - background: rgba(8, 20, 40, 0.98); +.post-pin--expanded .post-card { + min-width: 260px; + max-width: 320px; + background: rgba(8, 20, 40, 0.97); + border-radius: 14px; + padding: 10px 12px; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.8); + border: 1px solid rgba(90, 190, 255, 0.9); + color: #e8f5ff; + box-sizing: border-box; } -/* Titre + texte multi-ligne comme ta maquette */ -.post-pin.post-pin-expanded .post-pin-text { - white-space: normal; - max-width: 260px; - line-height: 1.35; +/* header : catégorie + heure/date */ +.post-card-header { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 11px; + margin-bottom: 6px; } -/* On garde la même pointe, donc le gros post pointe toujours sur la position */ +.post-card-cat { + font-weight: 600; + color: #8fc5ff; +} + +.post-card-time { + color: #9eb7ff; +} + +/* corps : media + texte */ +.post-card-main { + display: flex; + flex-direction: row; + gap: 8px; + margin-bottom: 6px; +} + +/* fake bloc image/vidéo */ +.post-card-media { + width: 72px; + height: 72px; + border-radius: 10px; + background: radial-gradient(circle at 30% 30%, #4a9dff, #07152b); + display: flex; + align-items: center; + justify-content: center; +} + +.post-card-media-label { + font-size: 9px; + text-align: center; + color: #e8f5ff; +} + +/* texte principal */ +.post-card-info { + flex: 1; +} + +.post-card-title { + font-size: 13px; + font-weight: 600; + margin-bottom: 2px; +} + +.post-card-meta { + font-size: 10px; + color: #9eb7ff; + margin-bottom: 4px; +} + +.post-card-body { + font-size: 11px; + color: #c7e3ff; + max-height: 70px; + overflow: hidden; +} + +/* footer boutons */ +.post-card-footer { + display: flex; + gap: 6px; + margin-bottom: 6px; +} + +.post-card-btn { + border: none; + border-radius: 999px; + padding: 3px 8px; + font-size: 10px; + background: rgba(5, 35, 70, 0.95); + color: #e8f5ff; + cursor: pointer; +} + +/* zone commentaires */ +.post-card-comments { + font-size: 10px; + color: #9eb7ff; + padding: 4px 6px; + border-radius: 8px; + background: rgba(3, 14, 32, 0.95); +} + +/* Pointe sous le gros post */ +.post-card-pointer { + width: 0; + height: 0; + margin-top: 3px; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 11px solid rgba(8, 20, 40, 0.97); + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8)); +}