diff --git a/src/app/globals.css b/src/app/globals.css
index 88cb57b..2553654 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -184,3 +184,36 @@
.supplier-map-label::before {
display: none;
}
+
+.dark .supplier-map-label {
+ background: rgba(15, 23, 42, 0.94);
+ color: #f8fafc;
+ box-shadow: 0 8px 18px rgba(0, 0, 0, 0.34);
+}
+
+.leaflet-container {
+ z-index: 0;
+}
+
+.leaflet-pane,
+.leaflet-top,
+.leaflet-bottom {
+ z-index: 10;
+}
+
+.dark .leaflet-control-zoom a,
+.dark .leaflet-control-attribution,
+.dark .leaflet-popup-content-wrapper,
+.dark .leaflet-popup-tip {
+ background: var(--card);
+ color: var(--card-foreground);
+}
+
+.dark .leaflet-control-zoom a {
+ border-color: var(--border);
+}
+
+.dark .leaflet-control-attribution a,
+.dark .leaflet-popup-content a {
+ color: var(--primary);
+}
diff --git a/src/components/supplier-map.tsx b/src/components/supplier-map.tsx
index 258011b..8021e52 100644
--- a/src/components/supplier-map.tsx
+++ b/src/components/supplier-map.tsx
@@ -3,13 +3,15 @@
import { useEffect, useMemo, useState } from "react";
import L from "leaflet";
import { MapContainer, Marker, Popup, TileLayer, Tooltip, Circle, useMap, useMapEvents } from "react-leaflet";
+import { useTheme } from "next-themes";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
-import { Mail, MapPin, Phone, RefreshCw, Search, Tag } from "lucide-react";
+import { Maximize2, Mail, MapPin, Minimize2, Move, Phone, RefreshCw, Search, Tag } from "lucide-react";
import { toast } from "sonner";
import { getAllSuppliers } from "@/lib/pb-helpers";
+import getPocketBase from "@/lib/pocketbase";
import type { Supplier } from "@/lib/types";
type SupplierPoint = Supplier & {
@@ -27,8 +29,12 @@ type SupplierCluster = {
const DEFAULT_CENTER: [number, number] = [-26.2041, 28.0473];
const CLUSTER_DISTANCE_KM = 8;
const CLUSTER_ZOOM_BREAKPOINT = 12;
-const LABEL_ZOOM_BREAKPOINT = 13;
+const LABEL_ZOOM_BREAKPOINT = 12;
const CLUSTER_COLORS = ["#1B76BB", "#E64B4B", "#F4B842", "#169B62", "#7C3AED", "#EA580C", "#0F766E"];
+const LIGHT_TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
+const DARK_TILE_URL = "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png";
+const LIGHT_TILE_ATTRIBUTION = '© OpenStreetMap';
+const DARK_TILE_ATTRIBUTION = '© OpenStreetMap © CARTO';
function parseCoordinates(value?: string): [number, number] | null {
if (!value) return null;
@@ -119,7 +125,13 @@ function buildClusters(points: SupplierPoint[], distanceKmLimit = CLUSTER_DISTAN
return clusters;
}
-function ZoomWatcher({ onZoomChange }: { onZoomChange: (zoom: number) => void }) {
+function MapWatcher({ isFullscreen, onZoomChange }: { isFullscreen: boolean; onZoomChange: (zoom: number) => void }) {
+ const map = useMap();
+
+ useEffect(() => {
+ window.setTimeout(() => map.invalidateSize(), 180);
+ }, [isFullscreen, map]);
+
useMapEvents({
zoomend: (event) => onZoomChange(event.target.getZoom()),
});
@@ -136,7 +148,7 @@ function ClusterMarker({ cluster }: { cluster: SupplierCluster }) {
return (
{count} suppliers in this area {supplier.suppliername || "Unnamed supplier"} {supplier.supplieraddress} Zoom in to see {count - 12} more.
{supplier.suppliername || "Unnamed supplier"}
@@ -174,15 +176,24 @@ function SupplierPopup({ supplier }: { supplier: SupplierPoint }) { {supplier.suppliernumber &&Phone: {supplier.suppliernumber}
} {supplier.email &&Email: {supplier.email}
} {supplier.supply_tags &&Tags: {supplier.supply_tags}
} + {editMode && ( ++ Drag this marker to correct its saved location. +
+ )}{clusters.length}
-Grouped within {CLUSTER_DISTANCE_KM}km
+Grouped within {clusterDistanceKm}km at this zoom