Auto deploy: 2025-12-09 06:24:43
This commit is contained in:
parent
5325e81b65
commit
b1e9e4379b
|
|
@ -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 = `
|
||||
<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>
|
||||
`;
|
||||
}
|
||||
|
||||
const dot = document.createElement("div");
|
||||
dot.className = "post-pin-dot";
|
||||
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>
|
||||
|
||||
const text = document.createElement("div");
|
||||
text.className = "post-pin-text";
|
||||
text.textContent = title;
|
||||
<div class="post-card-main">
|
||||
<div class="post-card-media">
|
||||
<div class="post-card-media-label">
|
||||
Image / Vidéo
|
||||
</div>
|
||||
</div>
|
||||
|
||||
bubble.appendChild(dot);
|
||||
bubble.appendChild(text);
|
||||
<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>
|
||||
|
||||
const pointer = document.createElement("div");
|
||||
pointer.className = "post-pin-pointer";
|
||||
<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>
|
||||
|
||||
root.appendChild(bubble);
|
||||
root.appendChild(pointer);
|
||||
<div class="post-card-comments">
|
||||
Live chat / comments (placeholder)
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-card-pointer"></div>
|
||||
`;
|
||||
}
|
||||
|
||||
// é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, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue