mega-plant/components/PlantMapLoader.tsx
David 3cd3025116 Map: dark tiles from Esri, because CARTO retired keyless access
CARTO now answers every keyless basemap request with HTTP 200 and a valid
256x256 PNG that is just a dark square watermarked "API KEY REQUIRED".
Leaflet accepts it as a tile and paints it, so the map silently filled with
the warning — no console error, nothing in the network tab to catch it.

Esri's World Dark Gray Canvas is a genuine dark basemap and needs no key.
Its ArcGIS REST service orders the tile path {z}/{y}/{x}, the reverse of
what Leaflet knows how to substitute, so a getTileUrl override is the whole
fix. react-leaflet always instantiates Leaflet's own TileLayer, so the
custom class is added to the map directly and torn down on unmount rather
than passed as a prop.
2026-10-03 09:20:24 +02:00

43 lines
1.9 KiB
TypeScript

"use client";
import dynamic from "next/dynamic";
import { Loader2, MapPinned } from "lucide-react";
/**
* Leaflet reads `window` at module scope, so it cannot be evaluated during SSR.
* `next/dynamic` with `ssr: false` keeps it out of the server bundle entirely —
* this file is the client boundary that makes that possible (App Router only
* allows `ssr: false` inside a Client Component).
*/
const PlantMap = dynamic(() => import("./PlantMap").then((m) => m.PlantMap), {
ssr: false,
loading: () => <MapSkeleton />,
});
function MapSkeleton() {
return (
<div className="grid lg:grid-cols-[minmax(0,1fr)_340px] gap-4 items-start">
<div className="relative rounded-2xl overflow-hidden border border-gray-200 dark:border-white/5 shadow-sm bg-gray-100 dark:bg-surface h-[52vh] min-h-[320px] lg:h-[calc(100vh-15rem)] lg:min-h-[560px] grid place-items-center">
<div className="text-center">
<Loader2 className="w-6 h-6 mx-auto text-[#30638E] animate-spin" />
<p className="mt-2 text-xs text-gray-500 dark:text-gray-400">Loading map…</p>
</div>
</div>
<div className="rounded-2xl border border-gray-200 dark:border-white/5 bg-white dark:bg-surface shadow-sm overflow-hidden">
<div className="p-4 border-b border-gray-100 dark:border-white/5">
<div className="h-4 w-20 rounded bg-gray-200 dark:bg-white/10 animate-pulse" />
<div className="mt-3 h-11 rounded-lg bg-gray-100 dark:bg-white/5 animate-pulse" />
</div>
<div className="p-4 space-y-3">
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="h-9 rounded bg-gray-100 dark:bg-white/5 animate-pulse" />
))}
</div>
</div>
</div>
);
}
export function PlantMapLoader(props: React.ComponentProps<typeof import("./PlantMap").PlantMap>) {
return <PlantMap {...props} />;
}