update frontend
This commit is contained in:
parent
50c0375be4
commit
fb538781b4
|
|
@ -0,0 +1,185 @@
|
||||||
|
/* MapLibre: on stabilise l'ancrage en gardant l'élément root à 0x0
|
||||||
|
et tout le UI en absolute au-dessus d'une pointe FIXE. */
|
||||||
|
|
||||||
|
/* Root du marker = ancre stable */
|
||||||
|
.post-pin {
|
||||||
|
position: relative;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
pointer-events: none; /* on active sur les enfants */
|
||||||
|
transform: translate3d(0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Conteneurs cliquables */
|
||||||
|
.post-pin * {
|
||||||
|
pointer-events: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pointe fixe (tip) — le bas du marker */
|
||||||
|
.post-pin-tip {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, -100%); /* remonte le tip au-dessus du point d'ancre */
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper commun (compact/expanded) positionné AU-DESSUS du tip */
|
||||||
|
.post-pin-layer {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, calc(-100% - 12px)); /* 12px = hauteur tip approx */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
COMPACT
|
||||||
|
========================= */
|
||||||
|
.post-pin-compact {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(6, 40, 80, 0.95);
|
||||||
|
border: 1px solid rgba(80, 180, 255, 0.9);
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
||||||
|
max-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-pin-dot {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #ff8a00;
|
||||||
|
margin-right: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-pin-text {
|
||||||
|
color: #e8f5ff;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
max-width: 160px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
EXPANDED
|
||||||
|
========================= */
|
||||||
|
.post-pin-expanded {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* header : catégorie + heure/date */
|
||||||
|
.post-card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 11px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-card-media-label {
|
||||||
|
font-size: 9px;
|
||||||
|
text-align: center;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* footer boutons */
|
||||||
|
.post-card-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-card-comments {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #9eb7ff;
|
||||||
|
padding: 4px 6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(3, 14, 32, 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helpers */
|
||||||
|
.post-hidden { display: none !important; }
|
||||||
|
|
@ -20,9 +20,8 @@ export function clearAllMarkers(markersRef, expandedElRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée un marqueur pour un post :
|
* Marker stable: root 0x0 + UI en absolute au-dessus d'un tip fixe.
|
||||||
* - état compact : petite bulle + pointe
|
* => Le pin ne "jump" plus quand tu expand/collapse.
|
||||||
* - état étendu : gros post (carte) comme sur ton dessin
|
|
||||||
*/
|
*/
|
||||||
export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
|
|
@ -64,103 +63,103 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||||
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 post-pin--compact";
|
root.className = "post-pin";
|
||||||
|
|
||||||
function renderCompact() {
|
// Layer UI (au-dessus du tip)
|
||||||
root.className = "post-pin post-pin--compact";
|
const layer = document.createElement("div");
|
||||||
root.innerHTML = `
|
layer.className = "post-pin-layer";
|
||||||
<div class="post-pin-bubble">
|
|
||||||
|
// Compact UI
|
||||||
|
const compact = document.createElement("div");
|
||||||
|
compact.className = "post-pin-compact";
|
||||||
|
compact.innerHTML = `
|
||||||
<div class="post-pin-dot"></div>
|
<div class="post-pin-dot"></div>
|
||||||
<div class="post-pin-text">${escapeHtml(title)}</div>
|
<div class="post-pin-text">${escapeHtml(title)}</div>
|
||||||
</div>
|
|
||||||
<div class="post-pin-pointer-small"></div>
|
|
||||||
`;
|
`;
|
||||||
}
|
|
||||||
|
|
||||||
function renderExpanded() {
|
// Expanded UI
|
||||||
root.className = "post-pin post-pin--expanded";
|
const expanded = document.createElement("div");
|
||||||
root.innerHTML = `
|
expanded.className = "post-pin-expanded post-hidden";
|
||||||
<div class="post-card">
|
expanded.innerHTML = `
|
||||||
<div class="post-card-header">
|
<div class="post-card-header">
|
||||||
<div class="post-card-cat">
|
<div class="post-card-cat">
|
||||||
${escapeHtml(category || "NEWS")}
|
${escapeHtml(category || "NEWS")}
|
||||||
${subCat ? "· " + escapeHtml(subCat) : ""}
|
${subCat ? "· " + escapeHtml(subCat) : ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="post-card-time">
|
<div class="post-card-time">${escapeHtml(created || "")}</div>
|
||||||
${escapeHtml(created || "")}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-card-main">
|
<div class="post-card-main">
|
||||||
<div class="post-card-media">
|
<div class="post-card-media">
|
||||||
<div class="post-card-media-label">
|
<div class="post-card-media-label">Image / Vidéo</div>
|
||||||
Image / Vidéo
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-card-info">
|
<div class="post-card-info">
|
||||||
<div class="post-card-title">
|
<div class="post-card-title">${escapeHtml(title)}</div>
|
||||||
${escapeHtml(title)}
|
|
||||||
</div>
|
|
||||||
<div class="post-card-meta">
|
<div class="post-card-meta">
|
||||||
by ${escapeHtml(author)} · lat ${lat.toFixed(3)} · lon ${lon.toFixed(3)}
|
by ${escapeHtml(author)} · lat ${lat.toFixed(3)} · lon ${lon.toFixed(3)}
|
||||||
</div>
|
</div>
|
||||||
<div class="post-card-body">
|
<div class="post-card-body">${escapeHtml(body)}</div>
|
||||||
${escapeHtml(body)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-card-footer">
|
<div class="post-card-footer">
|
||||||
<button class="post-card-btn">Live</button>
|
<button class="post-card-btn" type="button">Live</button>
|
||||||
<button class="post-card-btn">Like</button>
|
<button class="post-card-btn" type="button">Like</button>
|
||||||
<button class="post-card-btn">Share</button>
|
<button class="post-card-btn" type="button">Share</button>
|
||||||
<button class="post-card-btn">Fix</button>
|
<button class="post-card-btn" type="button">Fix</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-card-comments">
|
<div class="post-card-comments">Live chat / comments (placeholder)</div>
|
||||||
Live chat / comments (placeholder)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="post-card-pointer"></div>
|
|
||||||
`;
|
`;
|
||||||
}
|
|
||||||
|
|
||||||
// état initial : compact
|
// Tip fixe (le point de la map)
|
||||||
renderCompact();
|
const tip = document.createElement("div");
|
||||||
|
tip.className = "post-pin-tip";
|
||||||
|
|
||||||
|
layer.appendChild(compact);
|
||||||
|
layer.appendChild(expanded);
|
||||||
|
root.appendChild(layer);
|
||||||
|
root.appendChild(tip);
|
||||||
|
|
||||||
const marker = new maplibregl.Marker({
|
const marker = new maplibregl.Marker({
|
||||||
element: root,
|
element: root,
|
||||||
anchor: "bottom", // la pointe touche exactement la coordonnée
|
anchor: "bottom",
|
||||||
})
|
})
|
||||||
.setLngLat([lon, lat])
|
.setLngLat([lon, lat])
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
|
|
||||||
markersRef.current.push({ id: post.id, marker, el: root, post });
|
markersRef.current.push({ id: post.id, marker, el: root, post });
|
||||||
|
|
||||||
|
function setExpanded(isOn) {
|
||||||
|
if (isOn) {
|
||||||
|
compact.classList.add("post-hidden");
|
||||||
|
expanded.classList.remove("post-hidden");
|
||||||
|
expandedElRef.current = root;
|
||||||
|
} else {
|
||||||
|
expanded.classList.add("post-hidden");
|
||||||
|
compact.classList.remove("post-hidden");
|
||||||
|
if (expandedElRef.current === root) expandedElRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
root.addEventListener("click", (ev) => {
|
root.addEventListener("click", (ev) => {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
// Fermer l'ancien gros post
|
// Fermer l'ancien expanded
|
||||||
if (expandedElRef.current && expandedElRef.current !== root) {
|
if (expandedElRef.current && expandedElRef.current !== root) {
|
||||||
expandedElRef.current.__renderCompact &&
|
const prev = expandedElRef.current;
|
||||||
expandedElRef.current.__renderCompact();
|
if (prev && prev.__setExpanded) prev.__setExpanded(false);
|
||||||
expandedElRef.current = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle pour ce post
|
const isExpanded = !expanded.classList.contains("post-hidden");
|
||||||
const isExpanded = root.classList.contains("post-pin--expanded");
|
setExpanded(!isExpanded);
|
||||||
if (isExpanded) {
|
|
||||||
renderCompact();
|
|
||||||
expandedElRef.current = null;
|
|
||||||
} else {
|
|
||||||
renderExpanded();
|
|
||||||
expandedElRef.current = root;
|
|
||||||
// on garde les fonctions pour pouvoir re-compactifier
|
|
||||||
root.__renderCompact = renderCompact;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// expose pour pouvoir fermer depuis un autre marker
|
||||||
|
root.__setExpanded = setExpanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* petite fonction pour éviter d’injecter du HTML sale */
|
/* petite fonction pour éviter d’injecter du HTML sale */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue