From 9309f42ced7cd0cdff93ffd0435a39f35155912e Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Wed, 1 Jun 2022 10:46:38 +0800 Subject: [PATCH] app updates --- app/package-lock.json | 862 ++++++++++++++++++++++++++++++++++++- app/package.json | 11 +- app/src/App.tsx | 22 +- app/src/Inspector.tsx | 291 ++++++++++++- app/src/LeafletMap.tsx | 8 +- app/src/Loader.tsx | 207 ++++++++- app/src/MaplibreMap.tsx | 16 +- app/src/Start.tsx | 57 ++- app/src/main.tsx | 10 +- app/src/stitches.config.ts | 10 +- 10 files changed, 1420 insertions(+), 74 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index 58af48e..752fd5a 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -9,8 +9,13 @@ "version": "0.0.0", "dependencies": { "@mapbox/vector-tile": "^1.3.1", + "@radix-ui/react-dialog": "^0.1.7", + "@radix-ui/react-icons": "^1.1.0", "@radix-ui/react-label": "^0.1.5", + "@radix-ui/react-toolbar": "^0.1.5", "@stitches/react": "^1.2.8", + "d3-path": "^3.0.1", + "d3-scale-chromatic": "^3.0.0", "leaflet": "^1.8.0", "maplibre-gl": "^2.1.9", "pako": "^2.0.4", @@ -21,8 +26,11 @@ "react-dropzone": "^14.1.1" }, "devDependencies": { + "@types/d3-path": "^3.0.0", + "@types/d3-scale-chromatic": "^3.0.0", "@types/leaflet": "^1.7.9", "@types/mapbox__vector-tile": "^1.3.0", + "@types/pako": "^1.0.3", "@types/pbf": "^3.0.2", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", @@ -539,6 +547,29 @@ "node": ">=6.0.0" } }, + "node_modules/@radix-ui/primitive": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-0.1.0.tgz", + "integrity": "sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz", + "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-slot": "0.1.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz", @@ -561,6 +592,82 @@ "react": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-dialog": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-0.1.7.tgz", + "integrity": "sha512-jXt8srGhHBRvEr9jhEAiwwJzWCWZoGRJ030aC9ja/gkRJbZdy0iD3FwXf+Ff4RtsZyLUMHW7VUwFOlz3Ixe1Vw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-dismissable-layer": "0.1.5", + "@radix-ui/react-focus-guards": "0.1.0", + "@radix-ui/react-focus-scope": "0.1.4", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-portal": "0.1.4", + "@radix-ui/react-presence": "0.1.2", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-slot": "0.1.2", + "@radix-ui/react-use-controllable-state": "0.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "^2.4.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0", + "react-dom": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz", + "integrity": "sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-body-pointer-events": "0.1.1", + "@radix-ui/react-use-callback-ref": "0.1.0", + "@radix-ui/react-use-escape-keydown": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz", + "integrity": "sha512-kRx/swAjEfBpQ3ns7J3H4uxpXuWCqN7MpALiSDOXiyo2vkWv0L9sxvbpZeTulINuE3CGMzicVMuNc/VWXjFKOg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz", + "integrity": "sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-callback-ref": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-icons": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.1.0.tgz", + "integrity": "sha512-nhctV9YKN8G4HfkS3p03ml+osTBDMGKImaAJTm666hymtaWEgIPiqL7F53ivDqIO4A+20ERwUiiKJ8h3XK7uAg==", + "peerDependencies": { + "react": "^16.x || ^17.x" + } + }, "node_modules/@radix-ui/react-id": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", @@ -588,6 +695,33 @@ "react": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-portal": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz", + "integrity": "sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0", + "react-dom": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-0.1.2.tgz", + "integrity": "sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, "node_modules/@radix-ui/react-primitive": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", @@ -600,6 +734,37 @@ "react": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz", + "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-collection": "0.1.4", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-callback-ref": "0.1.0", + "@radix-ui/react-use-controllable-state": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-0.1.4.tgz", + "integrity": "sha512-ct2qE072ydvMyFiPwgO8xGE4iLGR9BsSk2tIan23TYSiNTeQ89anzkuax5vNGjey0el2vnwUcReFS0Gy7Lk2VQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "0.1.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-slot": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-0.1.2.tgz", @@ -612,6 +777,101 @@ "react": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-toggle": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz", + "integrity": "sha512-gxUq6NgMc4ChV8VJnwdYqueeoblspwXHAexYo+jM9N2hFLbI1C587jLjdTHzIcUa9q68Xaw4jtiImWDOokEhRw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-controllable-state": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz", + "integrity": "sha512-Yp14wFiqe00azF+sG5CCJz4JGOP/f5Jj+CxLlZCmMpG5qhVTWeaeG4YH6pvX4KL41fS8x9FAaLb8wW9y01o67g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-roving-focus": "0.1.5", + "@radix-ui/react-toggle": "0.1.4", + "@radix-ui/react-use-controllable-state": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-0.1.5.tgz", + "integrity": "sha512-k9ccGglui1tyR+YiYLty1oI+VOO7C4zCNAbR3sTT5FC0qflpBxaswJnOSQgapDIwl9tB/Al69mKUS3TFZ7WsQw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-roving-focus": "0.1.5", + "@radix-ui/react-separator": "0.1.4", + "@radix-ui/react-toggle-group": "0.1.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-use-body-pointer-events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz", + "integrity": "sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.1.0.tgz", + "integrity": "sha512-Va041McOFFl+aV+sejvl0BS2aeHx86ND9X/rVFmEFQKTXCp6xgUK0NGUAGcgBlIjnJSbMYPGEk1xKSSlVcN2Aw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz", + "integrity": "sha512-zv7CX/PgsRl46a52Tl45TwqwVJdmqnlQEQhaYMz/yBOD2sx2gCkCFSoF/z9mpnYWmS6DTLNTg5lIps3fV6EnXg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.1.0.tgz", + "integrity": "sha512-tDLZbTGFmvXaazUXXv8kYbiCcbAE8yKgng9s95d8fCO+Eundv0Jngbn/hKPhDDs4jj9ChwRX5cDDnlaN+ugYYQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-use-layout-effect": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz", @@ -649,6 +909,18 @@ "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz", "integrity": "sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==" }, + "node_modules/@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", + "dev": true + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", + "dev": true + }, "node_modules/@types/geojson": { "version": "7946.0.8", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", @@ -678,6 +950,12 @@ "@types/pbf": "*" } }, + "node_modules/@types/pako": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.3.tgz", + "integrity": "sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==", + "dev": true + }, "node_modules/@types/pbf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.2.tgz", @@ -687,13 +965,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.0.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.8.tgz", "integrity": "sha512-+j2hk9BzCOrrOSJASi5XiOyBbERk9jG5O73Ya4M0env5Ixi6vUNli4qy994AINcEF+1IEHISYFfIT4zwr++LKw==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -713,7 +991,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "devOptional": true }, "node_modules/@vitejs/plugin-react": { "version": "1.3.1", @@ -746,6 +1024,17 @@ "node": ">=4" } }, + "node_modules/aria-hidden": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz", + "integrity": "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==", + "dependencies": { + "tslib": "^1.0.0" + }, + "engines": { + "node": ">=8.5.0" + } + }, "node_modules/attr-accept": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", @@ -851,7 +1140,46 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", - "dev": true + "devOptional": true + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } }, "node_modules/debug": { "version": "4.3.4", @@ -870,6 +1198,11 @@ } } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, "node_modules/earcut": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", @@ -1315,6 +1648,14 @@ "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -1380,6 +1721,14 @@ } ] }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -1702,6 +2051,88 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.3.tgz", + "integrity": "sha512-NQ1bXrxKrnK5pFo/GhLkXeo3CrK5steI+5L+jynwwIemvZyfXqaL0L5BzwJd7CSwNCU723DZaccvjuyOdoy3Xw==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.1", + "react-style-singleton": "^2.2.0", + "tslib": "^2.0.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.1.tgz", + "integrity": "sha512-IvGX3mJclEF7+hga8APZczve1UyGMkMG+tjS0o/U1iLgvZRpjFAQEUBJ4JETfvbNlfNnZnoDyWJCICkA15Mghg==", + "dependencies": { + "react-style-singleton": "^2.2.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/react-remove-scroll/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/react-style-singleton": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.0.tgz", + "integrity": "sha512-nK7mN92DMYZEu3cQcAhfwE48NpzO5RpxjG4okbSqRRbfal9Pk+fG2RdQXTMp+f6all1hB9LIJSt+j7dCYrU11g==", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, "node_modules/regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", @@ -1825,6 +2256,11 @@ "node": ">=4" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/typescript": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", @@ -1838,6 +2274,57 @@ "node": ">=4.2.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz", + "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-callback-ref/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, "node_modules/vite": { "version": "2.9.6", "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.6.tgz", @@ -2265,6 +2752,26 @@ "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" }, + "@radix-ui/primitive": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-0.1.0.tgz", + "integrity": "sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-collection": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz", + "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-slot": "0.1.2" + } + }, "@radix-ui/react-compose-refs": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz", @@ -2281,6 +2788,67 @@ "@babel/runtime": "^7.13.10" } }, + "@radix-ui/react-dialog": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-0.1.7.tgz", + "integrity": "sha512-jXt8srGhHBRvEr9jhEAiwwJzWCWZoGRJ030aC9ja/gkRJbZdy0iD3FwXf+Ff4RtsZyLUMHW7VUwFOlz3Ixe1Vw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-dismissable-layer": "0.1.5", + "@radix-ui/react-focus-guards": "0.1.0", + "@radix-ui/react-focus-scope": "0.1.4", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-portal": "0.1.4", + "@radix-ui/react-presence": "0.1.2", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-slot": "0.1.2", + "@radix-ui/react-use-controllable-state": "0.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "^2.4.0" + } + }, + "@radix-ui/react-dismissable-layer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz", + "integrity": "sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-body-pointer-events": "0.1.1", + "@radix-ui/react-use-callback-ref": "0.1.0", + "@radix-ui/react-use-escape-keydown": "0.1.0" + } + }, + "@radix-ui/react-focus-guards": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz", + "integrity": "sha512-kRx/swAjEfBpQ3ns7J3H4uxpXuWCqN7MpALiSDOXiyo2vkWv0L9sxvbpZeTulINuE3CGMzicVMuNc/VWXjFKOg==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-focus-scope": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz", + "integrity": "sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-callback-ref": "0.1.0" + } + }, + "@radix-ui/react-icons": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.1.0.tgz", + "integrity": "sha512-nhctV9YKN8G4HfkS3p03ml+osTBDMGKImaAJTm666hymtaWEgIPiqL7F53ivDqIO4A+20ERwUiiKJ8h3XK7uAg==", + "requires": {} + }, "@radix-ui/react-id": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", @@ -2302,6 +2870,26 @@ "@radix-ui/react-primitive": "0.1.4" } }, + "@radix-ui/react-portal": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz", + "integrity": "sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-presence": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-0.1.2.tgz", + "integrity": "sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, "@radix-ui/react-primitive": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", @@ -2311,6 +2899,31 @@ "@radix-ui/react-slot": "0.1.2" } }, + "@radix-ui/react-roving-focus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz", + "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-collection": "0.1.4", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-callback-ref": "0.1.0", + "@radix-ui/react-use-controllable-state": "0.1.0" + } + }, + "@radix-ui/react-separator": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-0.1.4.tgz", + "integrity": "sha512-ct2qE072ydvMyFiPwgO8xGE4iLGR9BsSk2tIan23TYSiNTeQ89anzkuax5vNGjey0el2vnwUcReFS0Gy7Lk2VQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "0.1.4" + } + }, "@radix-ui/react-slot": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-0.1.2.tgz", @@ -2320,6 +2933,80 @@ "@radix-ui/react-compose-refs": "0.1.0" } }, + "@radix-ui/react-toggle": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz", + "integrity": "sha512-gxUq6NgMc4ChV8VJnwdYqueeoblspwXHAexYo+jM9N2hFLbI1C587jLjdTHzIcUa9q68Xaw4jtiImWDOokEhRw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-controllable-state": "0.1.0" + } + }, + "@radix-ui/react-toggle-group": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz", + "integrity": "sha512-Yp14wFiqe00azF+sG5CCJz4JGOP/f5Jj+CxLlZCmMpG5qhVTWeaeG4YH6pvX4KL41fS8x9FAaLb8wW9y01o67g==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-roving-focus": "0.1.5", + "@radix-ui/react-toggle": "0.1.4", + "@radix-ui/react-use-controllable-state": "0.1.0" + } + }, + "@radix-ui/react-toolbar": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-0.1.5.tgz", + "integrity": "sha512-k9ccGglui1tyR+YiYLty1oI+VOO7C4zCNAbR3sTT5FC0qflpBxaswJnOSQgapDIwl9tB/Al69mKUS3TFZ7WsQw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-context": "0.1.1", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-roving-focus": "0.1.5", + "@radix-ui/react-separator": "0.1.4", + "@radix-ui/react-toggle-group": "0.1.5" + } + }, + "@radix-ui/react-use-body-pointer-events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz", + "integrity": "sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-use-callback-ref": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.1.0.tgz", + "integrity": "sha512-Va041McOFFl+aV+sejvl0BS2aeHx86ND9X/rVFmEFQKTXCp6xgUK0NGUAGcgBlIjnJSbMYPGEk1xKSSlVcN2Aw==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-use-controllable-state": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz", + "integrity": "sha512-zv7CX/PgsRl46a52Tl45TwqwVJdmqnlQEQhaYMz/yBOD2sx2gCkCFSoF/z9mpnYWmS6DTLNTg5lIps3fV6EnXg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "0.1.0" + } + }, + "@radix-ui/react-use-escape-keydown": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.1.0.tgz", + "integrity": "sha512-tDLZbTGFmvXaazUXXv8kYbiCcbAE8yKgng9s95d8fCO+Eundv0Jngbn/hKPhDDs4jj9ChwRX5cDDnlaN+ugYYQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "0.1.0" + } + }, "@radix-ui/react-use-layout-effect": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz", @@ -2349,6 +3036,18 @@ "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz", "integrity": "sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==" }, + "@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", + "dev": true + }, + "@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", + "dev": true + }, "@types/geojson": { "version": "7946.0.8", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", @@ -2378,6 +3077,12 @@ "@types/pbf": "*" } }, + "@types/pako": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.3.tgz", + "integrity": "sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==", + "dev": true + }, "@types/pbf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.2.tgz", @@ -2387,13 +3092,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "devOptional": true }, "@types/react": { "version": "18.0.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.8.tgz", "integrity": "sha512-+j2hk9BzCOrrOSJASi5XiOyBbERk9jG5O73Ya4M0env5Ixi6vUNli4qy994AINcEF+1IEHISYFfIT4zwr++LKw==", - "dev": true, + "devOptional": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2413,7 +3118,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "devOptional": true }, "@vitejs/plugin-react": { "version": "1.3.1", @@ -2440,6 +3145,14 @@ "color-convert": "^1.9.0" } }, + "aria-hidden": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz", + "integrity": "sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==", + "requires": { + "tslib": "^1.0.0" + } + }, "attr-accept": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", @@ -2513,7 +3226,34 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", - "dev": true + "devOptional": true + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } }, "debug": { "version": "4.3.4", @@ -2524,6 +3264,11 @@ "ms": "2.1.2" } }, + "detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, "earcut": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", @@ -2765,6 +3510,11 @@ "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" }, + "get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -2801,6 +3551,14 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -3060,6 +3818,58 @@ "integrity": "sha512-suLIhrU2IHKL5JEKR/fAwJv7bbeq4kJ+pJopf77jHwuR+HmJS/HbrPIGsTBUVfw7tXPOmYv7UJ7PCaN49e8x4A==", "dev": true }, + "react-remove-scroll": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.3.tgz", + "integrity": "sha512-NQ1bXrxKrnK5pFo/GhLkXeo3CrK5steI+5L+jynwwIemvZyfXqaL0L5BzwJd7CSwNCU723DZaccvjuyOdoy3Xw==", + "requires": { + "react-remove-scroll-bar": "^2.3.1", + "react-style-singleton": "^2.2.0", + "tslib": "^2.0.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "react-remove-scroll-bar": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.1.tgz", + "integrity": "sha512-IvGX3mJclEF7+hga8APZczve1UyGMkMG+tjS0o/U1iLgvZRpjFAQEUBJ4JETfvbNlfNnZnoDyWJCICkA15Mghg==", + "requires": { + "react-style-singleton": "^2.2.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "react-style-singleton": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.0.tgz", + "integrity": "sha512-nK7mN92DMYZEu3cQcAhfwE48NpzO5RpxjG4okbSqRRbfal9Pk+fG2RdQXTMp+f6all1hB9LIJSt+j7dCYrU11g==", + "requires": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, "regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", @@ -3153,12 +3963,48 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "typescript": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, + "use-callback-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz", + "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==", + "requires": { + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "requires": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, "vite": { "version": "2.9.6", "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.6.tgz", diff --git a/app/package.json b/app/package.json index 50fd3d1..15e5238 100644 --- a/app/package.json +++ b/app/package.json @@ -4,12 +4,18 @@ "version": "0.0.0", "scripts": { "dev": "vite", - "preview": "vite preview" + "preview": "vite preview", + "tsc": "tsc --watch" }, "dependencies": { "@mapbox/vector-tile": "^1.3.1", + "@radix-ui/react-dialog": "^0.1.7", + "@radix-ui/react-icons": "^1.1.0", "@radix-ui/react-label": "^0.1.5", + "@radix-ui/react-toolbar": "^0.1.5", "@stitches/react": "^1.2.8", + "d3-path": "^3.0.1", + "d3-scale-chromatic": "^3.0.0", "leaflet": "^1.8.0", "maplibre-gl": "^2.1.9", "pako": "^2.0.4", @@ -20,8 +26,11 @@ "react-dropzone": "^14.1.1" }, "devDependencies": { + "@types/d3-path": "^3.0.0", + "@types/d3-scale-chromatic": "^3.0.0", "@types/leaflet": "^1.7.9", "@types/mapbox__vector-tile": "^1.3.0", + "@types/pako": "^1.0.3", "@types/pbf": "^3.0.2", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", diff --git a/app/src/App.tsx b/app/src/App.tsx index fee4008..477c5cd 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import { styled, globalStyles } from "./stitches.config"; +import { PMTiles } from "../../js"; import Start from "./Start"; import Loader from "./Loader"; @@ -8,26 +9,37 @@ const Header = styled("div", { height: "$4", }); -const GIT_SHA = (import.meta.env.VITE_GIT_SHA || "").substr(0,8) +const GIT_SHA = (import.meta.env.VITE_GIT_SHA || "").substr(0, 8); function App() { globalStyles(); - const existingValue = new URLSearchParams(location.search).get("file") || ""; + let initialValue; + const loadUrl = new URLSearchParams(location.search).get("url"); + if (loadUrl) { + initialValue = new PMTiles(loadUrl); + } - let [file, setFile] = useState(existingValue); + let [file, setFile] = useState(initialValue); useEffect(() => { if (file) { const url = new URL(window.location.href); - url.searchParams.set("file", file); + url.searchParams.set("url", file.source.getKey()); history.pushState(null, "", url.toString()); } }, [file]); + let clear = () => { + setFile(undefined); + }; + return (
-
pmtiles viewer | github | toggle | {GIT_SHA}
+
+ pmtiles viewer | github | toggle |{" "} + {GIT_SHA} +
{file ? : }
); diff --git a/app/src/Inspector.tsx b/app/src/Inspector.tsx index 3623dff..eb7bd6f 100644 --- a/app/src/Inspector.tsx +++ b/app/src/Inspector.tsx @@ -1,12 +1,291 @@ -import { useState } from "react"; -import { PMTiles } from "../../js"; +import { useState, useEffect, Dispatch, SetStateAction } from "react"; +import { createPortal } from "react-dom"; +import { PMTiles, Entry } from "../../js"; import { styled } from "./stitches.config"; +import { inflate } from "pako"; +import Protobuf from "pbf"; +import { VectorTile, VectorTileFeature } from "@mapbox/vector-tile"; +import { path } from "d3-path"; +import { schemeSet3 } from "d3-scale-chromatic"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; -function Inspector(props:{file:string}) { +const TableContainer = styled("div", { + height: "calc(100vh - $4)", + overflowY: "scroll", + width: "50%", +}); + +const Pane = styled("div", { + width: "50%", + backgroundColor: "black", +}); + +const TableRow = styled( + "tr", + { + cursor: "pointer", + }, + { "&:hover": { color: "red" } } +); + +const Split = styled("div", { + display: "flex", +}); + +const TileRow = (props: { + entry: Entry; + setSelectedEntry: Dispatch>; +}) => { return ( - <> - foo - + { + props.setSelectedEntry(props.entry); + }} + > + {props.entry.z} + {props.entry.x} + {props.entry.y} + {props.entry.offset} + {props.entry.length} + {props.entry.is_dir} + + ); +}; + +interface Layer { + name: string; + features: Feature[]; +} + +interface Feature { + path: string; + type: number; + id: number; + properties: any; +} + +let smartCompare = (a: Layer, b: Layer): number => { + if (a.name === "earth") return -4; + if (a.name === "water") return -3; + if (a.name === "natural") return -2; + if (a.name === "landuse") return -1; + if (a.name === "places") return 1; + return 0; +}; + +const FeatureSvg = (props: { + feature: Feature; + setSelectedFeature: Dispatch>; +}) => { + let [highlighted, setHighlighted] = useState(false); + let fill = "none"; + let stroke = ""; + + if (props.feature.type === 3) { + fill = highlighted ? "white" : "currentColor"; + } else { + stroke = highlighted ? "white" : "currentColor"; + } + + let mouseOver = () => { + setHighlighted(true); + }; + + let mouseOut = () => { + setHighlighted(false); + }; + + let mouseDown = () => { + props.setSelectedFeature(props.feature); + }; + + return ( + + ); +}; + +const LayerSvg = (props: { + layer: Layer; + color: string; + setSelectedFeature: Dispatch>; +}) => { + let elems = props.layer.features.map((f, i) => ( + + )); + return {elems}; +}; + +const StyledFeatureProperties = styled("div", { + position: "absolute", + right: 0, + bottom: 0, + backgroundColor: "red", +}); + +const FeatureProperties = (props: { feature: Feature }) => { + let tmp: [string, string][] = []; + for (var key in props.feature.properties) { + tmp.push([key, props.feature.properties[key]]); + } + + const rows = tmp.map((d, i) => ( + + {d[0]} + {d[1]} + + )); + + return {rows}; +}; + +const VectorPreview = (props: { file: PMTiles; entry: Entry }) => { + let [layers, setLayers] = useState([]); + let [selectedFeature, setSelectedFeature] = useState(null); + + useEffect(() => { + let fn = async (entry: Entry) => { + let view = await props.file.source.getBytes(entry.offset, entry.length); + let tile = new VectorTile( + new Protobuf( + new Uint8Array(view.buffer, view.byteOffset, view.byteLength) + ) + ); + let newLayers = []; + for (let [name, layer] of Object.entries(tile.layers)) { + let features: Feature[] = []; + for (var i = 0; i < layer.length; i++) { + let feature = layer.feature(i); + let p = path(); + let geom = feature.loadGeometry(); + + if (feature.type === 1) { + for (let ring of geom) { + for (let pt of ring) { + p.arc(pt.x, pt.y, 20, 0, 2 * Math.PI); + } + } + } else { + for (let ring of geom) { + p.moveTo(ring[0].x, ring[0].y); + for (var j = 1; j < ring.length; j++) { + p.lineTo(ring[j].x, ring[j].y); + } + if (feature.type === 3) { + p.closePath(); + } + } + } + features.push({ + path: p.toString(), + type: feature.type, + id: feature.id, + properties: feature.properties, + }); + } + newLayers.push({ features: features, name: name }); + } + newLayers.sort(smartCompare); + setLayers(newLayers); + }; + + if (props.entry) { + fn(props.entry); + } + }, [props.entry]); + + let elems = layers.map((l, i) => ( + + )); + + return ( +
+ + {elems} + + {selectedFeature ? : null} +
+ ); +}; + +const RasterPreview = (props: { file: PMTiles; entry: Entry }) => { + let [imgSrc, setImageSrc] = useState(""); + + useEffect(() => { + let fn = async (entry: Entry) => { + // TODO 0,0,0 is broken + let view = await props.file.source.getBytes(entry.offset, entry.length); + let blob = new Blob([view]); + var imageUrl = window.URL.createObjectURL(blob); + setImageSrc(imageUrl); + }; + + if (props.entry) { + fn(props.entry); + } + }, [props.entry]); + + return ; +}; + +function Inspector(props: { file: PMTiles }) { + let [entryRows, setEntryRows] = useState([]); + let [selectedEntry, setSelectedEntry] = useState(null); + + useEffect(() => { + let fn = async () => { + let entries = await props.file.root_entries(); + setEntryRows(entries); + }; + + fn(); + }, [props.file]); + + let rows = entryRows.map((e, i) => ( + + )); + + let tilePreview =
; + if (selectedEntry) { + tilePreview = ; + } else { + } + + return ( + + + + + + + + + + + + + {rows} +
zxyoffsetlength
+
+ {tilePreview} +
); } diff --git a/app/src/LeafletMap.tsx b/app/src/LeafletMap.tsx index 3b25692..2c04056 100644 --- a/app/src/LeafletMap.tsx +++ b/app/src/LeafletMap.tsx @@ -8,14 +8,10 @@ const MapContainer = styled("div", { height: "calc(100vh - $4)", }); -function LeafletMap(props:{file:string, tileType: string | null}) { - const p = new PMTiles( - "https://protomaps-static.sfo3.digitaloceanspaces.com/osm_carto.pmtiles" - ); - +function LeafletMap(props: { file: PMTiles; tileType: string | null }) { useEffect(() => { const map = L.map("map").setView([0, 0], 0); - leafletLayer(p, { + leafletLayer(props.file, { attribution: '© OpenStreetMap contributors', }).addTo(map); diff --git a/app/src/Loader.tsx b/app/src/Loader.tsx index 7b772e8..64b51da 100644 --- a/app/src/Loader.tsx +++ b/app/src/Loader.tsx @@ -6,28 +6,140 @@ import Inspector from "./Inspector"; import LeafletMap from "./LeafletMap"; import MaplibreMap from "./MaplibreMap"; -function Loader(props: { file: string }) { - let [tab, setTab] = useState("maplibre"); +import { MagnifyingGlassIcon, ImageIcon } from "@radix-ui/react-icons"; +import * as ToolbarPrimitive from "@radix-ui/react-toolbar"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; + +const StyledToolbar = styled(ToolbarPrimitive.Root, { + display: "flex", + padding: 10, + width: "100%", + boxSizing: "border-box", + minWidth: "max-content", + borderRadius: 6, + backgroundColor: "white", + boxShadow: `0 2px 10px "black"`, +}); + +const itemStyles = { + all: "unset", + flex: "0 0 auto", + color: "black", + height: 25, + padding: "0 5px", + borderRadius: 4, + display: "inline-flex", + fontSize: 13, + lineHeight: 1, + alignItems: "center", + justifyContent: "center", + "&:hover": { backgroundColor: "$hover", color: "blue" }, + "&:focus": { position: "relative", boxShadow: `0 0 0 2px blue` }, +}; + +const StyledButton = styled( + ToolbarPrimitive.Button, + { + ...itemStyles, + paddingLeft: 10, + paddingRight: 10, + color: "white", + backgroundColor: "blue", + }, + { "&:hover": { color: "white", backgroundColor: "red" } } +); + +const StyledLink = styled( + ToolbarPrimitive.Link, + { + ...itemStyles, + backgroundColor: "transparent", + color: "black", + display: "inline-flex", + justifyContent: "center", + alignItems: "center", + }, + { "&:hover": { backgroundColor: "transparent", cursor: "pointer" } } +); + +const StyledSeparator = styled(ToolbarPrimitive.Separator, { + width: 1, + backgroundColor: "black", + margin: "0 10px", +}); + +const StyledToggleGroup = styled(ToolbarPrimitive.ToggleGroup, { + display: "inline-flex", + borderRadius: 4, +}); + +const StyledToggleItem = styled(ToolbarPrimitive.ToggleItem, { + ...itemStyles, + boxShadow: 0, + backgroundColor: "white", + marginLeft: 2, + "&:first-child": { marginLeft: 0 }, + "&[data-state=on]": { backgroundColor: "red", color: "blue" }, +}); + +const StyledOverlay = styled(DialogPrimitive.Overlay, { + backgroundColor: "black", + position: "fixed", + inset: 0, + opacity: "40%", + zIndex: 3, +}); + +const StyledContent = styled(DialogPrimitive.Content, { + backgroundColor: "white", + borderRadius: 6, + boxShadow: + "hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px", + position: "fixed", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: "90vw", + maxWidth: "450px", + maxHeight: "85vh", + padding: 25, + zIndex: 4, + "&:focus": { outline: "none" }, +}); + +const Toolbar = StyledToolbar; +const ToolbarButton = StyledButton; +const ToolbarSeparator = StyledSeparator; +const ToolbarLink = StyledLink; +const ToolbarToggleGroup = StyledToggleGroup; +const ToolbarToggleItem = StyledToggleItem; + +function Loader(props: { file: PMTiles }) { + let [tab, setTab] = useState("inspector"); let [tileType, setTileType] = useState(null); + let [metadata, setMetadata] = useState<[string, string][]>([]); + let [modalOpen, setModalOpen] = useState(false); let view; if (tab === "leaflet") { - view = ; + view = ; } else if (tab === "maplibre") { - view = ; + view = ; } else { view = ; } useEffect(() => { - let pmtiles = new PMTiles(props.file); + let pmtiles = props.file; const fetchData = async () => { - let metadata = await pmtiles.metadata(); + let m = await pmtiles.metadata(); + let tmp: [string, string][] = []; + for (var key in m) { + tmp.push([key, m[key]]); + } + setMetadata(tmp); - let resp = await fetch(props.file, { - headers: { Range: "bytes=512000-512003" }, - }); - let magic = new DataView(await resp.arrayBuffer()); + let magic = await props.file.source.getBytes(512000, 4); let b0 = magic.getUint8(0); let b1 = magic.getUint8(1); let b2 = magic.getUint8(2); @@ -36,7 +148,7 @@ function Loader(props: { file: string }) { if (b0 == 0x89 && b1 == 0x50 && b2 == 0x4e && b3 == 0x47) { setTileType("png"); } else if (b0 == 0xff && b1 == 0xd8 && b2 == 0xff && b3 == 0xe0) { - setTileType("jpg") + setTileType("jpg"); } else if (b0 == 0x1f && b1 == 0x8b) { setTileType("mvt.gz"); } else { @@ -46,10 +158,75 @@ function Loader(props: { file: string }) { fetchData(); }, [props.file]); - return <> -
{props.file} | {tileType}
- {view} - ; + const metadataRows = metadata.map((d, i) => ( + + {d[0]} + {d[1]} + + )); + + const closeModal = () => { + setModalOpen(false); + }; + + return ( + <> + + + + Tile Inspector + + + Leaflet + + + MapLibre + + + + + {props.file.source.getKey()} + + setModalOpen(true)} + > + Metadata + + + + + + + + + + + + + + + + + + {metadataRows} +
keyvalue
+ +
+
+
+ {view} + + ); } export default Loader; diff --git a/app/src/MaplibreMap.tsx b/app/src/MaplibreMap.tsx index 2e66853..086542c 100644 --- a/app/src/MaplibreMap.tsx +++ b/app/src/MaplibreMap.tsx @@ -8,33 +8,33 @@ const MapContainer = styled("div", { height: "calc(100vh - $4)", }); -const rasterStyle = (file:string) => { +const rasterStyle = (file: PMTiles) => { return { version: 8, sources: { source: { type: "raster", - tiles: ["pmtiles://" + file + "/{z}/{x}/{y}"], - maxzoom:4 + tiles: ["pmtiles://" + file.source.getKey() + "/{z}/{x}/{y}"], + maxzoom: 4, }, }, layers: [ { id: "raster", type: "raster", - source: "source" + source: "source", }, ], }; }; -const vectorStyle = (file:string) => { +const vectorStyle = (file: PMTiles) => { return { version: 8, sources: { source: { type: "vector", - tiles: ["pmtiles://" + file + "/{z}/{x}/{y}"], + tiles: ["pmtiles://" + file.source.getKey() + "/{z}/{x}/{y}"], maxzoom: 7, }, }, @@ -62,11 +62,12 @@ const vectorStyle = (file:string) => { }; }; -function MaplibreMap(props: { file: string, tileType: string | null }) { +function MaplibreMap(props: { file: PMTiles; tileType: string | null }) { let mapRef = useRef(null); useEffect(() => { let cache = new ProtocolCache(); maplibregl.addProtocol("pmtiles", cache.protocol); + cache.add(props.file); const map = new maplibregl.Map({ container: "map", @@ -74,6 +75,7 @@ function MaplibreMap(props: { file: string, tileType: string | null }) { center: [0, 0], style: rasterStyle(props.file) as any, }); // TODO maplibre types (not any) + map.addControl(new maplibregl.NavigationControl({})); map.on("load", map.resize); return () => { diff --git a/app/src/Start.tsx b/app/src/Start.tsx index 032eddc..fec725b 100644 --- a/app/src/Start.tsx +++ b/app/src/Start.tsx @@ -1,7 +1,7 @@ -import { useState, Dispatch, SetStateAction } from "react"; +import { useState, Dispatch, SetStateAction, useCallback } from "react"; import maplibregl from "maplibre-gl"; import L from "leaflet"; -import { PMTiles } from "../../js"; +import { PMTiles, FileSource } from "../../js"; import { styled } from "./stitches.config"; import { useDropzone } from "react-dropzone"; @@ -84,10 +84,10 @@ const Example = styled("div", { variants: { selected: { true: { - backgroundColor:"red" - } - } - } + backgroundColor: "red", + }, + }, + }, }); const ExampleList = styled("div", { @@ -97,29 +97,40 @@ const ExampleList = styled("div", { }); const EXAMPLE_FILES = [ - "https://protomaps-static.sfo3.digitaloceanspaces.com/osm_carto.pmtiles" -] + "https://protomaps-static.sfo3.digitaloceanspaces.com/osm_carto.pmtiles", + "https://protomaps-static.sfo3.digitaloceanspaces.com/mantle-trial.pmtiles", + "https://protomaps-static.sfo3.digitaloceanspaces.com/cb_2018_us_zcta510_500k_nolimit.pmtiles", +]; -function Start(props:{setFile:Dispatch>}) { +function Start(props: { + setFile: Dispatch>; +}) { + const onDrop = useCallback((acceptedFiles: File[]) => { + props.setFile(new PMTiles(new FileSource(acceptedFiles[0]))); + }, []); - const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); + const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ + onDrop, + }); let [remoteUrl, setRemoteUrl] = useState(""); let [selectedExample, setSelectedExample] = useState(1); - const onRemoteUrlChangeHandler = (event:React.ChangeEvent) => { + const onRemoteUrlChangeHandler = ( + event: React.ChangeEvent + ) => { setRemoteUrl(event.target.value); - } + }; - const loadExample = (i:number) => { + const loadExample = (i: number) => { return () => { - props.setFile(EXAMPLE_FILES[i]); - } - } + props.setFile(new PMTiles(EXAMPLE_FILES[i])); + }; + }; const onSubmit = () => { - props.setFile("abcd"); - } + // props.setFile(new PMTiles("abcd")); + }; return ( @@ -130,7 +141,9 @@ function Start(props:{setFile:Dispatch>}) { placeholder="https://example.com/my_archive.pmtiles" onChange={onRemoteUrlChangeHandler} > - + @@ -138,7 +151,11 @@ function Start(props:{setFile:Dispatch>}) { - {EXAMPLE_FILES.map((e,i) => {e})} + {EXAMPLE_FILES.map((e, i) => ( + + {e} + + ))} ); diff --git a/app/src/main.tsx b/app/src/main.tsx index eaad244..f46c379 100644 --- a/app/src/main.tsx +++ b/app/src/main.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App' +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; -ReactDOM.createRoot(document.getElementById('root')!).render( +ReactDOM.createRoot(document.getElementById("root")!).render( -) +); diff --git a/app/src/stitches.config.ts b/app/src/stitches.config.ts index 46a8bb2..73d562e 100644 --- a/app/src/stitches.config.ts +++ b/app/src/stitches.config.ts @@ -5,6 +5,8 @@ export const { styled } = createStitches({ colors: { black: "rgba(0, 0, 0)", white: "rgba(236, 237, 238)", + hover: "#666", + selected: "#444", }, fonts: { sans: "Inter, sans-serif", @@ -48,7 +50,13 @@ export const { styled } = createStitches({ }); export const globalStyles = globalCss({ - "*": { margin: 0, padding: 0, border: 0, fontFamily: "Inter, sans-serif", xborder: "1px solid gold" }, + "*": { + margin: 0, + padding: 0, + border: 0, + fontFamily: "Inter, sans-serif", + xborder: "1px solid gold", + }, body: { backgroundColor: "$black", color: "$white" }, "@import": ["url('https://rsms.me/inter/inter.css')"], });