Map loading: replace fuzzy ghost-pin blobs with a clean top bar + pill
The cold-start loading state scattered fuzzy pink "ghost pins" across the map
(the same blob look that was disliked on real markers) which read as broken.
Removed MapSkeletonPins entirely.
New loading state, per the agreed plan (keep the map instant, never cover it):
- A slim animated top progress bar ("ss-loadbar" sweep on a faint track) that
sits above the map while spots stream in.
- During a genuine cold start (no markers yet), a small labeled "Loading spots"
pill with a spinner near the top — honest about what's happening (querying
relays), not fake pins on the ocean.
- Reduced-motion respected (bar becomes static).
The map itself is untouched and still renders immediately; only the placeholder
changed. Dropped the now-unused MapSkeletonPins import. Build clean, no console
errors.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
a40c86e655
commit
46fbb0df43
2 changed files with 35 additions and 10 deletions
|
|
@ -395,6 +395,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Indeterminate top loading bar for the map ("Loading spots"). A short segment
|
||||||
|
sweeps left→right on a faint track, so it reads as active work without
|
||||||
|
pretending to know real progress. Disabled under reduced-motion. */
|
||||||
|
@keyframes ssLoadBar {
|
||||||
|
0% { transform: translateX(-120%); }
|
||||||
|
100% { transform: translateX(420%); }
|
||||||
|
}
|
||||||
|
.ss-loadbar {
|
||||||
|
animation: ssLoadBar 1.1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.ss-loadbar { animation: none; width: 100%; opacity: 0.7; }
|
||||||
|
}
|
||||||
|
|
||||||
.animate-fadeIn {
|
.animate-fadeIn {
|
||||||
animation: fadeIn 0.4s ease-out forwards;
|
animation: fadeIn 0.4s ease-out forwards;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ import { useToast } from '@/hooks/useToast';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { getCurrentPosition, GeolocationError, isNativeGeolocation } from '@/lib/geolocation';
|
import { getCurrentPosition, GeolocationError, isNativeGeolocation } from '@/lib/geolocation';
|
||||||
import { getLastLocation } from '@/lib/lastLocation';
|
import { getLastLocation } from '@/lib/lastLocation';
|
||||||
import { MapSkeletonPins } from '@/components/MapSkeletonPins';
|
|
||||||
|
|
||||||
|
|
||||||
type ViewMode = 'map' | 'list';
|
type ViewMode = 'map' | 'list';
|
||||||
|
|
@ -1615,17 +1614,29 @@ export default function MapPage() {
|
||||||
userLocation={userLocation ? { lat: userLocation.lat, lng: userLocation.lon } : null}
|
userLocation={userLocation ? { lat: userLocation.lat, lng: userLocation.lon } : null}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
{/* Loading indicator — slim top edge bar */}
|
{/* Loading indicator — a slim, honest top bar. The map stays
|
||||||
|
visible underneath and spots stream in; we NEVER cover the map
|
||||||
|
with fake placeholder pins. An animated sweep sits on top of a
|
||||||
|
faint track so it reads as "working", plus a small labeled pill
|
||||||
|
during a genuine cold start (no markers yet) so the user knows
|
||||||
|
we're talking to the relays. */}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute top-0 left-0 right-0 z-[1000] h-0.5">
|
<>
|
||||||
<div className="h-full bg-gradient-to-r from-[#ff0040] via-[#ff6600] to-[#ccff00] animate-pulse" />
|
<div className="absolute top-0 left-0 right-0 z-[1001] h-[3px] overflow-hidden bg-white/5">
|
||||||
|
<div className="ss-loadbar h-full w-1/3 bg-gradient-to-r from-[#ff0040] via-[#ff6600] to-[#ccff00]" />
|
||||||
|
</div>
|
||||||
|
{mapSpots.length === 0 && (
|
||||||
|
<div className="absolute top-3 left-1/2 -translate-x-1/2 z-[1001]">
|
||||||
|
<div className="flex items-center gap-2 rounded-full bg-black/60 px-3.5 py-1.5 backdrop-blur-md ring-1 ring-white/10 shadow-lg">
|
||||||
|
<span className="h-3.5 w-3.5 rounded-full border-2 border-[#ccff00]/30 border-t-[#ccff00] animate-spin" />
|
||||||
|
<span className="font-mono text-[10px] uppercase tracking-[0.22em] text-white/70">
|
||||||
|
Loading spots
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
{/* Cold-start skeleton: only while genuinely loading with NO
|
)}
|
||||||
markers on the map yet. The instant real (or cached) spots
|
|
||||||
render, mapSpots.length > 0 and this disappears — no blank map. */}
|
|
||||||
{isLoading && mapSpots.length === 0 && <MapSkeletonPins />}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue