@zekidev/ui 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +377 -565
- package/dist/leaflet-map-inner-SOHFKEYD.js +171 -0
- package/package.json +27 -17
- package/dist/index.cjs +0 -6141
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/sections/map/leaflet-map-inner.tsx
|
|
4
|
+
import "leaflet/dist/leaflet.css";
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
6
|
+
import L from "leaflet";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var OSM_ATTR = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
|
|
9
|
+
var CARTO_ATTR = `${OSM_ATTR} © <a href="https://carto.com/attributions">CARTO</a>`;
|
|
10
|
+
var ESRI_ATTR = "Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community";
|
|
11
|
+
var TILES = {
|
|
12
|
+
// OpenStreetMap
|
|
13
|
+
standard: {
|
|
14
|
+
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
15
|
+
attribution: OSM_ATTR
|
|
16
|
+
},
|
|
17
|
+
// CartoDB Positron — clean, minimal, ideal for data overlays
|
|
18
|
+
light: {
|
|
19
|
+
url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
20
|
+
attribution: CARTO_ATTR
|
|
21
|
+
},
|
|
22
|
+
// CartoDB Dark Matter
|
|
23
|
+
dark: {
|
|
24
|
+
url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
25
|
+
attribution: CARTO_ATTR
|
|
26
|
+
},
|
|
27
|
+
// CartoDB Voyager — colorful, modern
|
|
28
|
+
voyager: {
|
|
29
|
+
url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
|
|
30
|
+
attribution: CARTO_ATTR
|
|
31
|
+
},
|
|
32
|
+
// OpenTopoMap — topographic with elevation contours
|
|
33
|
+
topo: {
|
|
34
|
+
url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
|
|
35
|
+
attribution: `${OSM_ATTR}, <a href="https://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a>`,
|
|
36
|
+
maxZoom: 17
|
|
37
|
+
},
|
|
38
|
+
// ESRI World Imagery — satellite/aerial photography
|
|
39
|
+
satellite: {
|
|
40
|
+
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
|
41
|
+
attribution: ESRI_ATTR,
|
|
42
|
+
maxZoom: 18
|
|
43
|
+
},
|
|
44
|
+
// ESRI World Street Map — detailed street basemap
|
|
45
|
+
streets: {
|
|
46
|
+
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
|
|
47
|
+
attribution: ESRI_ATTR,
|
|
48
|
+
maxZoom: 18
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var markerIcon = new L.Icon({
|
|
52
|
+
iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
|
|
53
|
+
iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
|
|
54
|
+
shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
|
|
55
|
+
iconSize: [25, 41],
|
|
56
|
+
iconAnchor: [12, 41],
|
|
57
|
+
popupAnchor: [1, -34],
|
|
58
|
+
shadowSize: [41, 41]
|
|
59
|
+
});
|
|
60
|
+
async function geocodeAddress(address) {
|
|
61
|
+
try {
|
|
62
|
+
const res = await fetch(
|
|
63
|
+
`https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURIComponent(address)}`,
|
|
64
|
+
{ headers: { "Accept-Language": "en", "User-Agent": "LandingBuilder/1.0" } }
|
|
65
|
+
);
|
|
66
|
+
if (!res.ok) return null;
|
|
67
|
+
const data = await res.json();
|
|
68
|
+
if (!data.length) return null;
|
|
69
|
+
return [parseFloat(data[0].lat), parseFloat(data[0].lon)];
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function geocodeAll(locations) {
|
|
75
|
+
const result = [];
|
|
76
|
+
for (const loc of locations) {
|
|
77
|
+
if (loc.lat != null && loc.lng != null) {
|
|
78
|
+
result.push({ ...loc, coords: [loc.lat, loc.lng] });
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (loc.address) {
|
|
82
|
+
const coords = await geocodeAddress(loc.address);
|
|
83
|
+
if (coords) result.push({ ...loc, coords });
|
|
84
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
function buildPopup(loc) {
|
|
90
|
+
const parts = [];
|
|
91
|
+
parts.push(`<strong style="display:block;font-size:13px">${loc.name}</strong>`);
|
|
92
|
+
if (loc.address)
|
|
93
|
+
parts.push(`<span style="display:block;font-size:11px;color:#6b7280;margin-top:2px">${loc.address}</span>`);
|
|
94
|
+
if (loc.phone)
|
|
95
|
+
parts.push(`<span style="display:block;font-size:11px;margin-top:2px">${loc.phone}</span>`);
|
|
96
|
+
if (loc.hours)
|
|
97
|
+
parts.push(`<span style="display:block;font-size:11px;color:#6b7280;margin-top:2px">${loc.hours}</span>`);
|
|
98
|
+
if (loc.address)
|
|
99
|
+
parts.push(
|
|
100
|
+
`<a href="https://maps.google.com/?q=${encodeURIComponent(loc.address)}" target="_blank" rel="noopener noreferrer" style="display:block;font-size:11px;color:#2563eb;margin-top:4px">Ver en Google Maps \u2192</a>`
|
|
101
|
+
);
|
|
102
|
+
return parts.join("");
|
|
103
|
+
}
|
|
104
|
+
function LeafletMapInner({ locations, mapStyle = "standard", className }) {
|
|
105
|
+
const containerRef = useRef(null);
|
|
106
|
+
const mapRef = useRef(null);
|
|
107
|
+
const tileRef = useRef(null);
|
|
108
|
+
const [loading, setLoading] = useState(!!locations?.length);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!containerRef.current || mapRef.current) return;
|
|
111
|
+
const tile = TILES[mapStyle] ?? TILES.standard;
|
|
112
|
+
const map = L.map(containerRef.current, { scrollWheelZoom: false });
|
|
113
|
+
const tileLayer = L.tileLayer(tile.url, { attribution: tile.attribution, maxZoom: tile.maxZoom ?? 19 }).addTo(map);
|
|
114
|
+
map.setView([20, 0], 2);
|
|
115
|
+
mapRef.current = map;
|
|
116
|
+
tileRef.current = tileLayer;
|
|
117
|
+
return () => {
|
|
118
|
+
map.remove();
|
|
119
|
+
mapRef.current = null;
|
|
120
|
+
tileRef.current = null;
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (!mapRef.current) return;
|
|
125
|
+
const tile = TILES[mapStyle] ?? TILES.standard;
|
|
126
|
+
tileRef.current?.remove();
|
|
127
|
+
tileRef.current = L.tileLayer(tile.url, { attribution: tile.attribution, maxZoom: tile.maxZoom ?? 19 }).addTo(mapRef.current);
|
|
128
|
+
}, [mapStyle]);
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (!locations?.length) {
|
|
131
|
+
setLoading(false);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let cancelled = false;
|
|
135
|
+
setLoading(true);
|
|
136
|
+
geocodeAll(locations).then((geocoded) => {
|
|
137
|
+
if (cancelled || !mapRef.current) return;
|
|
138
|
+
mapRef.current.eachLayer((layer) => {
|
|
139
|
+
if (layer instanceof L.Marker) layer.remove();
|
|
140
|
+
});
|
|
141
|
+
geocoded.forEach((loc) => {
|
|
142
|
+
L.marker(loc.coords, { icon: markerIcon }).addTo(mapRef.current).bindPopup(buildPopup(loc));
|
|
143
|
+
});
|
|
144
|
+
if (geocoded.length === 1) {
|
|
145
|
+
mapRef.current.setView(geocoded[0].coords, 14);
|
|
146
|
+
} else if (geocoded.length > 1) {
|
|
147
|
+
mapRef.current.fitBounds(
|
|
148
|
+
geocoded.map((l) => l.coords),
|
|
149
|
+
{ padding: [48, 48] }
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
setLoading(false);
|
|
153
|
+
});
|
|
154
|
+
return () => {
|
|
155
|
+
cancelled = true;
|
|
156
|
+
};
|
|
157
|
+
}, [locations]);
|
|
158
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative ${className ?? ""}`, children: [
|
|
159
|
+
loading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-[1000] flex items-center justify-center bg-muted/80 rounded-xl", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-muted-foreground text-sm", children: [
|
|
160
|
+
/* @__PURE__ */ jsxs("svg", { className: "animate-spin h-6 w-6", viewBox: "0 0 24 24", fill: "none", children: [
|
|
161
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
162
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
163
|
+
] }),
|
|
164
|
+
"Geocoding addresses\u2026"
|
|
165
|
+
] }) }),
|
|
166
|
+
/* @__PURE__ */ jsx("div", { ref: containerRef, style: { height: "100%", width: "100%" } })
|
|
167
|
+
] });
|
|
168
|
+
}
|
|
169
|
+
export {
|
|
170
|
+
LeafletMapInner
|
|
171
|
+
};
|
package/package.json
CHANGED
|
@@ -1,26 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zekidev/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
-
"types": "./
|
|
8
|
-
"import": "./
|
|
9
|
-
"
|
|
10
|
-
"default": "./dist/index.js"
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"import": "./src/index.ts",
|
|
9
|
+
"default": "./src/index.ts"
|
|
11
10
|
},
|
|
12
11
|
"./styles": "./src/styles/globals.css",
|
|
13
12
|
"./tailwind-config": "./tailwind.config.ts"
|
|
14
13
|
},
|
|
15
|
-
"main": "./
|
|
16
|
-
"types": "./
|
|
14
|
+
"main": "./src/index.ts",
|
|
15
|
+
"types": "./src/index.ts",
|
|
17
16
|
"files": [
|
|
18
17
|
"dist",
|
|
19
18
|
"src/styles",
|
|
20
19
|
"tailwind.config.ts"
|
|
21
20
|
],
|
|
22
21
|
"publishConfig": {
|
|
23
|
-
"access": "public"
|
|
22
|
+
"access": "public",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./styles": "./src/styles/globals.css",
|
|
30
|
+
"./tailwind-config": "./tailwind.config.ts"
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup && tsc -p tsconfig.build.json",
|
|
38
|
+
"dev": "tsup --watch",
|
|
39
|
+
"type-check": "tsc --noEmit",
|
|
40
|
+
"lint": "eslint src --ext ts,tsx"
|
|
24
41
|
},
|
|
25
42
|
"dependencies": {
|
|
26
43
|
"@portabletext/react": "^3.0.0",
|
|
@@ -56,12 +73,5 @@
|
|
|
56
73
|
"tailwindcss": "^3.4.0",
|
|
57
74
|
"tsup": "^8.0.0",
|
|
58
75
|
"typescript": "^5.4.0"
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
"build": "tsup && tsc -p tsconfig.build.json",
|
|
62
|
-
"dev": "tsup --watch",
|
|
63
|
-
"type-check": "tsc --noEmit",
|
|
64
|
-
"lint": "eslint src --ext ts,tsx"
|
|
65
|
-
},
|
|
66
|
-
"module": "./dist/index.js"
|
|
67
|
-
}
|
|
76
|
+
}
|
|
77
|
+
}
|