diff --git a/src/components/Map/markerManager.js b/src/components/Map/markerManager.js index 8b8c1a1..e974930 100644 --- a/src/components/Map/markerManager.js +++ b/src/components/Map/markerManager.js @@ -7,6 +7,12 @@ import { cardTokens } from "../../theme/cardTokens"; import { getTemplateSpecForPost, adaptPostToTemplateData } from "./templateSpecs"; export function clearAllMarkers(markersRef, expandedElRef) { + // close overlay if any + try { + const el = expandedElRef?.current; + if (el && el.__swClose) el.__swClose(); + } catch {} + if (markersRef.current) { for (const m of markersRef.current) { try { @@ -46,9 +52,11 @@ export function applyOcclusionForExpanded(markersRef, expandedEl) { const list = markersRef.current || []; for (const item of list) { const el = item?.el; - if (!el || el === expandedEl) continue; + if (!el) continue; const r = el.getBoundingClientRect(); + + // Only hide markers that are below/behind the expanded card const isBelow = r.top >= raw.top; if (!isBelow) { el.style.visibility = "visible"; @@ -83,7 +91,9 @@ function mountCard(container, spec, data, theme) { themeTokens: tokens, onAction: (action, value) => { if (action?.type === "open_url" && value) { - try { window.open(value, "_blank"); } catch {} + try { + window.open(value, "_blank"); + } catch {} } }, className: "", @@ -91,33 +101,169 @@ function mountCard(container, spec, data, theme) { ); return () => { - try { root.unmount(); } catch {} + try { + root.unmount(); + } catch {} }; } +function escapeHtml(str) { + return String(str ?? "") + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + /** - * Force the marker anchor to be displayed at: - * - X: centered (50% width) - * - Y: 6/7 of map height (so the popup sits "1/7 from bottom") + * Overlay: fixed card at the bottom + pointer that follows the marker. + * We only pan the minimum if the marker ends up behind the card. */ -function panMarkerToPreferredAnchor(map, lngLat) { - if (!map) return; +function getOrCreateExpandedOverlay(map) { + const container = map.getContainer(); + if (!container) return null; - const el = map.getContainer(); - if (!el) return; + let root = container.querySelector(".sw-expanded-overlay-root"); + if (root) return root; - const rect = el.getBoundingClientRect(); - const targetX = rect.width * 0.5; - const targetY = rect.height * (6 / 7); // 1/7 from bottom => anchor at 6/7 height + root = document.createElement("div"); + root.className = "sw-expanded-overlay-root"; + + root.innerHTML = ` +
+
+
+
+
+
+
+
Watching
+
+
☑ Julia ★
— I see it…
+
☑ Kim / CNN
— Blah blah blah
+
☑ Yan ★
— Watch this!!
+
+ +
+
+ +
+
+
The news here (generated)
+
+ +
+ + + + +
+ +
+
Live chat / comments
+
+
— …
+
— what the f***?
+
— nice…
+
— my eyes!!
+
+
+ + +
+
+
+
+ +
+
+ `; + + // helper close fn + root.__swClose = () => { + try { + if (root.__swUnmountFull) root.__swUnmountFull(); + } catch {} + try { + if (root.__swMoveHandler && root.__swMap) { + root.__swMap.off("move", root.__swMoveHandler); + root.__swMap.off("zoom", root.__swMoveHandler); + } + } catch {} + try { + root.remove(); + } catch {} + }; + + container.appendChild(root); + return root; +} + +function updateOverlayPointer(map, overlayRoot, lngLat) { + if (!map || !overlayRoot || !lngLat) return; const p = map.project(lngLat); - const dx = targetX - p.x; - const dy = targetY - p.y; + const pointer = overlayRoot.querySelector(".sw-overlay-pointer"); + const line = overlayRoot.querySelector(".sw-overlay-line"); + const cardWrap = overlayRoot.querySelector(".sw-expanded-overlay-card"); + const card = overlayRoot.querySelector(".sw-expanded-overlay-card .post-card"); - // tiny deltas -> skip - if (Math.abs(dx) < 2 && Math.abs(dy) < 2) return; + if (!pointer || !line || !cardWrap || !card) return; + + // pointer follows marker + pointer.style.left = `${p.x}px`; + pointer.style.top = `${p.y}px`; + + // simple line from marker to bottom center of the card + const contRect = map.getContainer().getBoundingClientRect(); + const cardRect = cardWrap.getBoundingClientRect(); + + const x1 = p.x; + const y1 = p.y; + + const x2 = (cardRect.left - contRect.left) + cardRect.width / 2; + const y2 = (cardRect.top - contRect.top) + cardRect.height; // bottom of card + + const dx = x2 - x1; + const dy = y2 - y1; + const len = Math.sqrt(dx * dx + dy * dy); + + // place a thin line + line.style.left = `${x1}px`; + line.style.top = `${y1}px`; + line.style.width = `${len}px`; + line.style.transform = `rotate(${Math.atan2(dy, dx)}rad)`; +} + +function minimalPanToKeepMarkerVisible(map, overlayRoot, lngLat) { + if (!map || !overlayRoot || !lngLat) return; + + const p = map.project(lngLat); + const cont = map.getContainer(); + if (!cont) return; + + const contRect = cont.getBoundingClientRect(); + const cardWrap = overlayRoot.querySelector(".sw-expanded-overlay-card"); + if (!cardWrap) return; + + const cardRect = cardWrap.getBoundingClientRect(); + + const topPad = 18; + const bottomSafe = (cardRect.top - contRect.top) - 18; + + let dy = 0; + + // marker too high -> bring it down a bit + if (p.y < topPad) dy = (topPad - p.y); + + // marker behind the card -> bring it up a bit + if (p.y > bottomSafe) dy = (bottomSafe - p.y); + + // clamp so it never "vent dalle trop loin" + dy = Math.max(-160, Math.min(160, dy)); + + if (Math.abs(dy) < 2) return; - // lock close/fetch/rebuild while panning try { const until = Date.now() + 2000; map.__swIgnoreMapClickUntil = until; @@ -126,7 +272,7 @@ function panMarkerToPreferredAnchor(map, lngLat) { map.__swIgnoreRebuildUntil = until; } catch {} - map.panBy([dx, dy], { duration: 650 }); + map.panBy([0, dy], { duration: 350 }); } export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, theme = "blue") { @@ -160,7 +306,9 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, the function unmountIfAny() { if (root.__swUnmount) { - try { root.__swUnmount(); } catch {} + try { + root.__swUnmount(); + } catch {} root.__swUnmount = null; } } @@ -185,97 +333,86 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, the clearOcclusion(markersRef); } - function renderExpanded() { - unmountIfAny(); - root.className = "post-pin post-pin--expanded"; - root.style.zIndex = "999999"; + function closeExpandedOverlayIfAny() { + const cur = expandedElRef.current; + if (cur && cur.__swClose) { + try { + cur.__swClose(); + } catch {} + } + expandedElRef.current = null; + clearOcclusion(markersRef); + } - // 2000ms locks so recenter/fetch/rebuild does not close this expanded popup + function renderExpandedOverlay() { + // locks so fetch/rebuild doesn't close while opening try { - const m = mapRef.current; - if (m) { - const until = Date.now() + 2000; - m.__swIgnoreMapClickUntil = until; - m.__swIgnoreCloseUntil = until; - m.__swIgnoreFetchUntil = until; - m.__swIgnoreRebuildUntil = until; - } + const until = Date.now() + 2000; + map.__swIgnoreMapClickUntil = until; + map.__swIgnoreCloseUntil = until; + map.__swIgnoreFetchUntil = until; + map.__swIgnoreRebuildUntil = until; } catch {} + closeExpandedOverlayIfAny(); + + const overlayRoot = getOrCreateExpandedOverlay(map); + if (!overlayRoot) return; + + // fill headline const headline = escapeHtml(post?.title || "Untitled"); + const titleEl = overlayRoot.querySelector(".sw-news-title"); + if (titleEl) titleEl.innerHTML = headline; - root.innerHTML = ` -
-
-
-
-
+ // mount template full into the left area + try { + if (overlayRoot.__swUnmountFull) overlayRoot.__swUnmountFull(); + } catch {} + overlayRoot.__swUnmountFull = null; -
-
Watching
-
-
☑ Julia ★
— I see it…
-
☑ Kim / CNN
— Blah blah blah
-
☑ Yan ★
— Watch this!!
-
- -
-
- -
-
${headline}
-
The news here (generated)
-
- -
- - - - -
- -
-
Live chat / comments
-
-
— …
-
— what the f***?
-
— nice…
-
— my eyes!!
-
-
- - -
-
-
-
- `; - - const wrap = root.querySelector(".sw-template-full-wrap"); + const wrap = overlayRoot.querySelector(".sw-template-full-wrap"); if (wrap) { + wrap.innerHTML = ""; // ensure clean const spec = getTemplateSpecForPost(post, "full"); const data = adaptPostToTemplateData(post); - root.__swUnmount = mountCard(wrap, spec, data, theme); + overlayRoot.__swUnmountFull = mountCard(wrap, spec, data, theme); } - // After render, pan so marker sits at the preferred anchor (1/7 from bottom) + // pointer updater + const moveHandler = () => { + try { + updateOverlayPointer(map, overlayRoot, lngLat); + applyOcclusionForExpanded(markersRef, overlayRoot); + } catch {} + }; + + overlayRoot.__swMap = map; + overlayRoot.__swMoveHandler = moveHandler; + + map.on("move", moveHandler); + map.on("zoom", moveHandler); + + // initial layout after paint requestAnimationFrame(() => { try { - const m = mapRef.current; - if (!m) return; + // 1) update pointer/line + updateOverlayPointer(map, overlayRoot, lngLat); - // 1) put the marker anchor exactly where we want - panMarkerToPreferredAnchor(m, lngLat); + // 2) minimal pan so marker isn't hidden behind the fixed card + minimalPanToKeepMarkerVisible(map, overlayRoot, lngLat); - // 2) re-occlude after the pan finishes - m.once("moveend", () => { - try { applyOcclusionForExpanded(markersRef, root); } catch {} + // 3) occlusion now + after moveend + applyOcclusionForExpanded(markersRef, overlayRoot); + map.once("moveend", () => { + try { + updateOverlayPointer(map, overlayRoot, lngLat); + applyOcclusionForExpanded(markersRef, overlayRoot); + } catch {} }); - - // also occlude right away - applyOcclusionForExpanded(markersRef, root); } catch {} }); + + expandedElRef.current = overlayRoot; } renderCompact(); @@ -290,26 +427,17 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, the root.addEventListener("click", (ev) => { ev.stopPropagation(); - if (expandedElRef.current && expandedElRef.current !== root) { - if (expandedElRef.current.__renderCompact) expandedElRef.current.__renderCompact(); - expandedElRef.current = null; + // toggle: if overlay already open for this post, close it + const cur = expandedElRef.current; + if (cur && cur.__swForId && cur.__swForId === (post.id ?? `${lon},${lat}`)) { + closeExpandedOverlayIfAny(); + return; } - const isExpanded = root.classList.contains("post-pin--expanded"); - if (isExpanded) { - renderCompact(); - expandedElRef.current = null; - } else { - renderExpanded(); - expandedElRef.current = root; + // open overlay + renderExpandedOverlay(); + if (expandedElRef.current) { + expandedElRef.current.__swForId = post.id ?? `${lon},${lat}`; } }); } - -function escapeHtml(str) { - return String(str ?? "") - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """); -} diff --git a/src/components/Map/useMapCore.js b/src/components/Map/useMapCore.js index 14445d4..546292e 100644 --- a/src/components/Map/useMapCore.js +++ b/src/components/Map/useMapCore.js @@ -47,7 +47,23 @@ export function useMapCore(theme) { function closeExpandedIfAny() { const el = expandedElRef.current; - if (el && el.__renderCompact) el.__renderCompact(); + if (!el) return; + + // overlay style + if (el.__swClose) { + try { + el.__swClose(); + } catch {} + expandedElRef.current = null; + return; + } + + // legacy marker-expanded style + if (el.__renderCompact) { + try { + el.__renderCompact(); + } catch {} + } expandedElRef.current = null; } @@ -88,7 +104,7 @@ export function useMapCore(theme) { map.on("move", reOcclude); map.on("zoom", reOcclude); - // IMPORTANT: ignore close while we are auto-panning to keep popup visible + // ignore close while auto actions are happening map.on("click", () => { try { const until = map.__swIgnoreMapClickUntil || 0; diff --git a/src/styles/map.css b/src/styles/map.css index 9b4b999..1e88db9 100644 --- a/src/styles/map.css +++ b/src/styles/map.css @@ -43,7 +43,7 @@ min-width:0; } -/* keep side-by-side on most phones; stack only ultra-small */ -@media (max-width: 420px){ +/* stack only ultra-small (NOT normal portrait phones) */ +@media (max-width: 340px){ .below-row{ flex-direction:column; } } diff --git a/src/styles/mapMarkers.css b/src/styles/mapMarkers.css index 9fd4f6a..70cdc9f 100644 --- a/src/styles/mapMarkers.css +++ b/src/styles/mapMarkers.css @@ -37,362 +37,86 @@ filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6)); } -.post-pin--expanded { z-index: 999999; } - -.post-pin--expanded .post-card { +/* ===== Template mini wrapper (keeps pointer unchanged) ===== */ +.sw-template-mini-wrap{ position: absolute; left: 0; top: 0; - transform: translate(-50%, calc(-100% - 14px)); - min-width: 260px; - max-width: 320px; + transform: translate(-50%, calc(-100% - 12px)) scale(0.62); + transform-origin: bottom center; + will-change: transform; +} + +@media (max-width: 640px){ + .sw-template-mini-wrap{ + transform: translate(-50%, calc(-100% - 12px)) scale(0.52); + } +} + +/* ========================================================= + NEW: FIXED EXPANDED OVERLAY + - Card is fixed near bottom (consistent) + - Pointer follows marker (consistent) + - No huge map recenter jumps + ========================================================= */ + +.sw-expanded-overlay-root{ + position:absolute; + inset:0; + z-index: 999999; + pointer-events:none; +} + +/* Card position: "dans le bas" (approx bottom zone), consistent on rotate */ +.sw-expanded-overlay-card{ + position:absolute; + left: 50%; + bottom: calc(12px + env(safe-area-inset-bottom) + var(--sw-below-overlap, 0px)); + transform: translateX(-50%); + width: min(92vw, 420px); + pointer-events: auto; +} + +/* Make card fit mobile nicely */ +.sw-expanded-overlay-card .post-card{ + width: 100%; + max-height: min(58vh, 640px); + overflow:auto; + -webkit-overflow-scrolling: touch; background: rgba(8, 20, 40, 0.97); border-radius: 14px; padding: 10px 12px; - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.8); + box-shadow: 0 10px 26px rgba(0, 0, 0, 0.85); border: 1px solid rgba(90, 190, 255, 0.9); color: #e8f5ff; } -.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; } -.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; } -.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); -} -.post-pin--expanded .post-card-pointer { + +/* Pointer on the marker position */ +.sw-overlay-pointer{ position:absolute; - left:0; top:0; - transform: translate(-50%, -100%); width:0; height:0; - border-left:10px solid transparent; + border-left: 10px solid transparent; border-right:10px solid transparent; - border-top:11px solid rgba(8, 20, 40, 0.97); + border-top: 11px solid rgba(8, 20, 40, 0.97); filter: drop-shadow(0 2px 4px rgba(0,0,0,.8)); -} - -/* ===== Template marker wrappers (pointers stay the same classes) ===== */ -.sw-template-mini-wrap{ - position: absolute; + transform: translate(-50%, -100%); left: 0; top: 0; - transform: translate(-50%, calc(-100% - 12px)); } -.sw-expanded-shell{ - padding: 10px 12px; -} - -.sw-expanded-top{ - display:flex; - gap:10px; - align-items:flex-start; -} - -.sw-expanded-left{ - flex: 1; -} - -.sw-expanded-right{ - width: 150px; - min-width: 140px; - display:flex; - flex-direction:column; - gap:8px; - padding-top: 4px; -} - -.sw-watch-title{ - font-size: 11px; - font-weight: 800; - color:#bfdbfe; - text-transform: uppercase; - letter-spacing: .06em; -} - -.sw-watch-list{ - display:flex; - flex-direction:column; - gap:6px; -} - -.sw-watch-item{ - font-size: 11px; - color:#e8f5ff; - background: rgba(3, 14, 32, 0.75); - border: 1px solid rgba(90, 190, 255, 0.35); - border-radius: 10px; - padding: 6px 8px; -} - -.sw-watch-msg{ - opacity:.85; - margin-top:2px; - font-size: 10px; - color:#c7e3ff; -} - -.sw-add-feed-btn{ - margin-top: 2px; - border: 1px solid rgba(148,163,184,.7); - border-radius: 10px; - padding: 8px 10px; - background: rgba(5, 35, 70, 0.85); - color:#e8f5ff; - font-weight: 900; - font-size: 11px; - cursor:pointer; -} - -.sw-news-generated{ - margin-top: 10px; - padding: 8px 10px; - border-radius: 12px; - background: rgba(3, 14, 32, 0.75); - border: 1px solid rgba(90, 190, 255, 0.35); -} - -.sw-news-title{ - font-size: 12px; - font-weight: 900; - color:#e8f5ff; - margin-bottom: 2px; -} - -.sw-news-sub{ - font-size: 10px; - color:#9eb7ff; -} - -.sw-actions-row{ - margin-top: 8px; -} - -.sw-livechat{ - margin-top: 8px; -} - -.sw-livechat-title{ - font-weight: 800; - letter-spacing:.04em; - margin-bottom: 6px; -} - -.sw-livechat-body{ - display:flex; - flex-direction:column; - gap:3px; - margin-bottom: 8px; - opacity:.95; -} - -.sw-chat-line{ - font-size: 10px; - color:#c7e3ff; -} - -.sw-livechat-inputrow{ - display:flex; - gap:8px; - align-items:center; -} - -.sw-livechat-input{ - flex:1; - border-radius: 999px; - border: 1px solid rgba(90, 190, 255, 0.35); - background: rgba(3, 14, 32, 0.75); - color:#e8f5ff; - padding: 8px 10px; - font-size: 11px; - outline: none; -} - -.sw-livechat-post{ - border:none; - border-radius: 10px; - padding: 8px 12px; - background: rgba(56,189,248,0.22); - color:#e8f5ff; - font-weight: 900; - font-size: 11px; - cursor:pointer; -} - -/* ===== Template marker wrappers (pointers stay the same classes) ===== */ -.sw-template-mini-wrap{ - position: absolute; +/* Simple line from marker to card */ +.sw-overlay-line{ + position:absolute; + height: 2px; + background: rgba(56,189,248,0.35); + transform-origin: 0 50%; left: 0; top: 0; - transform: translate(-50%, calc(-100% - 12px)); -} - -.sw-expanded-shell{ - padding: 10px 12px; -} - -.sw-expanded-top{ - display:flex; - gap:10px; - align-items:flex-start; -} - -.sw-expanded-left{ - flex: 1; -} - -.sw-expanded-right{ - width: 150px; - min-width: 140px; - display:flex; - flex-direction:column; - gap:8px; - padding-top: 4px; -} - -.sw-watch-title{ - font-size: 11px; - font-weight: 800; - color:#bfdbfe; - text-transform: uppercase; - letter-spacing: .06em; -} - -.sw-watch-list{ - display:flex; - flex-direction:column; - gap:6px; -} - -.sw-watch-item{ - font-size: 11px; - color:#e8f5ff; - background: rgba(3, 14, 32, 0.75); - border: 1px solid rgba(90, 190, 255, 0.35); - border-radius: 10px; - padding: 6px 8px; -} - -.sw-watch-msg{ - opacity:.85; - margin-top:2px; - font-size: 10px; - color:#c7e3ff; -} - -.sw-add-feed-btn{ - margin-top: 2px; - border: 1px solid rgba(148,163,184,.7); - border-radius: 10px; - padding: 8px 10px; - background: rgba(5, 35, 70, 0.85); - color:#e8f5ff; - font-weight: 900; - font-size: 11px; - cursor:pointer; -} - -.sw-news-generated{ - margin-top: 10px; - padding: 8px 10px; - border-radius: 12px; - background: rgba(3, 14, 32, 0.75); - border: 1px solid rgba(90, 190, 255, 0.35); -} - -.sw-news-title{ - font-size: 12px; - font-weight: 900; - color:#e8f5ff; - margin-bottom: 2px; -} - -.sw-news-sub{ - font-size: 10px; - color:#9eb7ff; -} - -.sw-actions-row{ - margin-top: 8px; -} - -.sw-livechat{ - margin-top: 8px; -} - -.sw-livechat-title{ - font-weight: 800; - letter-spacing:.04em; - margin-bottom: 6px; -} - -.sw-livechat-body{ - display:flex; - flex-direction:column; - gap:3px; - margin-bottom: 8px; - opacity:.95; -} - -.sw-chat-line{ - font-size: 10px; - color:#c7e3ff; -} - -.sw-livechat-inputrow{ - display:flex; - gap:8px; - align-items:center; -} - -.sw-livechat-input{ - flex:1; - border-radius: 999px; - border: 1px solid rgba(90, 190, 255, 0.35); - background: rgba(3, 14, 32, 0.75); - color:#e8f5ff; - padding: 8px 10px; - font-size: 11px; - outline: none; -} - -.sw-livechat-post{ - border:none; - border-radius: 10px; - padding: 8px 12px; - background: rgba(56,189,248,0.22); - color:#e8f5ff; - font-weight: 900; - font-size: 11px; - cursor:pointer; -} - -/* ===== Template marker wrappers (pointers stay the same classes) ===== */ -.sw-template-mini-wrap{ - position: absolute; - left: 0; - top: 0; - transform: translate(-50%, calc(-100% - 12px)); + width: 0; + filter: drop-shadow(0 1px 2px rgba(0,0,0,.6)); } +/* ===== Expanded layout pieces (same as before) ===== */ .sw-expanded-shell{ padding: 10px 12px; } .sw-expanded-top{ @@ -511,156 +235,15 @@ cursor:pointer; } -/* ========================================================= - RESPONSIVE SIZING FIX - - Mini markers were too big (280x110 real size) - - Expanded card was overflowing on mobile - ========================================================= */ - -/* Mini template wrapper: keep pointer EXACTLY as-is, only scale the card */ -.sw-template-mini-wrap{ - /* was: translate(-50%, calc(-100% - 12px)) */ - transform: translate(-50%, calc(-100% - 12px)) scale(var(--sw-mini-scale, 0.72)); - transform-origin: bottom center; - will-change: transform; -} - -/* Expanded card: make it fit phone screens nicely */ -.post-pin--expanded .post-card{ - max-width: min(92vw, 380px); - width: auto; - max-height: min(72vh, 640px); - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -/* Layout in expanded sketch area */ -.sw-expanded-top{ - gap: 10px; -} - -/* Mobile tweaks */ +/* Mobile: keep overlay readable */ @media (max-width: 640px){ - /* Shrink mini markers even more on phones */ - .sw-template-mini-wrap{ - --sw-mini-scale: 0.58; + .sw-expanded-overlay-card{ + width: min(94vw, 360px); } - - /* Expanded: stack instead of side-by-side */ .sw-expanded-top{ flex-direction: column; } - - /* Right panel becomes horizontal strip (or you can hide it if you prefer) */ .sw-expanded-right{ - width: 100%; - min-width: 0; - flex-direction: row; - gap: 8px; - align-items: center; - overflow-x: auto; - padding-top: 0; - } - - .sw-watch-title{ - white-space: nowrap; - margin-right: 6px; - } - - .sw-watch-list{ - flex-direction: row; - gap: 8px; - } - - .sw-watch-item{ - min-width: 180px; - flex: 0 0 auto; - } - - .sw-add-feed-btn{ - flex: 0 0 auto; - white-space: nowrap; - } -} - - -/* SW_EXPANDED_OFFSET_FIX: lower expanded cards on phones (keep pointers unchanged) */ -@media (max-width: 640px){ - .post-pin--expanded .post-card{ - transform: translate(-50%, calc(-100% - 6px)); - } -} - - -/* SW_MOBILE_EXPANDED_TIGHTEN: make expanded marker card less tall on phones (no pointer change) */ -@media (max-width: 640px){ - .post-pin--expanded .post-card{ - padding: 8px 10px; - max-width: 300px; - } - .post-pin--expanded .post-card-main{ gap: 6px; margin-bottom: 6px; } - .post-pin--expanded .post-card-media{ width: 56px; height: 56px; border-radius: 10px; } - .post-pin--expanded .post-card-title{ font-size: 12px; line-height: 15px; } - .post-pin--expanded .post-card-body{ font-size: 11px; max-height: 56px; } -} - -/* SW_TEMPLATE_FULL_TIGHTEN: make template-full card less tall on phones */ -@media (max-width: 640px){ - .sw-template-full{ - transform: translate(-50%, calc(-100% - 14px)) scale(0.88); - transform-origin: bottom center; - } -} - -/* ===== MOBILE TUNING: expanded marker popup (template OR classic) ===== */ -@media (max-width: 640px){ - /* shrink the whole expanded marker a bit */ - .post-pin--expanded{ - transform: translate3d(0,0,0) scale(0.86); - transform-origin: bottom center; - } - - /* keep it inside screen */ - .post-pin--expanded .post-card{ - max-width: min(92vw, 340px) !important; - } - - /* title/body: prevent giant blocks */ - .post-pin--expanded .post-card-title{ font-size: 12px !important; line-height: 15px !important; } - .post-pin--expanded .post-card-body{ font-size: 11px !important; line-height: 14px !important; max-height: 54px !important; } - - /* buttons/footer area: tighter */ - .post-pin--expanded .post-card-footer{ gap: 5px !important; } - .post-pin--expanded .post-card-btn{ font-size: 10px !important; padding: 3px 7px !important; } -} - -/* === FINAL OVERRIDES (safe) === */ - -/* Keep pointers unchanged; only scale the mini template card */ -.sw-template-mini-wrap{ - transform: translate(-50%, calc(-100% - 12px)) scale(0.62) !important; - transform-origin: bottom center; -} - -@media (max-width: 640px){ - .sw-template-mini-wrap{ - transform: translate(-50%, calc(-100% - 12px)) scale(0.52) !important; - } -} - - -/* === SW MOBILE: make expanded popup shorter (no pointer change) === */ -@media (max-width: 640px){ - .post-pin--expanded .post-card{ - max-height: 58vh !important; - overflow: auto !important; - -webkit-overflow-scrolling: touch; - } - /* keep right panel from making it tall */ - .sw-expanded-right{ - display:none !important; - } - .sw-news-generated{ - margin-top: 8px; + display:none; } } diff --git a/src/styles/overlays.css b/src/styles/overlays.css index 92c15e0..8f1f221 100644 --- a/src/styles/overlays.css +++ b/src/styles/overlays.css @@ -15,8 +15,15 @@ display:flex; flex-direction:column; gap:.5rem; } -/* ✅ Sub-categories row MUST stay above the Sociowall overlap */ -.map-overlay-bottom { bottom: calc(3.2rem + var(--sw-below-overlap, 0px) + env(safe-area-inset-bottom)); left:50%; transform:translateX(-50%); display:flex; gap:.4rem; } +/* ✅ Sub-categories row MUST stay above the Sociowall overlap + ✅ And move DOWN by ~10px (less bottom padding) */ +.map-overlay-bottom{ + bottom: calc(2.6rem + var(--sw-below-overlap, 0px) + env(safe-area-inset-bottom)); + left:50%; + transform:translateX(-50%); + display:flex; + gap:.4rem; +} .map-overlay-myloc { right:.7rem; bottom:6rem; } @@ -31,7 +38,7 @@ background:#38bdf8; transform:translate(-50%,-50%); } .crosshair-aim::before{ width:70%; height:1px; } -.crosshair-aim::after{ width:1px; height:70%; } +.crosshair-aim::after{ width:1px; height:70px; } .create-post-panel { left:50%; bottom:20%; transform:translateX(-50%); diff --git a/src/styles/posts.css b/src/styles/posts.css index 5444240..c12ee8f 100644 --- a/src/styles/posts.css +++ b/src/styles/posts.css @@ -4,6 +4,13 @@ gap:.6rem; align-items:stretch; min-width:0; + flex-wrap: nowrap; /* ✅ keep side-by-side */ +} + +/* Small top nudge down (as requested) */ +.sociowall-panel, +.chat-panel{ + margin-top: 5px; /* ✅ descend 5px */ } .sociowall-panel{ @@ -48,7 +55,7 @@ cursor:pointer; } -/* SCALE the fixed 280px template so it never forces width */ +/* SCALE the fixed template so it never forces width */ .post-card .sw-wall-mini{ --sw-wall-scale: 0.86; transform: scale(var(--sw-wall-scale)); @@ -62,10 +69,12 @@ .status-text{ font-size:.72rem; opacity:.85; margin:.15rem 0; } .status-error{ color:#fecaca; } +/* ✅ Chat fixed column that can shrink a bit on narrow screens */ .chat-panel{ + flex: 0 0 190px; width: 190px; - min-width: 190px; - max-width: 220px; + min-width: 160px; /* allow shrink in portrait */ + max-width: min(220px, 42vw); min-height: 160px; background: rgba(15, 23, 42, 0.96); border-radius: 14px; @@ -98,9 +107,9 @@ .chat-users li{ display:flex; align-items:center; gap:.3rem; padding:.18rem .1rem; } .chat-users li::before{ content:"👤"; font-size:.72rem; opacity:.9; } -/* stack only very small */ -@media (max-width: 420px){ +/* Stack only ultra-ultra-small */ +@media (max-width: 340px){ .below-row{ flex-direction: column; } - .chat-panel{ width:100%; min-width:0; max-width:none; } + .chat-panel{ width:100%; min-width:0; max-width:none; flex: 1 1 auto; } .post-list{ max-height: 46vh; } }