update frontend
This commit is contained in:
parent
fb538781b4
commit
8249aa7e16
|
|
@ -1,50 +1,30 @@
|
||||||
import maplibregl from "maplibre-gl";
|
import maplibregl from "maplibre-gl";
|
||||||
|
|
||||||
/**
|
|
||||||
* Supprime tous les marqueurs
|
|
||||||
*/
|
|
||||||
export function clearAllMarkers(markersRef, expandedElRef) {
|
export function clearAllMarkers(markersRef, expandedElRef) {
|
||||||
if (markersRef.current) {
|
if (markersRef.current) {
|
||||||
for (const m of markersRef.current) {
|
for (const m of markersRef.current) {
|
||||||
try {
|
try { m.marker.remove(); } catch {}
|
||||||
m.marker.remove();
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
markersRef.current = [];
|
markersRef.current = [];
|
||||||
if (expandedElRef) {
|
if (expandedElRef) expandedElRef.current = null;
|
||||||
expandedElRef.current = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker stable: root 0x0 + UI en absolute au-dessus d'un tip fixe.
|
|
||||||
* => Le pin ne "jump" plus quand tu expand/collapse.
|
|
||||||
*/
|
|
||||||
export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
if (!map) return;
|
if (!map) return;
|
||||||
|
|
||||||
// --- coordonnées ---
|
|
||||||
const lat =
|
const lat =
|
||||||
typeof post.lat === "number"
|
typeof post.lat === "number" ? post.lat :
|
||||||
? post.lat
|
typeof post.Lat === "number" ? post.Lat :
|
||||||
: typeof post.Lat === "number"
|
typeof post.latitude === "number" ? post.latitude :
|
||||||
? post.Lat
|
null;
|
||||||
: typeof post.latitude === "number"
|
|
||||||
? post.latitude
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const lon =
|
const lon =
|
||||||
typeof post.lon === "number"
|
typeof post.lon === "number" ? post.lon :
|
||||||
? post.lon
|
typeof post.Lon === "number" ? post.Lon :
|
||||||
: typeof post.Lon === "number"
|
typeof post.longitude === "number" ? post.longitude :
|
||||||
? post.Lon
|
null;
|
||||||
: typeof post.longitude === "number"
|
|
||||||
? post.longitude
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (lat == null || lon == null) {
|
if (lat == null || lon == null) {
|
||||||
console.warn("post sans coordonnée:", post);
|
console.warn("post sans coordonnée:", post);
|
||||||
|
|
@ -58,20 +38,16 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
title;
|
title;
|
||||||
|
|
||||||
const author = (post.author || post.Author || "").trim() || "unknown";
|
const author = (post.author || post.Author || "").trim() || "unknown";
|
||||||
const created =
|
const created = (post.created_at || post.CreatedAt || "").toString().slice(0, 19);
|
||||||
(post.created_at || post.CreatedAt || "").toString().slice(0, 19);
|
|
||||||
const category = (post.category || post.Category || "").toUpperCase() || "";
|
const category = (post.category || post.Category || "").toUpperCase() || "";
|
||||||
const subCat = (post.sub_category || post.SubCategory || "").toString();
|
const subCat = (post.sub_category || post.SubCategory || "").toString();
|
||||||
|
|
||||||
// Root ancré stable
|
|
||||||
const root = document.createElement("div");
|
const root = document.createElement("div");
|
||||||
root.className = "post-pin";
|
root.className = "post-pin";
|
||||||
|
|
||||||
// Layer UI (au-dessus du tip)
|
|
||||||
const layer = document.createElement("div");
|
const layer = document.createElement("div");
|
||||||
layer.className = "post-pin-layer";
|
layer.className = "post-pin-layer";
|
||||||
|
|
||||||
// Compact UI
|
|
||||||
const compact = document.createElement("div");
|
const compact = document.createElement("div");
|
||||||
compact.className = "post-pin-compact";
|
compact.className = "post-pin-compact";
|
||||||
compact.innerHTML = `
|
compact.innerHTML = `
|
||||||
|
|
@ -79,7 +55,6 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
<div class="post-pin-text">${escapeHtml(title)}</div>
|
<div class="post-pin-text">${escapeHtml(title)}</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Expanded UI
|
|
||||||
const expanded = document.createElement("div");
|
const expanded = document.createElement("div");
|
||||||
expanded.className = "post-pin-expanded post-hidden";
|
expanded.className = "post-pin-expanded post-hidden";
|
||||||
expanded.innerHTML = `
|
expanded.innerHTML = `
|
||||||
|
|
@ -115,7 +90,9 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
<div class="post-card-comments">Live chat / comments (placeholder)</div>
|
<div class="post-card-comments">Live chat / comments (placeholder)</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Tip fixe (le point de la map)
|
// IMPORTANT: cliquer sur les boutons ne doit pas re-toggle le marker
|
||||||
|
expanded.addEventListener("click", (e) => e.stopPropagation());
|
||||||
|
|
||||||
const tip = document.createElement("div");
|
const tip = document.createElement("div");
|
||||||
tip.className = "post-pin-tip";
|
tip.className = "post-pin-tip";
|
||||||
|
|
||||||
|
|
@ -124,10 +101,7 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
root.appendChild(layer);
|
root.appendChild(layer);
|
||||||
root.appendChild(tip);
|
root.appendChild(tip);
|
||||||
|
|
||||||
const marker = new maplibregl.Marker({
|
const marker = new maplibregl.Marker({ element: root, anchor: "bottom" })
|
||||||
element: root,
|
|
||||||
anchor: "bottom",
|
|
||||||
})
|
|
||||||
.setLngLat([lon, lat])
|
.setLngLat([lon, lat])
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
|
|
||||||
|
|
@ -145,10 +119,12 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expose pour fermer depuis un autre marker
|
||||||
|
root.__setExpanded = setExpanded;
|
||||||
|
|
||||||
root.addEventListener("click", (ev) => {
|
root.addEventListener("click", (ev) => {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
// Fermer l'ancien expanded
|
|
||||||
if (expandedElRef.current && expandedElRef.current !== root) {
|
if (expandedElRef.current && expandedElRef.current !== root) {
|
||||||
const prev = expandedElRef.current;
|
const prev = expandedElRef.current;
|
||||||
if (prev && prev.__setExpanded) prev.__setExpanded(false);
|
if (prev && prev.__setExpanded) prev.__setExpanded(false);
|
||||||
|
|
@ -157,12 +133,8 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
const isExpanded = !expanded.classList.contains("post-hidden");
|
const isExpanded = !expanded.classList.contains("post-hidden");
|
||||||
setExpanded(!isExpanded);
|
setExpanded(!isExpanded);
|
||||||
});
|
});
|
||||||
|
|
||||||
// expose pour pouvoir fermer depuis un autre marker
|
|
||||||
root.__setExpanded = setExpanded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* petite fonction pour éviter d’injecter du HTML sale */
|
|
||||||
function escapeHtml(str) {
|
function escapeHtml(str) {
|
||||||
return String(str)
|
return String(str)
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
|
|
|
||||||
|
|
@ -1,166 +1,140 @@
|
||||||
/* MapLibre gère la position/transform, on ne touche pas */
|
/* SocioWire — Marker stable (no jump)
|
||||||
.post-pin {
|
Root 0x0 anchored, UI absolutely positioned above a fixed tip */
|
||||||
|
|
||||||
|
.post-pin{
|
||||||
|
position: relative;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
pointer-events: auto;
|
||||||
|
transform: translate3d(0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-pin-layer{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, calc(-100% - 14px)); /* 14px ~ tip height */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
pointer-events: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== ÉTAT COMPACT : petite bulle + petite pointe ===== */
|
.post-pin-tip{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, -100%);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
.post-pin--compact .post-pin-bubble {
|
.post-hidden{ display:none !important; }
|
||||||
|
|
||||||
|
/* ===== COMPACT ===== */
|
||||||
|
.post-pin-compact{
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: rgba(6, 40, 80, 0.95);
|
background: rgba(6, 40, 80, 0.95);
|
||||||
border: 1px solid rgba(80, 180, 255, 0.9);
|
border: 1px solid rgba(80, 180, 255, 0.9);
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 2px 4px rgba(0,0,0,0.5);
|
||||||
|
max-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-pin-dot {
|
.post-pin-dot{
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #ff8a00;
|
background: #ff8a00;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-pin-text {
|
.post-pin-text{
|
||||||
color: #e8f5ff;
|
color: #e8f5ff;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
max-width: 120px;
|
max-width: 180px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* petite pointe */
|
/* ===== EXPANDED ===== */
|
||||||
.post-pin-pointer-small {
|
.post-pin-expanded{
|
||||||
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);
|
|
||||||
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===== ÉTAT ÉTENDU : gros post (carte) ===== */
|
|
||||||
|
|
||||||
.post-pin--expanded .post-card {
|
|
||||||
min-width: 260px;
|
min-width: 260px;
|
||||||
max-width: 320px;
|
max-width: 320px;
|
||||||
background: rgba(8, 20, 40, 0.97);
|
background: rgba(8, 20, 40, 0.97);
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.8);
|
box-shadow: 0 6px 18px rgba(0,0,0,0.8);
|
||||||
border: 1px solid rgba(90, 190, 255, 0.9);
|
border: 1px solid rgba(90, 190, 255, 0.9);
|
||||||
color: #e8f5ff;
|
color: #e8f5ff;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* header : catégorie + heure/date */
|
/* header */
|
||||||
.post-card-header {
|
.post-card-header{
|
||||||
display: flex;
|
display:flex;
|
||||||
justify-content: space-between;
|
justify-content:space-between;
|
||||||
align-items: center;
|
align-items:center;
|
||||||
font-size: 11px;
|
font-size:11px;
|
||||||
margin-bottom: 6px;
|
margin-bottom:6px;
|
||||||
}
|
}
|
||||||
|
.post-card-cat{ font-weight:600; color:#8fc5ff; }
|
||||||
|
.post-card-time{ color:#9eb7ff; }
|
||||||
|
|
||||||
.post-card-cat {
|
/* main */
|
||||||
font-weight: 600;
|
.post-card-main{
|
||||||
color: #8fc5ff;
|
display:flex;
|
||||||
|
gap:8px;
|
||||||
|
margin-bottom:6px;
|
||||||
}
|
}
|
||||||
|
.post-card-media{
|
||||||
.post-card-time {
|
width:72px;
|
||||||
color: #9eb7ff;
|
height:72px;
|
||||||
}
|
border-radius:10px;
|
||||||
|
|
||||||
/* 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);
|
background: radial-gradient(circle at 30% 30%, #4a9dff, #07152b);
|
||||||
display: flex;
|
display:flex;
|
||||||
align-items: center;
|
align-items:center;
|
||||||
justify-content: center;
|
justify-content:center;
|
||||||
|
flex-shrink:0;
|
||||||
}
|
}
|
||||||
|
.post-card-media-label{
|
||||||
.post-card-media-label {
|
font-size:9px;
|
||||||
font-size: 9px;
|
text-align:center;
|
||||||
text-align: center;
|
color:#e8f5ff;
|
||||||
color: #e8f5ff;
|
|
||||||
}
|
}
|
||||||
|
.post-card-info{ flex:1; min-width:0; }
|
||||||
|
.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; }
|
||||||
|
|
||||||
/* texte principal */
|
/* footer */
|
||||||
.post-card-info {
|
.post-card-footer{
|
||||||
flex: 1;
|
display:flex;
|
||||||
|
gap:6px;
|
||||||
|
margin-bottom:6px;
|
||||||
|
flex-wrap:wrap;
|
||||||
}
|
}
|
||||||
|
.post-card-btn{
|
||||||
.post-card-title {
|
border:none;
|
||||||
font-size: 13px;
|
border-radius:999px;
|
||||||
font-weight: 600;
|
padding:3px 8px;
|
||||||
margin-bottom: 2px;
|
font-size:10px;
|
||||||
}
|
|
||||||
|
|
||||||
.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);
|
background: rgba(5, 35, 70, 0.95);
|
||||||
color: #e8f5ff;
|
color:#e8f5ff;
|
||||||
cursor: pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
||||||
|
.post-card-comments{
|
||||||
/* zone commentaires */
|
font-size:10px;
|
||||||
.post-card-comments {
|
color:#9eb7ff;
|
||||||
font-size: 10px;
|
padding:4px 6px;
|
||||||
color: #9eb7ff;
|
border-radius:8px;
|
||||||
padding: 4px 6px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: rgba(3, 14, 32, 0.95);
|
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));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue