Compare commits
5 Commits
main
...
feature/op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9181355bf | ||
|
|
299477a717 | ||
|
|
7a0de61bbb | ||
|
|
6e8d5cb091 | ||
|
|
5e72711629 |
5
examples/learn/next.config.js
Normal file
5
examples/learn/next.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const nextConfig = {
|
||||||
|
swcMinify: false
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nextConfig
|
||||||
93
package-lock.json
generated
93
package-lock.json
generated
@ -8808,6 +8808,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@reach/observe-rect/-/observe-rect-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@reach/observe-rect/-/observe-rect-1.2.0.tgz",
|
||||||
"integrity": "sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ=="
|
"integrity": "sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-leaflet/core": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"leaflet": "^1.9.0",
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/plugin-babel": {
|
"node_modules/@rollup/plugin-babel": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||||
@ -12696,6 +12706,15 @@
|
|||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/leaflet": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-Caa1lYOgKVqDkDZVWkto2Z5JtVo09spEaUt2S69LiugbBpoqQu92HYFMGUbYezZbnBkyOxMNPXHSgRrRY5UyIA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
"version": "4.14.195",
|
"version": "4.14.195",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
|
||||||
@ -15525,6 +15544,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chroma-js": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
|
||||||
|
},
|
||||||
"node_modules/chrome-trace-event": {
|
"node_modules/chrome-trace-event": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||||
@ -27579,6 +27603,11 @@
|
|||||||
"url": "https://github.com/motdotla/dotenv?sponsor=1"
|
"url": "https://github.com/motdotla/dotenv?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/leaflet": {
|
||||||
|
"version": "1.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
|
||||||
|
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
|
||||||
|
},
|
||||||
"node_modules/leven": {
|
"node_modules/leven": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||||
@ -32646,6 +32675,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-leaflet": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-leaflet/core": "^2.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"leaflet": "^1.9.0",
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-query": {
|
"node_modules/react-query": {
|
||||||
"version": "3.39.3",
|
"version": "3.39.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
|
||||||
@ -39254,17 +39296,20 @@
|
|||||||
},
|
},
|
||||||
"packages/components": {
|
"packages/components": {
|
||||||
"name": "@portaljs/components",
|
"name": "@portaljs/components",
|
||||||
"version": "0.1.11",
|
"version": "0.1.12",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@githubocto/flat-ui": "^0.14.1",
|
"@githubocto/flat-ui": "^0.14.1",
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
"@tanstack/react-table": "^8.8.5",
|
"@tanstack/react-table": "^8.8.5",
|
||||||
|
"chroma-js": "^2.4.2",
|
||||||
"flexsearch": "0.7.21",
|
"flexsearch": "0.7.21",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"next-mdx-remote": "^4.4.1",
|
"next-mdx-remote": "^4.4.1",
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.43.9",
|
"react-hook-form": "^7.43.9",
|
||||||
|
"react-leaflet": "^4.2.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-vega": "^7.6.0",
|
"react-vega": "^7.6.0",
|
||||||
"rollup-plugin-re": "^1.0.7",
|
"rollup-plugin-re": "^1.0.7",
|
||||||
@ -39281,6 +39326,7 @@
|
|||||||
"@storybook/react-vite": "^7.0.7",
|
"@storybook/react-vite": "^7.0.7",
|
||||||
"@storybook/testing-library": "^0.0.14-next.2",
|
"@storybook/testing-library": "^0.0.14-next.2",
|
||||||
"@types/flexsearch": "^0.7.3",
|
"@types/flexsearch": "^0.7.3",
|
||||||
|
"@types/leaflet": "^1.9.3",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "^18.0.28",
|
"@types/react": "^18.0.28",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
@ -39627,7 +39673,7 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@portaljs/core",
|
"name": "@portaljs/core",
|
||||||
"version": "1.0.3",
|
"version": "1.0.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docsearch/react": "^3.3.3",
|
"@docsearch/react": "^3.3.3",
|
||||||
@ -39653,7 +39699,7 @@
|
|||||||
},
|
},
|
||||||
"packages/remark-callouts": {
|
"packages/remark-callouts": {
|
||||||
"name": "@portaljs/remark-callouts",
|
"name": "@portaljs/remark-callouts",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mdast-util-from-markdown": "^1.2.0",
|
"mdast-util-from-markdown": "^1.2.0",
|
||||||
@ -39663,7 +39709,7 @@
|
|||||||
},
|
},
|
||||||
"packages/remark-embed": {
|
"packages/remark-embed": {
|
||||||
"name": "@portaljs/remark-embed",
|
"name": "@portaljs/remark-embed",
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"unist-util-visit": "^4.1.1"
|
"unist-util-visit": "^4.1.1"
|
||||||
@ -39671,7 +39717,7 @@
|
|||||||
},
|
},
|
||||||
"packages/remark-wiki-link": {
|
"packages/remark-wiki-link": {
|
||||||
"name": "@portaljs/remark-wiki-link",
|
"name": "@portaljs/remark-wiki-link",
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mdast-util-to-markdown": "^1.5.0",
|
"mdast-util-to-markdown": "^1.5.0",
|
||||||
@ -46416,6 +46462,7 @@
|
|||||||
"@storybook/testing-library": "^0.0.14-next.2",
|
"@storybook/testing-library": "^0.0.14-next.2",
|
||||||
"@tanstack/react-table": "^8.8.5",
|
"@tanstack/react-table": "^8.8.5",
|
||||||
"@types/flexsearch": "^0.7.3",
|
"@types/flexsearch": "^0.7.3",
|
||||||
|
"@types/leaflet": "^1.9.3",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "^18.0.28",
|
"@types/react": "^18.0.28",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
@ -46423,12 +46470,14 @@
|
|||||||
"@typescript-eslint/parser": "^5.57.1",
|
"@typescript-eslint/parser": "^5.57.1",
|
||||||
"@vitejs/plugin-react": "^4.0.0",
|
"@vitejs/plugin-react": "^4.0.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
|
"chroma-js": "2.4.2",
|
||||||
"eslint": "^8.38.0",
|
"eslint": "^8.38.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-react-refresh": "^0.3.4",
|
"eslint-plugin-react-refresh": "^0.3.4",
|
||||||
"eslint-plugin-storybook": "^0.6.11",
|
"eslint-plugin-storybook": "^0.6.11",
|
||||||
"flexsearch": "0.7.21",
|
"flexsearch": "0.7.21",
|
||||||
"json": "^11.0.0",
|
"json": "^11.0.0",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"next-mdx-remote": "^4.4.1",
|
"next-mdx-remote": "^4.4.1",
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
@ -46436,6 +46485,7 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.43.9",
|
"react-hook-form": "^7.43.9",
|
||||||
|
"react-leaflet": "^4.2.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-vega": "^7.6.0",
|
"react-vega": "^7.6.0",
|
||||||
"rollup-plugin-re": "^1.0.7",
|
"rollup-plugin-re": "^1.0.7",
|
||||||
@ -46799,6 +46849,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@reach/observe-rect/-/observe-rect-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@reach/observe-rect/-/observe-rect-1.2.0.tgz",
|
||||||
"integrity": "sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ=="
|
"integrity": "sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ=="
|
||||||
},
|
},
|
||||||
|
"@react-leaflet/core": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@rollup/plugin-babel": {
|
"@rollup/plugin-babel": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||||
@ -49605,6 +49661,15 @@
|
|||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/leaflet": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-Caa1lYOgKVqDkDZVWkto2Z5JtVo09spEaUt2S69LiugbBpoqQu92HYFMGUbYezZbnBkyOxMNPXHSgRrRY5UyIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/lodash": {
|
"@types/lodash": {
|
||||||
"version": "4.14.195",
|
"version": "4.14.195",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
|
||||||
@ -51793,6 +51858,11 @@
|
|||||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chroma-js": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
|
||||||
|
},
|
||||||
"chrome-trace-event": {
|
"chrome-trace-event": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||||
@ -61034,6 +61104,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"leaflet": {
|
||||||
|
"version": "1.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
|
||||||
|
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
|
||||||
|
},
|
||||||
"leven": {
|
"leven": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||||
@ -64650,6 +64725,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||||
},
|
},
|
||||||
|
"react-leaflet": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==",
|
||||||
|
"requires": {
|
||||||
|
"@react-leaflet/core": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-query": {
|
"react-query": {
|
||||||
"version": "3.39.3",
|
"version": "3.39.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
|
||||||
|
|||||||
10
packages/components/.storybook/preview-head.html
Normal file
10
packages/components/.storybook/preview-head.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<!--
|
||||||
|
This is necessary for Leaflet maps to work.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||||
|
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
||||||
|
crossorigin=""
|
||||||
|
/>
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import 'tailwindcss/tailwind.css'
|
import 'tailwindcss/tailwind.css'
|
||||||
import '../src/index.css'
|
import '../src/index.css'
|
||||||
|
|
||||||
|
|
||||||
import type { Preview } from '@storybook/react';
|
import type { Preview } from '@storybook/react';
|
||||||
|
|
||||||
const preview: Preview = {
|
const preview: Preview = {
|
||||||
|
|||||||
@ -12,12 +12,14 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npm run storybook",
|
"dev": "npm run storybook",
|
||||||
"build": "tsc && vite build && npm run build-tailwind",
|
"example": "vite",
|
||||||
|
"build": "tsc && vite build && npm run build-tailwind && npm run fix-leaflet",
|
||||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
"build-storybook": "storybook build",
|
"build-storybook": "storybook build",
|
||||||
"build-tailwind": "NODE_ENV=production npx tailwindcss -o ./dist/styles.css --minify",
|
"build-tailwind": "NODE_ENV=production npx tailwindcss --postcss -c tailwind.config.js -i src/index.css -o ./dist/styles.css --minify",
|
||||||
"prepare": "npm run build"
|
"prepare": "npm run build",
|
||||||
|
"fix-leaflet": "node ./scripts/fix-leaflet.cjs"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@ -26,16 +28,20 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@githubocto/flat-ui": "^0.14.1",
|
"@githubocto/flat-ui": "^0.14.1",
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
|
"@planet/maps": "^8.1.0",
|
||||||
"@tanstack/react-table": "^8.8.5",
|
"@tanstack/react-table": "^8.8.5",
|
||||||
|
"chroma-js": "^2.4.2",
|
||||||
"flexsearch": "0.7.21",
|
"flexsearch": "0.7.21",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"next-mdx-remote": "^4.4.1",
|
"next-mdx-remote": "^4.4.1",
|
||||||
|
"ol": "^7.4.0",
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.43.9",
|
"react-hook-form": "^7.43.9",
|
||||||
|
"react-leaflet": "^4.2.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-vega": "^7.6.0",
|
"react-vega": "^7.6.0",
|
||||||
"rollup-plugin-re": "^1.0.7",
|
|
||||||
"vega": "5.25.0",
|
"vega": "5.25.0",
|
||||||
"vega-lite": "5.1.0",
|
"vega-lite": "5.1.0",
|
||||||
"vitest": "^0.31.4"
|
"vitest": "^0.31.4"
|
||||||
@ -48,13 +54,16 @@
|
|||||||
"@storybook/react": "^7.0.7",
|
"@storybook/react": "^7.0.7",
|
||||||
"@storybook/react-vite": "^7.0.7",
|
"@storybook/react-vite": "^7.0.7",
|
||||||
"@storybook/testing-library": "^0.0.14-next.2",
|
"@storybook/testing-library": "^0.0.14-next.2",
|
||||||
|
"@swc/core": "^1.3.68",
|
||||||
"@types/flexsearch": "^0.7.3",
|
"@types/flexsearch": "^0.7.3",
|
||||||
|
"@types/leaflet": "^1.9.3",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "^18.0.28",
|
"@types/react": "^18.0.28",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||||
"@typescript-eslint/parser": "^5.57.1",
|
"@typescript-eslint/parser": "^5.57.1",
|
||||||
"@vitejs/plugin-react": "^4.0.0",
|
"@vitejs/plugin-react": "^4.0.0",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"eslint": "^8.38.0",
|
"eslint": "^8.38.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
@ -62,12 +71,15 @@
|
|||||||
"eslint-plugin-storybook": "^0.6.11",
|
"eslint-plugin-storybook": "^0.6.11",
|
||||||
"json": "^11.0.0",
|
"json": "^11.0.0",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
|
"postcss-import": "^15.1.0",
|
||||||
|
"postcss-import-url": "^7.2.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"storybook": "^7.0.7",
|
"storybook": "^7.0.7",
|
||||||
"tailwindcss": "^3.3.2",
|
"tailwindcss": "^3.3.2",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
"vite": "^4.3.2",
|
"vite": "^4.3.2",
|
||||||
"vite-plugin-dts": "^2.3.0"
|
"vite-plugin-dts": "^2.3.0",
|
||||||
|
"vite-plugin-swc-only": "^0.1.18"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
console.log('PostCSS')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
plugins: {
|
plugins: {
|
||||||
|
'postcss-import': {},
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
6
packages/components/scripts/fix-leaflet.cjs
Normal file
6
packages/components/scripts/fix-leaflet.cjs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const leafletPath = path.join(require.resolve('leaflet'), '../')
|
||||||
|
|
||||||
|
fs.cpSync(`${leafletPath}images`,'./dist/images', { recursive: true });
|
||||||
139
packages/components/src/components/Map.tsx
Normal file
139
packages/components/src/components/Map.tsx
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import LoadingSpinner from './LoadingSpinner';
|
||||||
|
import loadData from '../lib/loadData';
|
||||||
|
import chroma from 'chroma-js';
|
||||||
|
import {
|
||||||
|
MapContainer,
|
||||||
|
TileLayer,
|
||||||
|
GeoJSON as GeoJSONLayer,
|
||||||
|
} from 'react-leaflet';
|
||||||
|
|
||||||
|
import * as L from 'leaflet';
|
||||||
|
|
||||||
|
export type MapProps = {
|
||||||
|
data: string | GeoJSON.GeoJSON;
|
||||||
|
title?: string;
|
||||||
|
colorScale?: {
|
||||||
|
starting: string;
|
||||||
|
ending: string;
|
||||||
|
};
|
||||||
|
center?: { latitude: number | undefined; longitude: number | undefined };
|
||||||
|
zoom?: number;
|
||||||
|
tooltip?: {
|
||||||
|
prop: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Map({
|
||||||
|
data,
|
||||||
|
title = '',
|
||||||
|
colorScale = { starting: 'blue', ending: 'red' },
|
||||||
|
center = { latitude: 45, longitude: 45 },
|
||||||
|
zoom = 2,
|
||||||
|
tooltip = {
|
||||||
|
prop: '',
|
||||||
|
},
|
||||||
|
}: MapProps) {
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// By default, assumes data is an Array...
|
||||||
|
const [geoJsonData, setGeoJsonData] = useState<any>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// If data is string, assume it's a URL
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
loadData(data).then((res: any) => {
|
||||||
|
const geoJsonObject = JSON.parse(res);
|
||||||
|
|
||||||
|
const colorScaleAr = chroma
|
||||||
|
.scale([colorScale.starting, colorScale.ending])
|
||||||
|
.mode('lch')
|
||||||
|
.colors(geoJsonObject.features.length);
|
||||||
|
|
||||||
|
geoJsonObject.features.forEach((feature, i) => {
|
||||||
|
if (feature.color === undefined) {
|
||||||
|
feature.color = colorScaleAr[i];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setGeoJsonData(geoJsonObject);
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setGeoJsonData(data);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onEachFeature = (feature, layer) => {
|
||||||
|
const geometryType = feature.type;
|
||||||
|
|
||||||
|
if (tooltip.prop)
|
||||||
|
layer.bindTooltip(feature.properties[tooltip.prop], {
|
||||||
|
direction: 'center',
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.on({
|
||||||
|
mouseover: (event) => {
|
||||||
|
if (['Polygon', 'MultiPolygon'].includes(geometryType)) {
|
||||||
|
event.target.setStyle({
|
||||||
|
fillColor: '#B85042',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mouseout: (event) => {
|
||||||
|
if (['Polygon', 'MultiPolygon'].includes(geometryType)) {
|
||||||
|
event.target.setStyle({
|
||||||
|
fillColor: '#A7BEAE',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return isLoading || !geoJsonData ? (
|
||||||
|
<div className="w-full flex items-center justify-center w-[600px] h-[300px]">
|
||||||
|
<LoadingSpinner />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<MapContainer
|
||||||
|
center={[center.latitude, center.longitude]}
|
||||||
|
zoom={zoom}
|
||||||
|
scrollWheelZoom={false}
|
||||||
|
className="h-80 w-full"
|
||||||
|
// @ts-ignore
|
||||||
|
whenReady={(map: any) => {
|
||||||
|
map.target.scrollWheelZoom.enable();
|
||||||
|
|
||||||
|
var info = new L.Control() as any;
|
||||||
|
|
||||||
|
info.onAdd = function () {
|
||||||
|
this._div = L.DomUtil.create('div', 'info');
|
||||||
|
this.update();
|
||||||
|
return this._div;
|
||||||
|
};
|
||||||
|
|
||||||
|
info.update = function () {
|
||||||
|
this._div.innerHTML = `<h4 style="font-weight: 600; background: #f9f9f9; padding: 5px; border-radius: 5px; color: #464646;">${title}</h4>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (title) info.addTo(map.target);
|
||||||
|
|
||||||
|
setTimeout(() => map.target.invalidateSize(), 5000);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GeoJSONLayer
|
||||||
|
data={geoJsonData}
|
||||||
|
style={(geoJsonFeature: any) => {
|
||||||
|
return { color: geoJsonFeature?.color };
|
||||||
|
}}
|
||||||
|
onEachFeature={onEachFeature}
|
||||||
|
/>
|
||||||
|
<TileLayer
|
||||||
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
/>
|
||||||
|
</MapContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
84
packages/components/src/components/OpenLayers/Controls.jsx
Normal file
84
packages/components/src/components/OpenLayers/Controls.jsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
|
export const Controls = ({ children }) => {
|
||||||
|
return <div>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
import { FullScreen, Zoom } from 'ol/control';
|
||||||
|
import { MapContext } from './Map';
|
||||||
|
|
||||||
|
export const FullScreenControl = () => {
|
||||||
|
const { map } = useContext(MapContext);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return;
|
||||||
|
let fullScreenControl = new FullScreen({
|
||||||
|
className: 'ml-1 flex flex-col w-8 items-center mt-2',
|
||||||
|
activeClassName:
|
||||||
|
'w-full inline-flex justify-center items-center rounded-t-md bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
|
||||||
|
inactiveClassName:
|
||||||
|
'inline-flex w-full justify-center items-center rounded-t-md bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
|
||||||
|
});
|
||||||
|
let zoomControl = new Zoom({
|
||||||
|
className: 'ml-1 flex flex-col w-8 items-center',
|
||||||
|
zoomInClassName:
|
||||||
|
'inline-flex w-full justify-center items-center bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
|
||||||
|
zoomOutClassName:
|
||||||
|
'inline-flex w-full justify-center items-center rounded-b-md bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
|
||||||
|
});
|
||||||
|
map.controls.push(fullScreenControl);
|
||||||
|
map.controls.push(zoomControl);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
map.controls.remove(zoomControl);
|
||||||
|
map.controls.remove(fullScreenControl);
|
||||||
|
};
|
||||||
|
}, [map]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
//build a list of checkboxes in react
|
||||||
|
|
||||||
|
export const ListOfCheckboxes = ({ layers, shownLayers, setShownLayers }) => {
|
||||||
|
//layers is an array of url and name
|
||||||
|
function addLayer(layer) {
|
||||||
|
setShownLayers([...shownLayers, layer.url]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeLayer(layer) {
|
||||||
|
setShownLayers(shownLayers.filter((l) => l !== layer.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3 className="mb-4 font-semibold text-gray-900 ">Layers</h3>
|
||||||
|
<ul className="w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg ">
|
||||||
|
{layers.map((layer, index) => (
|
||||||
|
<li
|
||||||
|
key={index}
|
||||||
|
className="w-full border-b border-gray-200 rounded-t-lg "
|
||||||
|
>
|
||||||
|
<div className="flex items-center pl-3">
|
||||||
|
<input
|
||||||
|
id={layer.name}
|
||||||
|
type="checkbox"
|
||||||
|
defaultChecked={shownLayers.includes(layer.url)}
|
||||||
|
onClick={() =>
|
||||||
|
shownLayers.includes(layer.url)
|
||||||
|
? removeLayer(layer)
|
||||||
|
: addLayer(layer)
|
||||||
|
}
|
||||||
|
value={true}
|
||||||
|
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 focus:ring-2 "
|
||||||
|
></input>
|
||||||
|
<label
|
||||||
|
htmlFor={layer.name}
|
||||||
|
className="w-full py-3 ml-2 text-sm font-medium text-gray-90"
|
||||||
|
>
|
||||||
|
{layer.name}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { useContext, useEffect, useState } from 'react';
|
||||||
|
import HeatMap from 'ol/layer/Heatmap';
|
||||||
|
import { MapContext } from './Map';
|
||||||
|
const HeatMapLayer = ({ source, style, zIndex = 0 }) => {
|
||||||
|
const { map } = useContext(MapContext);
|
||||||
|
const [heatMapLayer, setHeatMapLayer] = useState(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return;
|
||||||
|
let heatMapLayer = new HeatMap({
|
||||||
|
source,
|
||||||
|
style,
|
||||||
|
blur: parseInt(5, 10),
|
||||||
|
radius: parseInt(5, 10),
|
||||||
|
});
|
||||||
|
map.addLayer(heatMapLayer);
|
||||||
|
setHeatMapLayer(heatMapLayer);
|
||||||
|
heatMapLayer.setZIndex(zIndex);
|
||||||
|
return () => {
|
||||||
|
if (map) {
|
||||||
|
map.removeLayer(heatMapLayer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [map]);
|
||||||
|
useEffect(() => {
|
||||||
|
heatMapLayer && heatMapLayer.setZIndex(zIndex);
|
||||||
|
}, [zIndex]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
export default HeatMapLayer;
|
||||||
4
packages/components/src/components/OpenLayers/Layers.jsx
Normal file
4
packages/components/src/components/OpenLayers/Layers.jsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
|
export const Layers = ({ children }) => {
|
||||||
|
return <div>{children}</div>;
|
||||||
|
};
|
||||||
50
packages/components/src/components/OpenLayers/Map.jsx
Normal file
50
packages/components/src/components/OpenLayers/Map.jsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
|
import * as ol from 'ol';
|
||||||
|
|
||||||
|
export const MapContext = new React.createContext();
|
||||||
|
|
||||||
|
const Map = ({ children, zoom, center, setSelected }) => {
|
||||||
|
const mapRef = useRef();
|
||||||
|
const [map, setMap] = useState(null);
|
||||||
|
// on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
let options = {
|
||||||
|
view: new ol.View({ zoom, center }),
|
||||||
|
layers: [],
|
||||||
|
controls: [],
|
||||||
|
overlays: [],
|
||||||
|
};
|
||||||
|
let mapObject = new ol.Map(options);
|
||||||
|
mapObject.setTarget(mapRef.current);
|
||||||
|
setMap(mapObject);
|
||||||
|
return () => mapObject.setTarget(undefined);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (map) {
|
||||||
|
if (setSelected !== null) {
|
||||||
|
let selected = null;
|
||||||
|
map.on('pointermove', function (e) {
|
||||||
|
map.forEachFeatureAtPixel(e.pixel, function (f) {
|
||||||
|
selected = f;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (selected) {
|
||||||
|
setSelected(selected);
|
||||||
|
} else {
|
||||||
|
setSelected(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [map]);
|
||||||
|
return (
|
||||||
|
<MapContext.Provider value={{ map }}>
|
||||||
|
<div ref={mapRef} className="w-full" style={{height: '500px'}}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</MapContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Map;
|
||||||
136
packages/components/src/components/OpenLayers/OpenLayers.tsx
Normal file
136
packages/components/src/components/OpenLayers/OpenLayers.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import Map from './Map';
|
||||||
|
import { Layers } from './Layers';
|
||||||
|
import { Fill, Icon, Style } from 'ol/style';
|
||||||
|
import * as olSource from 'ol/source';
|
||||||
|
import TileLayer from './TileLayer';
|
||||||
|
import { fromLonLat } from 'ol/proj';
|
||||||
|
import VectorLayer from './VectorLayer';
|
||||||
|
import { Vector as VectorSource } from 'ol/source';
|
||||||
|
import GeoJSON from 'ol/format/GeoJSON';
|
||||||
|
import KML from 'ol/format/KML';
|
||||||
|
import { colors } from './colors';
|
||||||
|
import { FullScreenControl, Controls, ListOfCheckboxes } from './Controls';
|
||||||
|
import HeatMapLayer from './HeatMapLayer';
|
||||||
|
|
||||||
|
function osm() {
|
||||||
|
return new olSource.OSM();
|
||||||
|
}
|
||||||
|
|
||||||
|
const formats = {
|
||||||
|
geojson: new GeoJSON(),
|
||||||
|
kml: new KML(),
|
||||||
|
};
|
||||||
|
|
||||||
|
interface OpenLayersProps {
|
||||||
|
layers: {
|
||||||
|
url: string;
|
||||||
|
name?: string;
|
||||||
|
format?: string;
|
||||||
|
heatmap?: boolean;
|
||||||
|
}[];
|
||||||
|
center?: [number, number];
|
||||||
|
zoom?: number;
|
||||||
|
popup?: (selected: any) => JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OpenLayers({
|
||||||
|
layers,
|
||||||
|
center = [0, 0],
|
||||||
|
zoom = 1,
|
||||||
|
popup,
|
||||||
|
}: OpenLayersProps) {
|
||||||
|
const [shownLayers, setShownLayers] = useState(
|
||||||
|
layers.map((layer) => layer.url)
|
||||||
|
);
|
||||||
|
const [selected, setSelected] = useState(null);
|
||||||
|
const [style, setStyle] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const style = new Style({
|
||||||
|
fill: new Fill({
|
||||||
|
color: '#eeeeee',
|
||||||
|
}),
|
||||||
|
image: new Icon({
|
||||||
|
anchor: [0.5, 46],
|
||||||
|
anchorXUnits: 'fraction',
|
||||||
|
anchorYUnits: 'pixels',
|
||||||
|
width: 18,
|
||||||
|
height: 28,
|
||||||
|
src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Google_Maps_icon_%282020%29.svg/418px-Google_Maps_icon_%282020%29.svg.png?20200218211225',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
setStyle(style);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<Map
|
||||||
|
center={fromLonLat(center)}
|
||||||
|
zoom={zoom}
|
||||||
|
setSelected={popup ? setSelected : null}
|
||||||
|
>
|
||||||
|
<Layers>
|
||||||
|
<TileLayer source={osm()} zIndex={0} />
|
||||||
|
{layers.map((layer, index) =>
|
||||||
|
!layer.heatmap ? (
|
||||||
|
<VectorLayer
|
||||||
|
key={index}
|
||||||
|
zIndex={shownLayers.includes(layer.url) ? 1 : -1}
|
||||||
|
source={
|
||||||
|
new VectorSource({
|
||||||
|
url: layer.url,
|
||||||
|
format: layer.format
|
||||||
|
? formats[layer.format]
|
||||||
|
: new GeoJSON(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
style={function (feature) {
|
||||||
|
const id = feature.getId();
|
||||||
|
const color = feature.get('COLOR') || colors[id % 1302].hex;
|
||||||
|
style.getFill().setColor(color);
|
||||||
|
return style;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<HeatMapLayer
|
||||||
|
key={index}
|
||||||
|
zIndex={shownLayers.includes(layer.url) ? 1 : -1}
|
||||||
|
source={
|
||||||
|
new VectorSource({
|
||||||
|
url: layer.url,
|
||||||
|
format: layer.format
|
||||||
|
? formats[layer.format]
|
||||||
|
: new GeoJSON(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
style={function (feature) {
|
||||||
|
const color =
|
||||||
|
feature.get('COLOR') || colors[feature.ol_uid % 1302].hex;
|
||||||
|
style.getFill().setColor(color);
|
||||||
|
return style;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Layers>
|
||||||
|
{/* add a floating pane that will output the ListOfCheckboxes component using tailwind*/}
|
||||||
|
<div className="absolute bottom-0 right-0 m-4 p-4 z-50 bg-white rounded-lg shadow-xl">
|
||||||
|
<ListOfCheckboxes
|
||||||
|
layers={layers}
|
||||||
|
shownLayers={shownLayers}
|
||||||
|
setShownLayers={setShownLayers}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{popup && selected && (
|
||||||
|
<div className="absolute bottom-0 left-0 m-4 p-4 z-50 bg-white rounded-lg shadow-xl">
|
||||||
|
{popup(selected)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Controls>
|
||||||
|
<FullScreenControl />
|
||||||
|
</Controls>
|
||||||
|
</Map>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
packages/components/src/components/OpenLayers/TileLayer.jsx
Normal file
23
packages/components/src/components/OpenLayers/TileLayer.jsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
import OLTileLayer from 'ol/layer/Tile';
|
||||||
|
import { MapContext } from './Map';
|
||||||
|
const TileLayer = ({ source, zIndex = 0 }) => {
|
||||||
|
const { map } = useContext(MapContext);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
let tileLayer = new OLTileLayer({
|
||||||
|
source,
|
||||||
|
zIndex,
|
||||||
|
});
|
||||||
|
map.addLayer(tileLayer);
|
||||||
|
tileLayer.setZIndex(zIndex);
|
||||||
|
return () => {
|
||||||
|
if (map) {
|
||||||
|
map.removeLayer(tileLayer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [map]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
export default TileLayer;
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import { useContext, useEffect, useState } from 'react';
|
||||||
|
import OLVectorLayer from 'ol/layer/Vector';
|
||||||
|
import { MapContext } from './Map';
|
||||||
|
const VectorLayer = ({ source, style, zIndex = 0 }) => {
|
||||||
|
const { map } = useContext(MapContext);
|
||||||
|
const [vectorLayer, setVectorLayer] = useState(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return;
|
||||||
|
let vectorLayer = new OLVectorLayer({
|
||||||
|
source,
|
||||||
|
style,
|
||||||
|
});
|
||||||
|
const vectorSource = vectorLayer.getSource();
|
||||||
|
vectorSource.on('featuresloadend', function () {
|
||||||
|
vectorSource.getFeatures().forEach((feature, index) => {
|
||||||
|
feature.setId(index);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
map.addLayer(vectorLayer);
|
||||||
|
setVectorLayer(vectorLayer);
|
||||||
|
vectorLayer.setZIndex(zIndex);
|
||||||
|
return () => {
|
||||||
|
if (map) {
|
||||||
|
map.removeLayer(vectorLayer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [map]);
|
||||||
|
useEffect(() => {
|
||||||
|
vectorLayer && vectorLayer.setZIndex(zIndex);
|
||||||
|
}, [zIndex]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
export default VectorLayer;
|
||||||
5210
packages/components/src/components/OpenLayers/colors.js
Normal file
5210
packages/components/src/components/OpenLayers/colors.js
Normal file
File diff suppressed because it is too large
Load Diff
6
packages/components/src/include.css
Normal file
6
packages/components/src/include.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/* Temporary fix for a size issue with FlatUiTable loading indicator on Firefox */
|
||||||
|
@layer base {
|
||||||
|
svg[tw^='animate-pulse w-12'] {
|
||||||
|
max-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,7 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
/* Temporary fix for a size issue with FlatUiTable loading indicator on Firefox */
|
@import "tailwindcss/base";
|
||||||
@layer base {
|
@import "tailwindcss/components";
|
||||||
svg[tw^='animate-pulse w-12'] {
|
@import "leaflet";
|
||||||
max-width: 100px;
|
@import "include";
|
||||||
}
|
@import "tailwindcss/utilities";
|
||||||
}
|
|
||||||
|
|||||||
@ -4,3 +4,5 @@ export * from "./components/LineChart";
|
|||||||
export * from "./components/Vega";
|
export * from "./components/Vega";
|
||||||
export * from "./components/VegaLite";
|
export * from "./components/VegaLite";
|
||||||
export * from "./components/FlatUiTable";
|
export * from "./components/FlatUiTable";
|
||||||
|
export * from './components/OpenLayers/OpenLayers';
|
||||||
|
export * from "./components/Map";
|
||||||
|
|||||||
171
packages/components/src/types/GeoJSON.tsx
Normal file
171
packages/components/src/types/GeoJSON.tsx
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* Typescript types for the GeoJSON RFC7946 specification. This is not fully RFC-compliant due to lack of support for
|
||||||
|
* ranged number data types.
|
||||||
|
*
|
||||||
|
* See https://tools.ietf.org/html/rfc7946
|
||||||
|
*/
|
||||||
|
export declare namespace GeoJSON {
|
||||||
|
/**
|
||||||
|
* Inside this document, the term "geometry type" refers to seven case-sensitive strings: "Point", "MultiPoint",
|
||||||
|
* "LineString", "MultiLineString", "Polygon", "MultiPolygon", and "GeometryCollection".
|
||||||
|
*/
|
||||||
|
export type Geometry = Point | MultiPoint | LineString | MultiLineString | Polygon | MultiPolygon
|
||||||
|
| GeometryCollection;
|
||||||
|
export type GeometryType = Geometry["type"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ...the term "GeoJSON types" refers to nine case-sensitive strings: "Feature", "FeatureCollection", and the
|
||||||
|
* geometry types listed above.
|
||||||
|
*/
|
||||||
|
export type GeoJson = Geometry | Feature | FeatureCollection;
|
||||||
|
export type GeoJsonType = GeoJson["type"];
|
||||||
|
|
||||||
|
// types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A position is an array of numbers. There MUST be two or more elements. The first two elements are longitude and
|
||||||
|
* latitude, or easting and northing, precisely in that order and using decimal numbers. Altitude or elevation MAY
|
||||||
|
* be included as an optional third element.
|
||||||
|
*
|
||||||
|
* Implementations SHOULD NOT extend positions beyond three elements because the semantics of extra elements are
|
||||||
|
* unspecified and ambiguous.
|
||||||
|
*/
|
||||||
|
export type Position = [longitude: number, latitude: number, elevation?: number]
|
||||||
|
|
||||||
|
export type Record = { [key in string | number]: unknown };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties inherit to all GeoJSON types
|
||||||
|
*/
|
||||||
|
export interface GeometryBase extends Record {
|
||||||
|
/**
|
||||||
|
* A GeoJSON object MAY have a member named "bbox" to include information on the coordinate range for its
|
||||||
|
* Geometries, Features, or FeatureCollections. The value of the bbox member MUST be an array of length 2*n
|
||||||
|
* where n is the number of dimensions represented in the contained geometries, with all axes of the most
|
||||||
|
* southwesterly point followed by all axes of the more northeasterly point. The axes order of a bbox follows
|
||||||
|
* the axes order of geometries.
|
||||||
|
*/
|
||||||
|
bbox?: number[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A GeoJSON object MAY have other members.
|
||||||
|
*
|
||||||
|
* Members not described in this specification ("foreign members") MAY be used in a GeoJSON document. Note that
|
||||||
|
* support for foreign members can vary across implementations, and no normative processing model for foreign
|
||||||
|
* members is defined.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// geometry types
|
||||||
|
|
||||||
|
export interface Point extends GeometryBase {
|
||||||
|
type: "Point";
|
||||||
|
/**
|
||||||
|
* For type "Point", the "coordinates" member is a single position.
|
||||||
|
*/
|
||||||
|
coordinates: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultiPoint extends GeometryBase {
|
||||||
|
type: "MultiPoint";
|
||||||
|
/**
|
||||||
|
* For type "MultiPoint", the "coordinates" member is an array of positions.
|
||||||
|
*/
|
||||||
|
coordinates: Position[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LineString extends GeometryBase {
|
||||||
|
type: "LineString";
|
||||||
|
/**
|
||||||
|
* For type "LineString", the "coordinates" member is an array of two or more positions.
|
||||||
|
*/
|
||||||
|
coordinates: { 0: Position, 1: Position } & Position[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultiLineString extends GeometryBase {
|
||||||
|
type: "MultiLineString";
|
||||||
|
/**
|
||||||
|
* For type "MultiLineString", the "coordinates" member is an array of LineString coordinate arrays.
|
||||||
|
*/
|
||||||
|
coordinates: LineString["coordinates"][];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To specify a constraint specific to Polygons, it is useful to introduce the concept of a linear ring:
|
||||||
|
* - A linear ring is a closed LineString with four or more positions.
|
||||||
|
* - The first and last positions are equivalent, and they MUST contain identical values; their representation
|
||||||
|
* SHOULD also be identical.
|
||||||
|
* - A linear ring is the boundary of a surface or the boundary of a hole in a surface.
|
||||||
|
* - A linear ring MUST follow the right-hand rule with respect to the area it bounds, i.e., exterior rings are
|
||||||
|
* counterclockwise, and holes are clockwise.
|
||||||
|
*/
|
||||||
|
export type LinearRing = { 0: Position, 1: Position, 2: Position, 3: Position } & Position[];
|
||||||
|
|
||||||
|
export interface Polygon extends GeometryBase {
|
||||||
|
type: "Polygon";
|
||||||
|
/**
|
||||||
|
* For type "Polygon", the "coordinates" member MUST be an array of linear ring coordinate arrays.
|
||||||
|
*
|
||||||
|
* For Polygons with more than one of these rings, the first MUST be the exterior ring, and any others MUST be
|
||||||
|
* interior rings. The exterior ring bounds the surface, and the interior rings (if present) bound holes within
|
||||||
|
* the surface.
|
||||||
|
*/
|
||||||
|
coordinates: LinearRing[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultiPolygon extends GeometryBase {
|
||||||
|
type: "MultiPolygon";
|
||||||
|
/**
|
||||||
|
* For type "MultiPolygon", the "coordinates" member is an array of Polygon coordinate arrays.
|
||||||
|
*/
|
||||||
|
coordinates: Polygon["coordinates"][];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeometryCollection {
|
||||||
|
/**
|
||||||
|
* A GeoJSON object with type "GeometryCollection" is a Geometry object.
|
||||||
|
*/
|
||||||
|
type: "GeometryCollection";
|
||||||
|
/**
|
||||||
|
* A GeometryCollection has a member with the name "geometries". The value of "geometries" is an array. Each
|
||||||
|
* element of this array is a GeoJSON Geometry object. It is possible for this array to be empty.
|
||||||
|
*/
|
||||||
|
geometries: Geometry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeoJSON types
|
||||||
|
|
||||||
|
export interface Feature {
|
||||||
|
/**
|
||||||
|
* A Feature object has a "type" member with the value "Feature".
|
||||||
|
*/
|
||||||
|
type: "Feature";
|
||||||
|
/**
|
||||||
|
* If a Feature has a commonly used identifier, that identifier SHOULD be included as a member of the Feature object
|
||||||
|
* with the name "id", and the value of this member is either a JSON string or number.
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
/**
|
||||||
|
* A Feature object has a member with the name "geometry". The value of the geometry member SHALL be either a
|
||||||
|
* Geometry object as defined above or, in the case that the Feature is unlocated, a JSON null value.
|
||||||
|
*/
|
||||||
|
geometry: Geometry | null;
|
||||||
|
/**
|
||||||
|
* A Feature object has a member with the name "properties". The value of the properties member is an object
|
||||||
|
* (any JSON object or a JSON null value).
|
||||||
|
*/
|
||||||
|
properties: Record | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FeatureCollection {
|
||||||
|
/**
|
||||||
|
* A GeoJSON object with the type "FeatureCollection" is a FeatureCollection object.
|
||||||
|
*/
|
||||||
|
type: "FeatureCollection";
|
||||||
|
/**
|
||||||
|
* A FeatureCollection object has a member with the name "features". The value of "features" is a JSON array. Each
|
||||||
|
* element of the array is a Feature object as defined above. It is possible for this array to be empty.
|
||||||
|
*/
|
||||||
|
features: Feature[];
|
||||||
|
}
|
||||||
|
}
|
||||||
55
packages/components/stories/Map.stories.ts
Normal file
55
packages/components/stories/Map.stories.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Map, MapProps } from '../src/components/Map';
|
||||||
|
|
||||||
|
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Components/Map',
|
||||||
|
component: Map,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
argTypes: {
|
||||||
|
data: {
|
||||||
|
description:
|
||||||
|
'Data to be displayed.\n\n GeoJSON Object \n\nOR\n\n URL to GeoJSON Object',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
description: 'Title to display on the map. Optional.',
|
||||||
|
},
|
||||||
|
center: {
|
||||||
|
description: 'Initial coordinates of the center of the map',
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
description: 'Zoom level',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
description: 'Tooltip settings'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<MapProps>;
|
||||||
|
|
||||||
|
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
||||||
|
export const GeoJSONPolygons: Story = {
|
||||||
|
name: 'GeoJSON polygons map',
|
||||||
|
args: {
|
||||||
|
data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||||
|
title: 'Seas and Oceans Map',
|
||||||
|
center: { latitude: 45, longitude: 0 },
|
||||||
|
zoom: 2,
|
||||||
|
tooltip: { prop: 'name' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GeoJSONPoints: Story = {
|
||||||
|
name: 'GeoJSON points map',
|
||||||
|
args: {
|
||||||
|
data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||||
|
title: 'Roads in York',
|
||||||
|
center: { latitude: 53.9614, longitude: -1.0739 },
|
||||||
|
zoom: 12,
|
||||||
|
tooltip: { prop: 'Location' },
|
||||||
|
},
|
||||||
|
};
|
||||||
136
packages/components/stories/OpenLayers.stories.tsx
Normal file
136
packages/components/stories/OpenLayers.stories.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { OpenLayers } from '../src/components/OpenLayers/OpenLayers';
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Components/OpenLayers',
|
||||||
|
component: OpenLayers,
|
||||||
|
argTypes: {
|
||||||
|
layers: {
|
||||||
|
description: 'Layers to be added to the map',
|
||||||
|
control: {
|
||||||
|
type: 'array',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
center: {
|
||||||
|
description: 'Center of the map',
|
||||||
|
defaultValue: [0, 0],
|
||||||
|
control: {
|
||||||
|
type: 'array',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
description: 'Zoom level of the map',
|
||||||
|
defaultValue: 1,
|
||||||
|
control: {
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<any>;
|
||||||
|
|
||||||
|
export const Secondary: Story = {
|
||||||
|
name: 'Map with OpenLayers',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://openlayers.org/data/vector/ecoregions.json',
|
||||||
|
name: 'Ecoregions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Primary: Story = {
|
||||||
|
name: 'Map with OpenLayers 2',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||||
|
name: 'Marine regions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MapWithPopover: Story = {
|
||||||
|
name: 'Map with popup',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://openlayers.org/data/vector/ecoregions.json',
|
||||||
|
name: 'Ecoregions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
popup: (feature: any) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-y-1" style={{ color: 'red' }}>
|
||||||
|
<span className="font-bold">Biome name</span>
|
||||||
|
<span className="text-sm">{feature.values_.BIOME_NAME}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Third: Story = {
|
||||||
|
name: 'Map with two layers',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||||
|
name: 'Marine regions',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'https://openlayers.org/data/vector/ecoregions.json',
|
||||||
|
name: 'Ecoregions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomCenter: Story = {
|
||||||
|
name: 'Map with custom center and zoom',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://openlayers.org/data/vector/ecoregions.json',
|
||||||
|
name: 'Ecoregions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
center: [-15, 20],
|
||||||
|
zoom: 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PointsOnMap: Story = {
|
||||||
|
name: 'Map with points on',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||||
|
name: 'E-Scooter Parking Bays',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
center: [-1.055429957881787, 53.963900188025301],
|
||||||
|
zoom: 12,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const KMLFile: Story = {
|
||||||
|
name: 'Map with KML File',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
url: 'https://openlayers.org/en/latest/examples/data/kml/2012_Earthquakes_Mag5.kml',
|
||||||
|
name: '2012 Earthquakes M5+',
|
||||||
|
format: 'kml',
|
||||||
|
heatmap: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,8 +1,6 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||||
theme: {
|
theme: {},
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [],
|
plugins: [],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,29 +1,15 @@
|
|||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react-swc';
|
||||||
import path from 'node:path'
|
import path from 'node:path';
|
||||||
import { defineConfig } from 'vitest/config'
|
import { defineConfig } from 'vitest/config';
|
||||||
import dts from 'vite-plugin-dts'
|
import dts from 'vite-plugin-dts';
|
||||||
import tailwindcss from 'tailwindcss'
|
import tailwindcss from 'tailwindcss';
|
||||||
import { UserConfigExport } from 'vite'
|
import { UserConfigExport } from 'vite';
|
||||||
import replace from "rollup-plugin-re"
|
import replace from 'rollup-plugin-re';
|
||||||
|
|
||||||
const app = async (): Promise<UserConfigExport> => {
|
const app = async (): Promise<UserConfigExport> => {
|
||||||
return defineConfig({
|
return defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
replace({
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
match: /js-sha256/,
|
|
||||||
test: `eval("require('crypto')")`,
|
|
||||||
replace: `require('crypto')`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: /js-sha256/,
|
|
||||||
test: `eval("require('buffer').Buffer")`,
|
|
||||||
replace: `require('buffer').Buffer`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
dts({
|
dts({
|
||||||
insertTypesEntry: true,
|
insertTypesEntry: true,
|
||||||
}),
|
}),
|
||||||
@ -34,6 +20,7 @@ const app = async (): Promise<UserConfigExport> => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
target: 'es2020',
|
||||||
lib: {
|
lib: {
|
||||||
entry: path.resolve(__dirname, 'src/index.ts'),
|
entry: path.resolve(__dirname, 'src/index.ts'),
|
||||||
name: 'components',
|
name: 'components',
|
||||||
@ -41,12 +28,27 @@ const app = async (): Promise<UserConfigExport> => {
|
|||||||
fileName: (format) => `components.${format}.js`,
|
fileName: (format) => `components.${format}.js`,
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['react', 'react-dom', 'tailwindcss', 'vega-lite', 'vega', 'react-vega'],
|
external: [
|
||||||
|
'react',
|
||||||
|
'ol-mapbox-style',
|
||||||
|
'react-dom',
|
||||||
|
'tailwindcss',
|
||||||
|
'vega-lite',
|
||||||
|
'vega',
|
||||||
|
'react-vega',
|
||||||
|
'ol',
|
||||||
|
'leaflet'
|
||||||
|
],
|
||||||
output: {
|
output: {
|
||||||
|
manualChunks: undefined,
|
||||||
globals: {
|
globals: {
|
||||||
react: 'React',
|
react: 'React',
|
||||||
|
ol: 'ol',
|
||||||
|
'ol-mapbox-style': 'ol-mapbox-style',
|
||||||
|
'react-vega': 'react-vega',
|
||||||
'react-dom': 'ReactDOM',
|
'react-dom': 'ReactDOM',
|
||||||
tailwindcss: 'tailwindcss',
|
tailwindcss: 'tailwindcss',
|
||||||
|
leaflet: 'leaflet'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -55,7 +57,7 @@ const app = async (): Promise<UserConfigExport> => {
|
|||||||
globals: true,
|
globals: true,
|
||||||
environment: 'jsdom',
|
environment: 'jsdom',
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default app
|
export default app;
|
||||||
|
|||||||
@ -0,0 +1,64 @@
|
|||||||
|
// vite.config.ts
|
||||||
|
import react from "file:///home/urutu-branco/Projetos/portaljs/node_modules/@vitejs/plugin-react-swc/index.mjs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { defineConfig } from "file:///home/urutu-branco/Projetos/portaljs/node_modules/vitest/dist/config.js";
|
||||||
|
import dts from "file:///home/urutu-branco/Projetos/portaljs/node_modules/vite-plugin-dts/dist/index.mjs";
|
||||||
|
import tailwindcss from "file:///home/urutu-branco/Projetos/portaljs/node_modules/tailwindcss/lib/index.js";
|
||||||
|
var __vite_injected_original_dirname = "/home/urutu-branco/Projetos/portaljs/packages/components";
|
||||||
|
var app = async () => {
|
||||||
|
return defineConfig({
|
||||||
|
plugins: [
|
||||||
|
react(),
|
||||||
|
dts({
|
||||||
|
insertTypesEntry: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [tailwindcss]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
target: "es2020",
|
||||||
|
lib: {
|
||||||
|
entry: path.resolve(__vite_injected_original_dirname, "src/index.ts"),
|
||||||
|
name: "components",
|
||||||
|
formats: ["es", "umd"],
|
||||||
|
fileName: (format) => `components.${format}.js`
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
external: [
|
||||||
|
"react",
|
||||||
|
"ol-mapbox-style",
|
||||||
|
"react-dom",
|
||||||
|
"tailwindcss",
|
||||||
|
"vega-lite",
|
||||||
|
"vega",
|
||||||
|
"react-vega",
|
||||||
|
"ol",
|
||||||
|
"ol/dom.js"
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
manualChunks: void 0,
|
||||||
|
globals: {
|
||||||
|
react: "React",
|
||||||
|
ol: "ol",
|
||||||
|
"ol/dom.js": "ol/dom.js",
|
||||||
|
"react-vega": "react-vega",
|
||||||
|
"react-dom": "ReactDOM",
|
||||||
|
tailwindcss: "tailwindcss"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: "jsdom"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var vite_config_default = app;
|
||||||
|
export {
|
||||||
|
vite_config_default as default
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS91cnV0dS1icmFuY28vUHJvamV0b3MvcG9ydGFsanMvcGFja2FnZXMvY29tcG9uZW50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvdXJ1dHUtYnJhbmNvL1Byb2pldG9zL3BvcnRhbGpzL3BhY2thZ2VzL2NvbXBvbmVudHMvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdXJ1dHUtYnJhbmNvL1Byb2pldG9zL3BvcnRhbGpzL3BhY2thZ2VzL2NvbXBvbmVudHMvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgcmVhY3QgZnJvbSAnQHZpdGVqcy9wbHVnaW4tcmVhY3Qtc3djJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlc3QvY29uZmlnJztcbmltcG9ydCBkdHMgZnJvbSAndml0ZS1wbHVnaW4tZHRzJztcbmltcG9ydCB0YWlsd2luZGNzcyBmcm9tICd0YWlsd2luZGNzcyc7XG5pbXBvcnQgeyBVc2VyQ29uZmlnRXhwb3J0IH0gZnJvbSAndml0ZSc7XG5pbXBvcnQgcmVwbGFjZSBmcm9tICdyb2xsdXAtcGx1Z2luLXJlJztcblxuY29uc3QgYXBwID0gYXN5bmMgKCk6IFByb21pc2U8VXNlckNvbmZpZ0V4cG9ydD4gPT4ge1xuICByZXR1cm4gZGVmaW5lQ29uZmlnKHtcbiAgICBwbHVnaW5zOiBbXG4gICAgICByZWFjdCgpLFxuICAgICAgZHRzKHtcbiAgICAgICAgaW5zZXJ0VHlwZXNFbnRyeTogdHJ1ZSxcbiAgICAgIH0pLFxuICAgIF0sXG4gICAgY3NzOiB7XG4gICAgICBwb3N0Y3NzOiB7XG4gICAgICAgIHBsdWdpbnM6IFt0YWlsd2luZGNzc10sXG4gICAgICB9LFxuICAgIH0sXG4gICAgYnVpbGQ6IHtcbiAgICAgIHRhcmdldDogJ2VzMjAyMCcsXG4gICAgICBsaWI6IHtcbiAgICAgICAgZW50cnk6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICdzcmMvaW5kZXgudHMnKSxcbiAgICAgICAgbmFtZTogJ2NvbXBvbmVudHMnLFxuICAgICAgICBmb3JtYXRzOiBbJ2VzJywgJ3VtZCddLFxuICAgICAgICBmaWxlTmFtZTogKGZvcm1hdCkgPT4gYGNvbXBvbmVudHMuJHtmb3JtYXR9LmpzYCxcbiAgICAgIH0sXG4gICAgICByb2xsdXBPcHRpb25zOiB7XG4gICAgICAgIGV4dGVybmFsOiBbXG4gICAgICAgICAgJ3JlYWN0JyxcbiAgICAgICAgICAnb2wtbWFwYm94LXN0eWxlJyxcbiAgICAgICAgICAncmVhY3QtZG9tJyxcbiAgICAgICAgICAndGFpbHdpbmRjc3MnLFxuICAgICAgICAgICd2ZWdhLWxpdGUnLFxuICAgICAgICAgICd2ZWdhJyxcbiAgICAgICAgICAncmVhY3QtdmVnYScsXG4gICAgICAgICAgJ29sJyxcbiAgICAgICAgICAnb2wvZG9tLmpzJyxcbiAgICAgICAgXSxcbiAgICAgICAgb3V0cHV0OiB7XG4gICAgICAgICAgbWFudWFsQ2h1bmtzOiB1bmRlZmluZWQsXG4gICAgICAgICAgZ2xvYmFsczoge1xuICAgICAgICAgICAgcmVhY3Q6ICdSZWFjdCcsXG4gICAgICAgICAgICBvbDogJ29sJyxcbiAgICAgICAgICAgICdvbC9kb20uanMnOiAnb2wvZG9tLmpzJyxcbiAgICAgICAgICAgICdyZWFjdC12ZWdhJzogJ3JlYWN0LXZlZ2EnLFxuICAgICAgICAgICAgJ3JlYWN0LWRvbSc6ICdSZWFjdERPTScsXG4gICAgICAgICAgICB0YWlsd2luZGNzczogJ3RhaWx3aW5kY3NzJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICAgIHRlc3Q6IHtcbiAgICAgIGdsb2JhbHM6IHRydWUsXG4gICAgICBlbnZpcm9ubWVudDogJ2pzZG9tJyxcbiAgICB9LFxuICB9KTtcbn07XG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgYXBwO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUEwVixPQUFPLFdBQVc7QUFDNVcsT0FBTyxVQUFVO0FBQ2pCLFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLGlCQUFpQjtBQUp4QixJQUFNLG1DQUFtQztBQVF6QyxJQUFNLE1BQU0sWUFBdUM7QUFDakQsU0FBTyxhQUFhO0FBQUEsSUFDbEIsU0FBUztBQUFBLE1BQ1AsTUFBTTtBQUFBLE1BQ04sSUFBSTtBQUFBLFFBQ0Ysa0JBQWtCO0FBQUEsTUFDcEIsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUNBLEtBQUs7QUFBQSxNQUNILFNBQVM7QUFBQSxRQUNQLFNBQVMsQ0FBQyxXQUFXO0FBQUEsTUFDdkI7QUFBQSxJQUNGO0FBQUEsSUFDQSxPQUFPO0FBQUEsTUFDTCxRQUFRO0FBQUEsTUFDUixLQUFLO0FBQUEsUUFDSCxPQUFPLEtBQUssUUFBUSxrQ0FBVyxjQUFjO0FBQUEsUUFDN0MsTUFBTTtBQUFBLFFBQ04sU0FBUyxDQUFDLE1BQU0sS0FBSztBQUFBLFFBQ3JCLFVBQVUsQ0FBQyxXQUFXLGNBQWM7QUFBQSxNQUN0QztBQUFBLE1BQ0EsZUFBZTtBQUFBLFFBQ2IsVUFBVTtBQUFBLFVBQ1I7QUFBQSxVQUNBO0FBQUEsVUFDQTtBQUFBLFVBQ0E7QUFBQSxVQUNBO0FBQUEsVUFDQTtBQUFBLFVBQ0E7QUFBQSxVQUNBO0FBQUEsVUFDQTtBQUFBLFFBQ0Y7QUFBQSxRQUNBLFFBQVE7QUFBQSxVQUNOLGNBQWM7QUFBQSxVQUNkLFNBQVM7QUFBQSxZQUNQLE9BQU87QUFBQSxZQUNQLElBQUk7QUFBQSxZQUNKLGFBQWE7QUFBQSxZQUNiLGNBQWM7QUFBQSxZQUNkLGFBQWE7QUFBQSxZQUNiLGFBQWE7QUFBQSxVQUNmO0FBQUEsUUFDRjtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBQUEsSUFDQSxNQUFNO0FBQUEsTUFDSixTQUFTO0FBQUEsTUFDVCxhQUFhO0FBQUEsSUFDZjtBQUFBLEVBQ0YsQ0FBQztBQUNIO0FBRUEsSUFBTyxzQkFBUTsiLAogICJuYW1lcyI6IFtdCn0K
|
||||||
Loading…
x
Reference in New Issue
Block a user