Improve the worldmap display

This commit is contained in:
Arnaud 2024-10-11 11:17:48 +02:00
parent 29ceaea8c5
commit b33c79788d
No known key found for this signature in database
GPG Key ID: 69D6CE281FCAE663
7 changed files with 667 additions and 319 deletions

125
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@sentry/react": "^8.31.0",
"@tanstack/react-query": "^5.51.15",
"@tanstack/react-router": "^1.58.7",
"dotted-map": "^2.2.3",
"idb-keyval": "^6.2.1",
"lucide-react": "^0.445.0",
"react": "^18.3.1",
@ -39,47 +40,6 @@
"node": ">=18"
}
},
"../storybook": {
"name": "@codex-storage/marketplace-ui-components",
"version": "0.0.16",
"license": "MIT",
"dependencies": {
"lucide-react": "^0.441.0"
},
"devDependencies": {
"@chromatic-com/storybook": "^2.0.2",
"@storybook/addon-essentials": "^8.2.9",
"@storybook/addon-interactions": "^8.2.9",
"@storybook/addon-links": "^8.2.9",
"@storybook/addon-onboarding": "^8.2.9",
"@storybook/blocks": "^8.2.9",
"@storybook/react": "^8.2.9",
"@storybook/react-vite": "^8.2.9",
"@storybook/test": "^8.2.9",
"@typescript-eslint/eslint-plugin": "^8.6.0",
"@typescript-eslint/parser": "^8.0.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"glob": "^9.3.5",
"prettier": "^3.3.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"storybook": "^8.2.9",
"typescript": "5.5.2",
"vite-plugin-dts": "^4.0.3",
"vite-plugin-lib-inject-css": "^2.1.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@codex-storage/sdk-js": "^0.0.6",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
},
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
"dev": true,
@ -383,8 +343,28 @@
}
},
"node_modules/@codex-storage/marketplace-ui-components": {
"resolved": "../storybook",
"link": true
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.16.tgz",
"integrity": "sha512-49RQB/ld3EIZrFr/1GL7NB/cEI7TjnHRIBD3LJqZ2/ml+0gj//Mep85yV9Df1owiE2yyFh76bAeC8rUTo9cA/g==",
"dependencies": {
"lucide-react": "^0.441.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@codex-storage/sdk-js": "^0.0.6",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
},
"node_modules/@codex-storage/marketplace-ui-components/node_modules/lucide-react": {
"version": "0.441.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.441.0.tgz",
"integrity": "sha512-0vfExYtvSDhkC2lqg0zYVW1Uu9GsI4knuV9GP9by5z0Xhc4Zi5RejTxfz9LsjRmCyWVzHCJvxGKZWcRyvQCWVg==",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
}
},
"node_modules/@codex-storage/sdk-js": {
"version": "0.0.7",
@ -1595,6 +1575,37 @@
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@turf/boolean-point-in-polygon": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz",
"integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==",
"dependencies": {
"@turf/helpers": "^6.5.0",
"@turf/invariant": "^6.5.0"
},
"funding": {
"url": "https://opencollective.com/turf"
}
},
"node_modules/@turf/helpers": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz",
"integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==",
"funding": {
"url": "https://opencollective.com/turf"
}
},
"node_modules/@turf/invariant": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz",
"integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==",
"dependencies": {
"@turf/helpers": "^6.5.0"
},
"funding": {
"url": "https://opencollective.com/turf"
}
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"dev": true,
@ -2190,6 +2201,15 @@
"node": ">=6.0.0"
}
},
"node_modules/dotted-map": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/dotted-map/-/dotted-map-2.2.3.tgz",
"integrity": "sha512-8hyOOHHLLVCcCisM3yb9hqp+3bJ7TSMcr1SfrUw8Wxp5UMqih35jIvUyagweCooJbz/EH1nC9GGuPysh7+YlAg==",
"dependencies": {
"@turf/boolean-point-in-polygon": "^6.0.1",
"proj4": "^2.6.1"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"dev": true,
@ -2899,6 +2919,11 @@
"node": ">= 8"
}
},
"node_modules/mgrs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
"integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA=="
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@ -3119,6 +3144,15 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/proj4": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.12.1.tgz",
"integrity": "sha512-vmhP3hmstjXjzFwg8QXJwpoj4n7GVrXk3ZW3DzNK/Ur4cuwXq7ZiMXaWYvLYLQbX8n4MXgbwTr4lthOUZltBpA==",
"dependencies": {
"mgrs": "1.0.0",
"wkt-parser": "^1.3.3"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"dev": true,
@ -4019,6 +4053,11 @@
"node": ">= 8"
}
},
"node_modules/wkt-parser": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.3.tgz",
"integrity": "sha512-ZnV3yH8/k58ZPACOXeiHaMuXIiaTk1t0hSUVisbO0t4RjA5wPpUytcxeyiN2h+LZRrmuHIh/1UlrR9e7DHDvTw=="
},
"node_modules/word-wrap": {
"version": "1.2.5",
"dev": true,

View File

@ -29,6 +29,7 @@
"@sentry/react": "^8.31.0",
"@tanstack/react-query": "^5.51.15",
"@tanstack/react-router": "^1.58.7",
"dotted-map": "^2.2.3",
"idb-keyval": "^6.2.1",
"lucide-react": "^0.445.0",
"react": "^18.3.1",
@ -55,4 +56,4 @@
"author": "Codex team",
"readme": "README.md",
"license": "MIT"
}
}

