Smooth filter transitions

This commit is contained in:
Your Name 2025-12-31 02:36:59 -05:00
parent 0647dc823b
commit c955b122e3
4 changed files with 75 additions and 14 deletions

View File

@ -33,7 +33,7 @@ export default function MapView({
onOpenIslands, onOpenIslands,
}) { }) {
const { authenticated, username, token, needsEmailVerification } = useAuth(); const { authenticated, username, token, needsEmailVerification } = useAuth();
const CLUSTERS_ENABLED = true; const CLUSTERS_ENABLED = false;
const HEATMAP_ENABLED = false; const HEATMAP_ENABLED = false;
const { containerRef, mapRef, markersRef, expandedElRef, viewParams, hasLastView } = const { containerRef, mapRef, markersRef, expandedElRef, viewParams, hasLastView } =
@ -53,6 +53,15 @@ export default function MapView({
const [subFilter, setSubFilter] = useState("All"); const [subFilter, setSubFilter] = useState("All");
const [mainNewsOnly, setMainNewsOnly] = useState(false); const [mainNewsOnly, setMainNewsOnly] = useState(false);
const debugEnabled = (() => {
try {
return typeof window !== "undefined" &&
new URLSearchParams(window.location.search || "").has("debug");
} catch {
return false;
}
})();
useEffect(() => { useEffect(() => {
try { try {
localStorage.setItem(TIME_FILTER_KEY, String(timeHours)); localStorage.setItem(TIME_FILTER_KEY, String(timeHours));
@ -157,7 +166,7 @@ export default function MapView({
[mapRef] [mapRef]
); );
const { status, visiblePosts, loadingPosts, loadError, handleIncomingPost, handlePostUpdate } = const { status, debugStatus, visiblePosts, loadingPosts, loadError, handleIncomingPost, handlePostUpdate } =
usePostsEngine({ usePostsEngine({
theme, theme,
mapRef, mapRef,
@ -176,6 +185,7 @@ export default function MapView({
onAutoWidenTimeFilter: () => setTimeHours(336), onAutoWidenTimeFilter: () => setTimeHours(336),
onSelectPost, onSelectPost,
username, username,
debugEnabled,
}); });
const [isCreating, setIsCreating] = useState(false); const [isCreating, setIsCreating] = useState(false);
@ -324,15 +334,24 @@ export default function MapView({
if (queryPostRef.current) return; if (queryPostRef.current) return;
const qs = new URLSearchParams(window.location.search || ""); const qs = new URLSearchParams(window.location.search || "");
let idRaw = qs.get("post_id") || qs.get("id") || qs.get("p"); let idRaw = qs.get("post_id") || qs.get("id") || qs.get("p");
let wasSharedLink = false;
if (!idRaw) { if (!idRaw) {
const path = (window.location.pathname || "").trim(); const path = (window.location.pathname || "").trim();
const m = path.match(/^\/p\/(\d+)/); const m = path.match(/^\/p\/(\d+)/);
if (m && m[1]) { if (m && m[1]) {
idRaw = m[1]; idRaw = m[1];
wasSharedLink = true;
// Clean URL immediately - no post_id in URL, just stay on root
try { try {
window.history.replaceState(null, "", `/?post_id=${m[1]}`); window.history.replaceState(null, "", "/");
} catch {} } catch {}
} }
} else {
// If arrived with ?post_id=123, also clean it
wasSharedLink = true;
try {
window.history.replaceState(null, "", "/");
} catch {}
} }
if (!idRaw) return; if (!idRaw) return;
queryPostRef.current = true; queryPostRef.current = true;
@ -1211,6 +1230,47 @@ export default function MapView({
<div className="map-stage" ref={stageRef}> <div className="map-stage" ref={stageRef}>
<div ref={containerRef} className="map-container" /> <div ref={containerRef} className="map-container" />
{status && <div className="map-status">{status}</div>} {status && <div className="map-status">{status}</div>}
{debugEnabled && (
<>
<div
className="sw-debug-banner"
style={{
position: "fixed",
top: 62,
left: 8,
zIndex: 99999,
padding: "6px 8px",
background: "rgba(0,0,0,0.8)",
color: "#fff",
fontSize: 12,
borderRadius: 6,
maxWidth: "92vw",
pointerEvents: "none",
}}
>
{debugStatus || "debug active"}
</div>
<div
style={{
position: "fixed",
bottom: 0,
left: 0,
right: 0,
zIndex: 99999,
background: "#ffea00",
color: "#111",
fontWeight: 700,
fontSize: 14,
textAlign: "center",
padding: "4px 0",
letterSpacing: "0.08em",
pointerEvents: "none",
}}
>
DEV DEBUG
</div>
</>
)}
{/* TOP: Search avec suggestions intelligentes */} {/* TOP: Search avec suggestions intelligentes */}
<div className="map-overlay map-overlay-top"> <div className="map-overlay map-overlay-top">

View File

@ -372,6 +372,7 @@ export function usePostsEngine({
onAutoWidenTimeFilter, onAutoWidenTimeFilter,
onSelectPost, onSelectPost,
username, username,
debugEnabled = false,
theme = "blue", theme = "blue",
}) { }) {
const allPostsRef = useRef([]); const allPostsRef = useRef([]);
@ -707,6 +708,7 @@ export function usePostsEngine({
); );
const [status, setStatus] = useState(""); const [status, setStatus] = useState("");
const [debugStatus, setDebugStatus] = useState("debug active");
const [visiblePosts, setVisiblePosts] = useState([]); const [visiblePosts, setVisiblePosts] = useState([]);
const [loadingPosts, setLoadingPosts] = useState(false); const [loadingPosts, setLoadingPosts] = useState(false);
const [loadError, setLoadError] = useState(""); const [loadError, setLoadError] = useState("");
@ -735,12 +737,6 @@ export function usePostsEngine({
fullCardPosts = prioritized.fullCardPosts; fullCardPosts = prioritized.fullCardPosts;
simpleMarkerPosts = prioritized.simpleMarkerPosts; simpleMarkerPosts = prioritized.simpleMarkerPosts;
console.log('[usePostsEngine] Prioritized:', {
total: visible.length,
fullCards: fullCardPosts.length,
simpleMarkers: simpleMarkerPosts.length
});
// Combine both types for "wanted" tracking // Combine both types for "wanted" tracking
const wanted = new Map(); const wanted = new Map();
for (const post of visible) { for (const post of visible) {
@ -823,8 +819,7 @@ export function usePostsEngine({
replacePoolRef.current = true; replacePoolRef.current = true;
pendingFilterRef.current = `${mainFilter}|${subFilter}|${timeHours}`; pendingFilterRef.current = `${mainFilter}|${subFilter}|${timeHours}`;
allPostsRef.current = []; allPostsRef.current = [];
setVisiblePosts([]); autoWidenRef.current = false; // Reset auto-widen when user manually changes filter
syncMarkers([]);
if (map && clustersEnabled && heatmapEnabled) { if (map && clustersEnabled && heatmapEnabled) {
updateClusterAreas(map, []); updateClusterAreas(map, []);
} }
@ -836,7 +831,7 @@ export function usePostsEngine({
} catch {} } catch {}
}, 60); }, 60);
} }
}, [mainFilter, subFilter, timeHours, mapRef, syncMarkers, clustersEnabled, heatmapEnabled, updateClusterAreas]); }, [mainFilter, subFilter, timeHours, mapRef, clustersEnabled, heatmapEnabled, updateClusterAreas]);
const computeVisible = useCallback( const computeVisible = useCallback(
(tf) => { (tf) => {
@ -1104,6 +1099,11 @@ export function usePostsEngine({
// Smooth update: sync markers/clusters + wall without clearing everything // Smooth update: sync markers/clusters + wall without clearing everything
refreshVisibleAndMarkers(timeHours); refreshVisibleAndMarkers(timeHours);
const visible = computeVisible(timeHours); const visible = computeVisible(timeHours);
if (debugEnabled) {
const count = Array.isArray(newPosts) ? newPosts.length : 0;
const q = (searchQuery || "").trim();
setDebugStatus(`tf:${timeHours || 0} fetched:${count} visible:${visible.length}${q ? ` q:${q}` : ""}`);
}
const now = Date.now(); const now = Date.now();
if (now - analyticsDebounceRef.current > 4000) { if (now - analyticsDebounceRef.current > 4000) {
analyticsDebounceRef.current = now; analyticsDebounceRef.current = now;
@ -1387,5 +1387,5 @@ export function usePostsEngine({
[mapRef, refreshVisibleAndMarkers, timeHours] [mapRef, refreshVisibleAndMarkers, timeHours]
); );
return { status, visiblePosts, loadingPosts, loadError, handleIncomingPost, handlePostUpdate }; return { status, debugStatus, visiblePosts, loadingPosts, loadError, handleIncomingPost, handlePostUpdate };
} }

View File

@ -121,4 +121,4 @@
} }
/* Espace pour les bulles */ /* Espace pour les bulles */
.below-stage { padding-bottom: 70px; } .below-stage { padding-bottom: 70px; }

View File

@ -48,6 +48,7 @@
position:relative; position:relative;
z-index:25; z-index:25;
padding: .25rem .7rem 1.0rem; padding: .25rem .7rem 1.0rem;
transition: opacity 320ms ease, filter 320ms ease;
} }
.below-row{ .below-row{