diff --git a/components/dashboard/DottedMap.tsx b/components/dashboard/DottedMap.tsx new file mode 100644 index 0000000..dee2e67 --- /dev/null +++ b/components/dashboard/DottedMap.tsx @@ -0,0 +1,95 @@ +'use client' + +import { useMemo } from 'react' +import { createMap } from 'svg-dotted-map' +import { cn } from '@ciphera-net/ui' +import { countryCentroids } from '@/lib/country-centroids' + +interface DottedMapProps { + data: Array<{ country: string; pageviews: number }> + className?: string +} + +export default function DottedMap({ data, className }: DottedMapProps) { + const width = 150 + const height = 75 + const dotRadius = 0.2 + + const { points, addMarkers } = createMap({ width, height, mapSamples: 5000 }) + + const markers = useMemo(() => { + if (!data.length) return [] + + const max = Math.max(...data.map((d) => d.pageviews)) + if (max === 0) return [] + + return data + .filter((d) => d.country && d.country !== 'Unknown' && countryCentroids[d.country]) + .map((d) => ({ + lat: countryCentroids[d.country].lat, + lng: countryCentroids[d.country].lng, + size: 0.4 + (d.pageviews / max) * 0.8, + })) + }, [data]) + + const processedMarkers = addMarkers(markers) + + // Compute stagger helpers + const { xStep, yToRowIndex } = useMemo(() => { + const sorted = [...points].sort((a, b) => a.y - b.y || a.x - b.x) + const rowMap = new Map() + let step = 0 + let prevY = Number.NaN + let prevXInRow = Number.NaN + + for (const p of sorted) { + if (p.y !== prevY) { + prevY = p.y + prevXInRow = Number.NaN + if (!rowMap.has(p.y)) rowMap.set(p.y, rowMap.size) + } + if (!Number.isNaN(prevXInRow)) { + const delta = p.x - prevXInRow + if (delta > 0) step = step === 0 ? delta : Math.min(step, delta) + } + prevXInRow = p.x + } + + return { xStep: step || 1, yToRowIndex: rowMap } + }, [points]) + + return ( + + {points.map((point, index) => { + const rowIndex = yToRowIndex.get(point.y) ?? 0 + const offsetX = rowIndex % 2 === 1 ? xStep / 2 : 0 + return ( + + ) + })} + {processedMarkers.map((marker, index) => { + const rowIndex = yToRowIndex.get(marker.y) ?? 0 + const offsetX = rowIndex % 2 === 1 ? xStep / 2 : 0 + return ( + + ) + })} + + ) +} diff --git a/components/dashboard/Locations.tsx b/components/dashboard/Locations.tsx index 74f819e..faef66b 100644 --- a/components/dashboard/Locations.tsx +++ b/components/dashboard/Locations.tsx @@ -6,7 +6,7 @@ import { formatNumber } from '@ciphera-net/ui' import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard' import * as Flags from 'country-flag-icons/react/3x2' import iso3166 from 'iso-3166-2' -import WorldMap from './WorldMap' +import DottedMap from './DottedMap' import { Modal, GlobeIcon } from '@ciphera-net/ui' import { ListSkeleton } from '@/components/skeletons' import { ShieldCheck, Detective, Broadcast } from '@phosphor-icons/react' @@ -225,7 +225,7 @@ export default function Locations({ countries, cities, regions, geoDataLevel = '

{getDisabledMessage()}

) : activeTab === 'map' ? ( - hasData ? : ( + hasData ? : (
diff --git a/components/dashboard/WorldMap.tsx b/components/dashboard/WorldMap.tsx deleted file mode 100644 index 6602d51..0000000 --- a/components/dashboard/WorldMap.tsx +++ /dev/null @@ -1,110 +0,0 @@ -'use client' - -import React, { memo, useMemo, useState } from 'react' -import { ComposableMap, Geographies, Geography } from 'react-simple-maps' -import countries from 'i18n-iso-countries' -import enLocale from 'i18n-iso-countries/langs/en.json' -import { useTheme } from '@ciphera-net/ui' - -countries.registerLocale(enLocale) - -const geoUrl = "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json" - -interface WorldMapProps { - data: Array<{ country: string; pageviews: number }> -} - -const WorldMap = ({ data }: WorldMapProps) => { - const { resolvedTheme } = useTheme() - const [tooltipContent, setTooltipContent] = useState<{ content: string; x: number; y: number } | null>(null) - - const processedData = useMemo(() => { - const map = new Map() - let max = 0 - data.forEach(item => { - if (item.country === 'Unknown') return - // API returns 2 letter code. Convert to numeric (3 digits string) - const numericCode = countries.alpha2ToNumeric(item.country) - if (numericCode) { - map.set(numericCode, item.pageviews) - if (item.pageviews > max) max = item.pageviews - } - }) - return { map, max } - }, [data]) - - // Plausible-like colors based on provided SVG snippet - const isDark = resolvedTheme === 'dark' - const defaultFill = isDark ? "var(--color-neutral-800)" : "var(--color-neutral-100)" - const defaultStroke = isDark ? "var(--color-neutral-900)" : "#ffffff" - const brandOrange = "var(--color-brand-orange)" - - return ( -
- - - {({ geographies }) => - geographies - .filter(geo => geo.id !== "010") // Remove Antarctica - .map((geo) => { - const id = String(geo.id).padStart(3, '0') - const count = processedData.map.get(id) || 0 - const fillColor = count > 0 ? brandOrange : defaultFill - - return ( - { - const { name } = geo.properties - setTooltipContent({ - content: `${name}: ${count} visitors`, - x: evt.clientX, - y: evt.clientY - }) - }} - onMouseLeave={() => { - setTooltipContent(null) - }} - onMouseMove={(evt) => { - setTooltipContent(prev => prev ? { ...prev, x: evt.clientX, y: evt.clientY } : null) - }} - /> - ) - }) - } - - - {tooltipContent && ( -
- {tooltipContent.content} -
- )} -
- ) -} - -export default memo(WorldMap) diff --git a/lib/country-centroids.ts b/lib/country-centroids.ts new file mode 100644 index 0000000..79f73ee --- /dev/null +++ b/lib/country-centroids.ts @@ -0,0 +1,205 @@ +/** + * Country centroids: ISO 3166-1 alpha-2 → { lat, lng } + * Used to place markers on the DottedMap for visitor locations. + */ +export const countryCentroids: Record = { + AD: { lat: 42.5, lng: 1.5 }, + AE: { lat: 24.0, lng: 54.0 }, + AF: { lat: 33.0, lng: 65.0 }, + AG: { lat: 17.1, lng: -61.8 }, + AL: { lat: 41.0, lng: 20.0 }, + AM: { lat: 40.0, lng: 45.0 }, + AO: { lat: -12.5, lng: 18.5 }, + AR: { lat: -34.0, lng: -64.0 }, + AT: { lat: 47.3, lng: 13.3 }, + AU: { lat: -25.0, lng: 134.0 }, + AZ: { lat: 40.5, lng: 47.5 }, + BA: { lat: 44.0, lng: 17.8 }, + BB: { lat: 13.2, lng: -59.5 }, + BD: { lat: 24.0, lng: 90.0 }, + BE: { lat: 50.8, lng: 4.0 }, + BF: { lat: 13.0, lng: -1.5 }, + BG: { lat: 43.0, lng: 25.0 }, + BH: { lat: 26.0, lng: 50.6 }, + BI: { lat: -3.5, lng: 29.9 }, + BJ: { lat: 9.3, lng: 2.3 }, + BN: { lat: 4.5, lng: 114.7 }, + BO: { lat: -17.0, lng: -65.0 }, + BR: { lat: -10.0, lng: -55.0 }, + BS: { lat: 24.3, lng: -76.0 }, + BT: { lat: 27.5, lng: 90.5 }, + BW: { lat: -22.0, lng: 24.0 }, + BY: { lat: 53.0, lng: 28.0 }, + BZ: { lat: 17.3, lng: -88.8 }, + CA: { lat: 56.0, lng: -96.0 }, + CD: { lat: -3.0, lng: 23.0 }, + CF: { lat: 7.0, lng: 21.0 }, + CG: { lat: -1.0, lng: 15.0 }, + CH: { lat: 47.0, lng: 8.0 }, + CI: { lat: 8.0, lng: -5.5 }, + CL: { lat: -30.0, lng: -71.0 }, + CM: { lat: 6.0, lng: 12.5 }, + CN: { lat: 35.0, lng: 105.0 }, + CO: { lat: 4.0, lng: -72.0 }, + CR: { lat: 10.0, lng: -84.0 }, + CU: { lat: 22.0, lng: -79.5 }, + CV: { lat: 16.0, lng: -24.0 }, + CY: { lat: 35.0, lng: 33.0 }, + CZ: { lat: 49.8, lng: 15.5 }, + DE: { lat: 51.2, lng: 10.4 }, + DJ: { lat: 11.5, lng: 43.1 }, + DK: { lat: 56.0, lng: 10.0 }, + DM: { lat: 15.4, lng: -61.4 }, + DO: { lat: 19.0, lng: -70.7 }, + DZ: { lat: 28.0, lng: 3.0 }, + EC: { lat: -2.0, lng: -77.5 }, + EE: { lat: 59.0, lng: 26.0 }, + EG: { lat: 27.0, lng: 30.0 }, + ER: { lat: 15.0, lng: 39.0 }, + ES: { lat: 40.0, lng: -4.0 }, + ET: { lat: 8.0, lng: 38.0 }, + FI: { lat: 64.0, lng: 26.0 }, + FJ: { lat: -18.0, lng: 175.0 }, + FM: { lat: 6.9, lng: 158.2 }, + FR: { lat: 46.0, lng: 2.0 }, + GA: { lat: -1.0, lng: 11.8 }, + GB: { lat: 54.0, lng: -2.0 }, + GD: { lat: 12.1, lng: -61.7 }, + GE: { lat: 42.0, lng: 43.5 }, + GH: { lat: 8.0, lng: -2.0 }, + GM: { lat: 13.5, lng: -15.3 }, + GN: { lat: 11.0, lng: -10.0 }, + GQ: { lat: 2.0, lng: 10.0 }, + GR: { lat: 39.0, lng: 22.0 }, + GT: { lat: 15.5, lng: -90.3 }, + GW: { lat: 12.0, lng: -15.0 }, + GY: { lat: 5.0, lng: -59.0 }, + HK: { lat: 22.3, lng: 114.2 }, + HN: { lat: 15.0, lng: -86.5 }, + HR: { lat: 45.2, lng: 15.5 }, + HT: { lat: 19.0, lng: -72.4 }, + HU: { lat: 47.0, lng: 20.0 }, + ID: { lat: -5.0, lng: 120.0 }, + IE: { lat: 53.0, lng: -8.0 }, + IL: { lat: 31.5, lng: 34.8 }, + IN: { lat: 20.0, lng: 77.0 }, + IQ: { lat: 33.0, lng: 44.0 }, + IR: { lat: 32.0, lng: 53.0 }, + IS: { lat: 65.0, lng: -18.0 }, + IT: { lat: 42.8, lng: 12.8 }, + JM: { lat: 18.3, lng: -77.4 }, + JO: { lat: 31.0, lng: 36.0 }, + JP: { lat: 36.0, lng: 138.0 }, + KE: { lat: 1.0, lng: 38.0 }, + KG: { lat: 41.0, lng: 75.0 }, + KH: { lat: 13.0, lng: 105.0 }, + KI: { lat: 1.4, lng: 173.0 }, + KM: { lat: -12.2, lng: 44.2 }, + KN: { lat: 17.3, lng: -62.7 }, + KP: { lat: 40.0, lng: 127.0 }, + KR: { lat: 37.0, lng: 127.5 }, + KW: { lat: 29.5, lng: 47.8 }, + KZ: { lat: 48.0, lng: 68.0 }, + LA: { lat: 18.0, lng: 105.0 }, + LB: { lat: 33.9, lng: 35.8 }, + LC: { lat: 13.9, lng: -61.0 }, + LI: { lat: 47.2, lng: 9.5 }, + LK: { lat: 7.0, lng: 81.0 }, + LR: { lat: 6.5, lng: -9.5 }, + LS: { lat: -29.5, lng: 28.5 }, + LT: { lat: 56.0, lng: 24.0 }, + LU: { lat: 49.8, lng: 6.2 }, + LV: { lat: 57.0, lng: 25.0 }, + LY: { lat: 25.0, lng: 17.0 }, + MA: { lat: 32.0, lng: -5.0 }, + MC: { lat: 43.7, lng: 7.4 }, + MD: { lat: 47.0, lng: 29.0 }, + ME: { lat: 42.5, lng: 19.3 }, + MG: { lat: -20.0, lng: 47.0 }, + MK: { lat: 41.8, lng: 22.0 }, + ML: { lat: 17.0, lng: -4.0 }, + MM: { lat: 22.0, lng: 98.0 }, + MN: { lat: 46.0, lng: 105.0 }, + MO: { lat: 22.2, lng: 113.5 }, + MR: { lat: 20.0, lng: -12.0 }, + MT: { lat: 35.9, lng: 14.4 }, + MU: { lat: -20.3, lng: 57.6 }, + MV: { lat: 3.2, lng: 73.2 }, + MW: { lat: -13.5, lng: 34.0 }, + MX: { lat: 23.0, lng: -102.0 }, + MY: { lat: 2.5, lng: 112.5 }, + MZ: { lat: -18.3, lng: 35.0 }, + NA: { lat: -22.0, lng: 17.0 }, + NE: { lat: 16.0, lng: 8.0 }, + NG: { lat: 10.0, lng: 8.0 }, + NI: { lat: 13.0, lng: -85.0 }, + NL: { lat: 52.5, lng: 5.8 }, + NO: { lat: 62.0, lng: 10.0 }, + NP: { lat: 28.0, lng: 84.0 }, + NR: { lat: -0.5, lng: 166.9 }, + NZ: { lat: -41.0, lng: 174.0 }, + OM: { lat: 21.0, lng: 57.0 }, + PA: { lat: 9.0, lng: -80.0 }, + PE: { lat: -10.0, lng: -76.0 }, + PG: { lat: -6.0, lng: 147.0 }, + PH: { lat: 13.0, lng: 122.0 }, + PK: { lat: 30.0, lng: 70.0 }, + PL: { lat: 52.0, lng: 20.0 }, + PR: { lat: 18.3, lng: -66.6 }, + PS: { lat: 31.9, lng: 35.2 }, + PT: { lat: 39.5, lng: -8.0 }, + PW: { lat: 7.5, lng: 134.6 }, + PY: { lat: -23.0, lng: -58.0 }, + QA: { lat: 25.5, lng: 51.3 }, + RO: { lat: 46.0, lng: 25.0 }, + RS: { lat: 44.0, lng: 21.0 }, + RU: { lat: 60.0, lng: 100.0 }, + RW: { lat: -2.0, lng: 29.9 }, + SA: { lat: 24.0, lng: 45.0 }, + SB: { lat: -8.0, lng: 159.0 }, + SC: { lat: -4.7, lng: 55.5 }, + SD: { lat: 15.0, lng: 30.0 }, + SE: { lat: 62.0, lng: 15.0 }, + SG: { lat: 1.4, lng: 103.8 }, + SI: { lat: 46.1, lng: 15.0 }, + SK: { lat: 48.7, lng: 19.5 }, + SL: { lat: 8.5, lng: -11.8 }, + SM: { lat: 43.9, lng: 12.4 }, + SN: { lat: 14.5, lng: -14.5 }, + SO: { lat: 5.0, lng: 46.0 }, + SR: { lat: 4.0, lng: -56.0 }, + SS: { lat: 7.0, lng: 30.0 }, + ST: { lat: 1.0, lng: 7.0 }, + SV: { lat: 13.8, lng: -88.9 }, + SY: { lat: 35.0, lng: 38.0 }, + SZ: { lat: -26.5, lng: 31.5 }, + TD: { lat: 15.0, lng: 19.0 }, + TG: { lat: 8.0, lng: 1.2 }, + TH: { lat: 15.0, lng: 100.0 }, + TJ: { lat: 39.0, lng: 71.0 }, + TL: { lat: -8.8, lng: 126.0 }, + TM: { lat: 40.0, lng: 60.0 }, + TN: { lat: 34.0, lng: 9.0 }, + TO: { lat: -20.0, lng: -175.0 }, + TR: { lat: 39.0, lng: 35.0 }, + TT: { lat: 10.5, lng: -61.3 }, + TV: { lat: -8.0, lng: 178.0 }, + TW: { lat: 23.5, lng: 121.0 }, + TZ: { lat: -6.0, lng: 35.0 }, + UA: { lat: 49.0, lng: 32.0 }, + UG: { lat: 1.0, lng: 32.0 }, + US: { lat: 39.8, lng: -98.5 }, + UY: { lat: -33.0, lng: -56.0 }, + UZ: { lat: 41.0, lng: 64.0 }, + VA: { lat: 41.9, lng: 12.5 }, + VC: { lat: 13.3, lng: -61.2 }, + VE: { lat: 8.0, lng: -66.0 }, + VN: { lat: 16.0, lng: 108.0 }, + VU: { lat: -16.0, lng: 167.0 }, + WS: { lat: -13.8, lng: -172.1 }, + XK: { lat: 42.6, lng: 21.0 }, + YE: { lat: 15.0, lng: 48.0 }, + ZA: { lat: -29.0, lng: 24.0 }, + ZM: { lat: -15.0, lng: 28.0 }, + ZW: { lat: -20.0, lng: 30.0 }, +} diff --git a/package-lock.json b/package-lock.json index 482959d..1a32675 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "d3-scale": "^4.0.2", "framer-motion": "^12.23.26", "html-to-image": "^1.11.13", - "i18n-iso-countries": "^7.14.0", "iso-3166-2": "^1.0.0", "jspdf": "^4.0.0", "jspdf-autotable": "^5.0.7", @@ -27,9 +26,9 @@ "react": "^19.2.3", "react-dom": "^19.2.3", "react-markdown": "^10.1.0", - "react-simple-maps": "^3.0.0", "recharts": "^2.15.0", "sonner": "^2.0.7", + "svg-dotted-map": "^2.0.1", "swr": "^2.3.3", "xlsx": "^0.18.5" }, @@ -41,7 +40,6 @@ "@types/node": "^20.14.12", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "@types/react-simple-maps": "^3.0.6", "@vitejs/plugin-react": "^5.1.4", "autoprefixer": "^10.4.19", "eslint": "^9.39.2", @@ -4045,26 +4043,6 @@ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "license": "MIT" }, - "node_modules/@types/d3-geo": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-2.0.7.tgz", - "integrity": "sha512-RIXlxPdxvX+LAZFv+t78CuYpxYag4zuw9mZc+AwfB8tZpKU90rMEn2il2ADncmeZlb7nER9dDsJpRisA3lRvjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-interpolate": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.5.tgz", - "integrity": "sha512-UINE41RDaUMbulp+bxQMDnhOi51rh5lA2dG+dWZU0UY/IwQiG/u2x8TfnWYU9+xwGdXsJoAvrBYUEQl0r91atg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-color": "^2" - } - }, "node_modules/@types/d3-path": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", @@ -4080,13 +4058,6 @@ "@types/d3-time": "*" } }, - "node_modules/@types/d3-selection": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-2.0.5.tgz", - "integrity": "sha512-71BorcY0yXl12S7lvb01JdaN9TpeUHBDb4RRhSq8U8BEkX/nIk5p7Byho+ZRTsx5nYLMpAbY3qt5EhqFzfGJlw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/d3-shape": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", @@ -4108,17 +4079,6 @@ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, - "node_modules/@types/d3-zoom": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-2.0.7.tgz", - "integrity": "sha512-JWke4E8ZyrKUQ68ESTWSK16fVb0OYnaiJ+WXJRYxKLn4aXU0o4CLYxMWBEiouUfO3TTCoyroOrGPcBG6u1aAxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-interpolate": "^2", - "@types/d3-selection": "^2" - } - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -4170,13 +4130,6 @@ "@types/estree": "*" } }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -4257,19 +4210,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/react-simple-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/react-simple-maps/-/react-simple-maps-3.0.6.tgz", - "integrity": "sha512-hR01RXt6VvsE41FxDd+Bqm1PPGdKbYjCYVtCgh38YeBPt46z3SwmWPWu2L3EdCAP6bd6VYEgztucihRw1C0Klg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/d3-geo": "^2", - "@types/d3-zoom": "^2", - "@types/geojson": "*", - "@types/react": "*" - } - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -6320,28 +6260,6 @@ "node": ">=12" } }, - "node_modules/d3-dispatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", - "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-drag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", - "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dispatch": "1 - 2", - "d3-selection": "2" - } - }, - "node_modules/d3-ease": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", - "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==", - "license": "BSD-3-Clause" - }, "node_modules/d3-format": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", @@ -6351,30 +6269,6 @@ "node": ">=12" } }, - "node_modules/d3-geo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-2.0.2.tgz", - "integrity": "sha512-8pM1WGMLGFuhq9S+FpPURxic+gKzjluCD/CHTuUF3mXMeiCo0i6R0tO1s4+GArRFde96SLcW/kOFRjoAosPsFA==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^2.5.0" - } - }, - "node_modules/d3-geo/node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "license": "BSD-3-Clause", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-geo/node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", - "license": "ISC" - }, "node_modules/d3-interpolate": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", @@ -6412,13 +6306,6 @@ "node": ">=12" } }, - "node_modules/d3-selection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", - "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==", - "license": "BSD-3-Clause", - "peer": true - }, "node_modules/d3-shape": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", @@ -6455,71 +6342,6 @@ "node": ">=12" } }, - "node_modules/d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-transition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", - "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-color": "1 - 2", - "d3-dispatch": "1 - 2", - "d3-ease": "1 - 2", - "d3-interpolate": "1 - 2", - "d3-timer": "1 - 2" - }, - "peerDependencies": { - "d3-selection": "2" - } - }, - "node_modules/d3-transition/node_modules/d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-transition/node_modules/d3-interpolate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-color": "1 - 2" - } - }, - "node_modules/d3-zoom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", - "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dispatch": "1 - 2", - "d3-drag": "2", - "d3-interpolate": "1 - 2", - "d3-selection": "2", - "d3-transition": "2" - } - }, - "node_modules/d3-zoom/node_modules/d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-zoom/node_modules/d3-interpolate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-color": "1 - 2" - } - }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -6764,12 +6586,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/diacritics": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", - "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==", - "license": "MIT" - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -8387,18 +8203,6 @@ "node": ">= 14" } }, - "node_modules/i18n-iso-countries": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.14.0.tgz", - "integrity": "sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg==", - "license": "MIT", - "dependencies": { - "diacritics": "1.3.0" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", @@ -11140,23 +10944,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-simple-maps": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-simple-maps/-/react-simple-maps-3.0.0.tgz", - "integrity": "sha512-vKNFrvpPG8Vyfdjnz5Ne1N56rZlDfHXv5THNXOVZMqbX1rWZA48zQuYT03mx6PAKanqarJu/PDLgshIZAfHHqw==", - "license": "MIT", - "dependencies": { - "d3-geo": "^2.0.2", - "d3-selection": "^2.0.0", - "d3-zoom": "^2.0.0", - "topojson-client": "^3.1.0" - }, - "peerDependencies": { - "prop-types": "^15.7.2", - "react": "^16.8.0 || 17.x || 18.x", - "react-dom": "^16.8.0 || 17.x || 18.x" - } - }, "node_modules/react-smooth": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", @@ -12275,6 +12062,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-dotted-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/svg-dotted-map/-/svg-dotted-map-2.0.1.tgz", + "integrity": "sha512-eeI2XzIKm23gmSVr7ASTMNVJvxAvBfyL30tN33Y/DcZCJXvC/Br/cxQp9Ts6jDK/e7fkE5TpZStEfduPqPXrIw==" + }, "node_modules/svg-pathdata": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", @@ -12613,26 +12405,6 @@ "node": ">=8.0" } }, - "node_modules/topojson-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", - "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", - "license": "ISC", - "dependencies": { - "commander": "2" - }, - "bin": { - "topo2geo": "bin/topo2geo", - "topomerge": "bin/topomerge", - "topoquantize": "bin/topoquantize" - } - }, - "node_modules/topojson-client/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, "node_modules/tough-cookie": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", diff --git a/package.json b/package.json index cffe2d8..fced60c 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "d3-scale": "^4.0.2", "framer-motion": "^12.23.26", "html-to-image": "^1.11.13", - "i18n-iso-countries": "^7.14.0", "iso-3166-2": "^1.0.0", "jspdf": "^4.0.0", "jspdf-autotable": "^5.0.7", @@ -31,9 +30,9 @@ "react": "^19.2.3", "react-dom": "^19.2.3", "react-markdown": "^10.1.0", - "react-simple-maps": "^3.0.0", "recharts": "^2.15.0", "sonner": "^2.0.7", + "svg-dotted-map": "^2.0.1", "swr": "^2.3.3", "xlsx": "^0.18.5" }, @@ -51,7 +50,6 @@ "@types/node": "^20.14.12", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "@types/react-simple-maps": "^3.0.6", "@vitejs/plugin-react": "^5.1.4", "autoprefixer": "^10.4.19", "eslint": "^9.39.2",