View File

@ -0,0 +1,5 @@
.peerCountry {
display: flex;
align-items: center;
gap: 1rem;
}

View File

@ -1,7 +1,8 @@
import { Cell } from "@codex-storage/marketplace-ui-components";
import { useEffect, useState } from "react";
import { PeerPin } from "./types";
import { countriesCoordinates } from "./countries";
import { useQuery } from "@tanstack/react-query";
import "./PeerCountryCell.css";
export type Props = {
address: string;
@ -17,34 +18,56 @@ const getFlagEmoji = (countryCode: string) => {
};
export function PeerCountryCell({ address, onPinAdd }: Props) {
const [country, setCountry] = useState("");
const { data } = useQuery({
queryFn: () => {
const [ip] = address.split(":");
useEffect(() => {
const [ip] = address.split(":");
return fetch(import.meta.env.VITE_GEO_IP_URL + "/" + ip)
.then((res) => res.json())
.then((json) => {
const coordinate = countriesCoordinates.find(
(c) => c.iso === json.country
);
console.info(ip);
if (coordinate) {
onPinAdd({
lat: parseFloat(coordinate.lat),
lng: parseFloat(coordinate.lng),
});
}
fetch("https://api.country.is/" + ip)
.then((res) => res.json())
.then((json) => {
setCountry(json.country);
return coordinate;
});
},
queryKey: [address],
const coordinate = countriesCoordinates.find(
(c) => c.iso === json.country
);
// Enable only when the address exists
enabled: !!address,
if (coordinate) {
onPinAdd({
lat: parseFloat(coordinate.lat),
lng: parseFloat(coordinate.lng),
});
}
});
}, [address]);
// No need to retry because if the connection to the node
// is back again, all the queries will be invalidated.
retry: false,
// We can cache the data at Infinity because the relation between
// country and ip is fixed
staleTime: Infinity,
// Don't expect something new when coming back to the UI
refetchOnWindowFocus: false,
});
return (
<Cell>
{getFlagEmoji(country)} {address}
<div className="peerCountry">
{data ? (
<>
<span> {!!data && getFlagEmoji(data.iso)}</span>
<span>{data?.name}</span>
</>
) : (
<span>{address}</span>
)}
</div>
</Cell>
);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,41 @@
.peers-map,
.peers-table {
.peers-map {
max-width: 1000px;
margin: auto;
width: 100%;
}
.peers-table {
margin-top: 1rem;
width: 100%;
width: calc(100% - 4rem);
max-width: calc(1000px - 4rem);
}
.peers {
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 4rem;
padding-left: 2rem;
padding-right: 2rem;
}
.peers circle[fill="#d6ff79"] {
/* fill: yellow; */
animation: dash 3s linear infinite;
stroke: white;
stroke-width: 0.6px;
stroke-dasharray: 0.3;
}
@keyframes dash {
from {
stroke-dashoffset: 2;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes circleAn {
to {
/* stroke-dashoffset: 100px; */
}
}

View File

@ -53,7 +53,7 @@ export const Route = createFileRoute("/dashboard/peers")({
map.addPin({
lat: pin.lat,
lng: pin.lng,
svgOptions: { color: "#d6ff79", radius: 0.4 * quantity },
svgOptions: { color: "#d6ff79", radius: 0.8 * quantity },
})
);
@ -85,14 +85,18 @@ export const Route = createFileRoute("/dashboard/peers")({
)) || [];
return (
<>
<img
<div className="peers">
{/* <img
src={`data:image/svg+xml;utf8,${encodeURIComponent(svgMap)}`}
className="peers-map"
/>
/> */}
<div
className="peers-map"
dangerouslySetInnerHTML={{ __html: svgMap }}></div>
<Table headers={headers} rows={rows} className="peers-table" />
</>
</div>
);
},
});