Compare commits
63 Commits
feature/le
...
1005-note-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
573f938dfe | ||
|
|
961a219f61 | ||
|
|
df395e2b70 | ||
|
|
ea5dade346 | ||
|
|
8027026399 | ||
|
|
af7812f689 | ||
|
|
6a36e65b27 | ||
|
|
38aa62fcef | ||
|
|
ed9b575b4e | ||
|
|
8327f4efc0 | ||
|
|
d6a12e3111 | ||
|
|
9fc834c16d | ||
|
|
1a7371f9c5 | ||
|
|
c5ae365a20 | ||
|
|
30f7de04c7 | ||
|
|
989d0987c6 | ||
|
|
e1014025f0 | ||
|
|
7fc69b7ce8 | ||
|
|
d88a23c922 | ||
|
|
d367deaea3 | ||
|
|
3e9eadcc69 | ||
|
|
da226ef205 | ||
|
|
a37a31f89a | ||
|
|
03c27df800 | ||
|
|
d198130038 | ||
|
|
06209877ea | ||
|
|
822a3ce5ec | ||
|
|
1f06c67d13 | ||
|
|
9dea140859 | ||
|
|
d5899b22ab | ||
|
|
dc895ed277 | ||
|
|
7315df8a86 | ||
|
|
349f5bea66 | ||
|
|
6aef860a81 | ||
|
|
e908cb9344 | ||
|
|
1a22e54d5b | ||
|
|
172b4b71d4 | ||
|
|
3873852567 | ||
|
|
5e349855a2 | ||
|
|
40bd9e0311 | ||
|
|
b437b58d06 | ||
|
|
c3137ba1cb | ||
|
|
2e13c1b738 | ||
|
|
122870a23e | ||
|
|
4e282e0d86 | ||
|
|
6020f76adb | ||
|
|
f3c2a2ffa7 | ||
|
|
11659a838b | ||
|
|
58b7b4e753 | ||
|
|
7cf8c31e53 | ||
|
|
df000b9e8f | ||
|
|
77e9f58899 | ||
|
|
0737aaafb2 | ||
|
|
d798f402f6 | ||
|
|
80c6221a05 | ||
|
|
f04b86dda4 | ||
|
|
0fd3ee9912 | ||
|
|
cb0b9b1f14 | ||
|
|
5a0ddd91ce | ||
|
|
d097bc765b | ||
|
|
b283fc1e99 | ||
|
|
0511e00d83 | ||
|
|
c8afa775d4 |
5
.changeset/thick-worms-peel.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@portaljs/remark-wiki-link': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Parse note embeds as regular wiki links (until we add proper support for note embeds).
|
||||||
5
examples/learn/next.config.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const nextConfig = {
|
||||||
|
swcMinify: false
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nextConfig
|
||||||
@@ -7,13 +7,21 @@ import { Mermaid } from '@portaljs/core';
|
|||||||
// to handle import statements. Instead, you must include components in scope
|
// to handle import statements. Instead, you must include components in scope
|
||||||
// here.
|
// here.
|
||||||
const components = {
|
const components = {
|
||||||
Table: dynamic(() => import('@portaljs/components').then(mod => mod.Table)),
|
Table: dynamic(() => import('@portaljs/components').then((mod) => mod.Table)),
|
||||||
Catalog: dynamic(() => import('@portaljs/components').then(mod => mod.Catalog)),
|
Catalog: dynamic(() =>
|
||||||
|
import('@portaljs/components').then((mod) => mod.Catalog)
|
||||||
|
),
|
||||||
mermaid: Mermaid,
|
mermaid: Mermaid,
|
||||||
Vega: dynamic(() => import('@portaljs/components').then(mod => mod.Vega)),
|
Vega: dynamic(() => import('@portaljs/components').then((mod) => mod.Vega)),
|
||||||
VegaLite: dynamic(() => import('@portaljs/components').then(mod => mod.VegaLite)),
|
VegaLite: dynamic(() =>
|
||||||
LineChart: dynamic(() => import('@portaljs/components').then(mod => mod.LineChart)),
|
import('@portaljs/components').then((mod) => mod.VegaLite)
|
||||||
FlatUiTable: dynamic(() => import('@portaljs/components').then(mod => mod.FlatUiTable)),
|
),
|
||||||
|
LineChart: dynamic(() =>
|
||||||
|
import('@portaljs/components').then((mod) => mod.LineChart)
|
||||||
|
),
|
||||||
|
FlatUiTable: dynamic(() =>
|
||||||
|
import('@portaljs/components').then((mod) => mod.FlatUiTable)
|
||||||
|
),
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
export default function DRD({ source }: { source: any }) {
|
export default function DRD({ source }: { source: any }) {
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ the key to a prosperous future.
|
|||||||
title: '',
|
title: '',
|
||||||
field: 'label',
|
field: 'label',
|
||||||
scale: {
|
scale: {
|
||||||
domain: ["Education"],
|
domain: ['Education'],
|
||||||
range: ['#64b5f6']
|
range: ['#64b5f6'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tooltip: [
|
tooltip: [
|
||||||
@@ -189,4 +189,3 @@ Frankfurt is a city that's recognized the power of education, and it's using tha
|
|||||||
One can only hope that more cities follow suit.
|
One can only hope that more cities follow suit.
|
||||||
|
|
||||||
[^1]: https://worldpopulationreview.com/world-cities/frankfurt-population
|
[^1]: https://worldpopulationreview.com/world-cities/frankfurt-population
|
||||||
|
|
||||||
|
|||||||
311
examples/openspending/package-lock.json
generated
@@ -14,7 +14,7 @@
|
|||||||
"@heroicons/react": "^2.0.18",
|
"@heroicons/react": "^2.0.18",
|
||||||
"@octokit/plugin-throttling": "^5.2.2",
|
"@octokit/plugin-throttling": "^5.2.2",
|
||||||
"@portaljs/ckan": "^0.0.2",
|
"@portaljs/ckan": "^0.0.2",
|
||||||
"@portaljs/components": "^0.1.12",
|
"@portaljs/components": "0.1.12",
|
||||||
"@portaljs/core": "^1.0.5",
|
"@portaljs/core": "^1.0.5",
|
||||||
"@portaljs/remark-callouts": "^1.0.5",
|
"@portaljs/remark-callouts": "^1.0.5",
|
||||||
"@portaljs/remark-embed": "^1.0.4",
|
"@portaljs/remark-embed": "^1.0.4",
|
||||||
@@ -1971,6 +1971,40 @@
|
|||||||
"@lit-labs/ssr-dom-shim": "^1.0.0"
|
"@lit-labs/ssr-dom-shim": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mapbox/mapbox-gl-style-spec": {
|
||||||
|
"version": "13.28.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.28.0.tgz",
|
||||||
|
"integrity": "sha512-B8xM7Fp1nh5kejfIl4SWeY0gtIeewbuRencqO3cJDrCHZpaPg7uY+V8abuR+esMeuOjRl5cLhVTP40v+1ywxbg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||||
|
"@mapbox/point-geometry": "^0.1.0",
|
||||||
|
"@mapbox/unitbezier": "^0.0.0",
|
||||||
|
"csscolorparser": "~1.0.2",
|
||||||
|
"json-stringify-pretty-compact": "^2.0.0",
|
||||||
|
"minimist": "^1.2.6",
|
||||||
|
"rw": "^1.3.3",
|
||||||
|
"sort-object": "^0.3.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"gl-style-composite": "bin/gl-style-composite.js",
|
||||||
|
"gl-style-format": "bin/gl-style-format.js",
|
||||||
|
"gl-style-migrate": "bin/gl-style-migrate.js",
|
||||||
|
"gl-style-validate": "bin/gl-style-validate.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mapbox/mapbox-gl-style-spec/node_modules/json-stringify-pretty-compact": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ=="
|
||||||
|
},
|
||||||
"node_modules/@mapbox/node-pre-gyp": {
|
"node_modules/@mapbox/node-pre-gyp": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz",
|
||||||
@@ -2020,6 +2054,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@mapbox/point-geometry": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@mapbox/unitbezier": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA=="
|
||||||
|
},
|
||||||
"node_modules/@mdx-js/mdx": {
|
"node_modules/@mdx-js/mdx": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-2.3.0.tgz",
|
||||||
@@ -2657,6 +2701,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.11.0.tgz",
|
||||||
"integrity": "sha512-AanzbulOHljrku1NGfafxdpTCfw2ENaWzH01N2vqQM+cUFbk868Cgh0xylz0JIM9BoKbfI++bdD6EYX0Q/UTEw=="
|
"integrity": "sha512-AanzbulOHljrku1NGfafxdpTCfw2ENaWzH01N2vqQM+cUFbk868Cgh0xylz0JIM9BoKbfI++bdD6EYX0Q/UTEw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@petamoriken/float16": {
|
||||||
|
"version": "3.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj3dU9kuMy8AqrreIboVh3KCJGSQO5T+dJ8JQFl369961jTWvPLP1GIlLy0FVoWehXLoI9BXygu/yzuNiIHBlg=="
|
||||||
|
},
|
||||||
"node_modules/@pkgr/utils": {
|
"node_modules/@pkgr/utils": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.1.tgz",
|
||||||
@@ -2676,6 +2725,14 @@
|
|||||||
"url": "https://opencollective.com/unts"
|
"url": "https://opencollective.com/unts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@planet/maps": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@planet/maps/-/maps-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-THvbooWXFZYyjSdoqi6MFNqnjrfnO5Oev1tKh6ORjxFru0N69gZwUfEduRjg99VNklmaAk2BPaCatgKs5qr0XA==",
|
||||||
|
"dependencies": {
|
||||||
|
"react-reconciler": "^0.29.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@portaljs/ckan": {
|
"node_modules/@portaljs/ckan": {
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@portaljs/ckan/-/ckan-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@portaljs/ckan/-/ckan-0.0.2.tgz",
|
||||||
@@ -2692,21 +2749,25 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@portaljs/components": {
|
"node_modules/@portaljs/components": {
|
||||||
"version": "0.1.12",
|
"version": "0.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/@portaljs/components/-/components-0.1.12.tgz",
|
"resolved": "file:../../packages/components/portaljs-components-0.1.12.tgz",
|
||||||
"integrity": "sha512-p7I7uOJYXo+jZgVJfgGW2RtjT02wpjsSiGb+QgQCdIdh7E1e9LKIWMx7wnaRqB1eS3Z+yxaYtG3+0tQEqyxNoQ==",
|
"integrity": "sha512-Cr+RQ7tkbIqtBNq5D8zeZEB2dOejxD0V78l/I4AbdjYI8jvQ4Evx6APEfhPs3im6LDEGrT28LslVTZJ6luslnw==",
|
||||||
"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"
|
||||||
@@ -2909,6 +2970,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/@rushstack/eslint-patch": {
|
"node_modules/@rushstack/eslint-patch": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz",
|
||||||
@@ -4424,6 +4495,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/clean-set": {
|
"node_modules/clean-set": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/clean-set/-/clean-set-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/clean-set/-/clean-set-1.1.2.tgz",
|
||||||
@@ -4735,6 +4811,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||||
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/csscolorparser": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w=="
|
||||||
|
},
|
||||||
"node_modules/cssesc": {
|
"node_modules/cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
@@ -5858,6 +5939,11 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/earcut": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
|
||||||
|
},
|
||||||
"node_modules/ecdsa-sig-formatter": {
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
@@ -7155,6 +7241,39 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/geotiff": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-FKvFTNowMU5K6lHYY2f83d4lS2rsCNdpUC28AX61x9ZzzqPNaWFElWv93xj0eJFaNyOYA63ic5OzJ88dHpoA5Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@petamoriken/float16": "^3.4.7",
|
||||||
|
"lerc": "^3.0.0",
|
||||||
|
"pako": "^2.0.4",
|
||||||
|
"parse-headers": "^2.0.2",
|
||||||
|
"quick-lru": "^6.1.1",
|
||||||
|
"web-worker": "^1.2.0",
|
||||||
|
"xml-utils": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/geotiff/node_modules/pako": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
||||||
|
},
|
||||||
|
"node_modules/geotiff/node_modules/quick-lru": {
|
||||||
|
"version": "6.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.1.tgz",
|
||||||
|
"integrity": "sha512-S27GBT+F0NTRiehtbrgaSE1idUAJ5bX8dPAQTdylEyNlrdcH5X4Lz7Edz3DYzecbsCluD5zO8ZNEe04z3D3u6Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
@@ -7831,9 +7950,7 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"optional": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.2.4",
|
"version": "5.2.4",
|
||||||
@@ -8784,6 +8901,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
|
||||||
"integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="
|
"integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="
|
||||||
},
|
},
|
||||||
|
"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/lerc": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww=="
|
||||||
|
},
|
||||||
"node_modules/levn": {
|
"node_modules/levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
@@ -8956,14 +9083,6 @@
|
|||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/magic-string": {
|
|
||||||
"version": "0.16.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.16.0.tgz",
|
|
||||||
"integrity": "sha512-c4BEos3y6G2qO0B9X7K0FVLOPT9uGrjYwYRLFmDqyl5YMboUviyecnXWp94fJTSMwPw2/sf+CEYt5AGpmklkkQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"vlq": "^0.2.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/make-dir": {
|
"node_modules/make-dir": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||||
@@ -9023,6 +9142,11 @@
|
|||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/mapbox-to-css-font": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-f+NBjJJY4T3dHtlEz1wCG7YFlkODEjFIYlxDdLIDMNpkSksqTt+l/d4rjuwItxuzkuMFvPyrjzV2lxRM4ePcIA=="
|
||||||
|
},
|
||||||
"node_modules/markdown-extensions": {
|
"node_modules/markdown-extensions": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz",
|
||||||
@@ -11492,6 +11616,32 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ol": {
|
||||||
|
"version": "7.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ol/-/ol-7.4.0.tgz",
|
||||||
|
"integrity": "sha512-bgBbiah694HhC0jt8ptEFNRXwgO8d6xWH3G97PCg4bmn9Li5nLLbi59oSrvqUI6VPVwonPQF1YcqJymxxyMC6A==",
|
||||||
|
"dependencies": {
|
||||||
|
"earcut": "^2.2.3",
|
||||||
|
"geotiff": "^2.0.7",
|
||||||
|
"ol-mapbox-style": "^10.1.0",
|
||||||
|
"pbf": "3.2.1",
|
||||||
|
"rbush": "^3.0.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/openlayers"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ol-mapbox-style": {
|
||||||
|
"version": "10.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-10.6.0.tgz",
|
||||||
|
"integrity": "sha512-s86QhCoyyKVRsYkvPzzdWd///bhYh3onWrBq4lNXnCd9G/hS6AoK023kn4zlDESVlTBDTWLz8vhOistp0M3TXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@mapbox/mapbox-gl-style-spec": "^13.23.1",
|
||||||
|
"mapbox-to-css-font": "^2.4.1",
|
||||||
|
"ol": "^7.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/once": {
|
"node_modules/once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
@@ -11638,6 +11788,11 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parse-headers": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA=="
|
||||||
|
},
|
||||||
"node_modules/parse-json": {
|
"node_modules/parse-json": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||||
@@ -11735,6 +11890,18 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pbf": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ieee754": "^1.1.12",
|
||||||
|
"resolve-protobuf-schema": "^2.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"pbf": "bin/pbf"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pend": {
|
"node_modules/pend": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||||
@@ -12055,6 +12222,11 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/protocol-buffers-schema": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="
|
||||||
|
},
|
||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
@@ -12173,6 +12345,19 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/quickselect": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
|
||||||
|
},
|
||||||
|
"node_modules/rbush": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
|
||||||
|
"dependencies": {
|
||||||
|
"quickselect": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
@@ -12221,6 +12406,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-markdown": {
|
"node_modules/react-markdown": {
|
||||||
"version": "8.0.7",
|
"version": "8.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz",
|
||||||
@@ -12290,6 +12488,21 @@
|
|||||||
"react-dom": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
"react-dom": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-reconciler": {
|
||||||
|
"version": "0.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
|
||||||
|
"integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0",
|
||||||
|
"scheduler": "^0.23.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
||||||
@@ -12828,6 +13041,14 @@
|
|||||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/resolve-protobuf-schema": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"protocol-buffers-schema": "^3.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/retext": {
|
"node_modules/retext": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz",
|
||||||
@@ -12949,28 +13170,6 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-re": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/rollup-plugin-re/-/rollup-plugin-re-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-TyFf3QaV/eJ/50k4wp5BM0SodGy0Idq0uOgvA1q3gHRwgXLPVX5y3CRKkBuHzKTZPC9CTZX7igKw5UvgjDls8w==",
|
|
||||||
"dependencies": {
|
|
||||||
"magic-string": "^0.16.0",
|
|
||||||
"rollup-pluginutils": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rollup-pluginutils": {
|
|
||||||
"version": "2.8.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
|
|
||||||
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"estree-walker": "^0.6.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rollup-pluginutils/node_modules/estree-walker": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
|
|
||||||
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="
|
|
||||||
},
|
|
||||||
"node_modules/rtl-css-js": {
|
"node_modules/rtl-css-js": {
|
||||||
"version": "1.16.1",
|
"version": "1.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",
|
||||||
@@ -13314,6 +13513,34 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sort-asc": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sort-desc": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-jfZacW5SKOP97BF5rX5kQfJmRVZP5/adDUTY8fCSPvNcXDVpUEe2pr/iKGlcyZzchRJZrswnp68fgk3qBXgkJw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sort-object": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-aAQiEdqFTTdsvUFxXm3umdo04J7MRljoVGbBlkH7BgNsMvVNAJyGj7C/wV1A8wHWAJj/YikeZbfuCKqhggNWGA==",
|
||||||
|
"dependencies": {
|
||||||
|
"sort-asc": "^0.1.0",
|
||||||
|
"sort-desc": "^0.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
@@ -15964,11 +16191,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vlq": {
|
|
||||||
"version": "0.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
|
|
||||||
"integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow=="
|
|
||||||
},
|
|
||||||
"node_modules/warning": {
|
"node_modules/warning": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
@@ -16173,6 +16395,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xml-utils": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-bWB489+RQQclC7A9OW8e5BzbT8Tu//jtAOvkYwewFr+Q9T9KDGvfzC1lp0pYPEQPEoPQLDkmxkepSC/2gIAZGw=="
|
||||||
|
},
|
||||||
"node_modules/xtend": {
|
"node_modules/xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@heroicons/react": "^2.0.18",
|
"@heroicons/react": "^2.0.18",
|
||||||
"@octokit/plugin-throttling": "^5.2.2",
|
"@octokit/plugin-throttling": "^5.2.2",
|
||||||
"@portaljs/ckan": "^0.0.2",
|
"@portaljs/ckan": "^0.0.2",
|
||||||
"@portaljs/components": "^0.1.12",
|
"@portaljs/components": "0.1.12",
|
||||||
"@portaljs/core": "^1.0.5",
|
"@portaljs/core": "^1.0.5",
|
||||||
"@portaljs/remark-callouts": "^1.0.5",
|
"@portaljs/remark-callouts": "^1.0.5",
|
||||||
"@portaljs/remark-embed": "^1.0.4",
|
"@portaljs/remark-embed": "^1.0.4",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { AppProps } from 'next/app';
|
import { AppProps } from 'next/app';
|
||||||
|
import '@portaljs/components/styles.css';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
import { NextSeo } from 'next-seo';
|
import { NextSeo } from 'next-seo';
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ import { GetStaticProps } from 'next';
|
|||||||
import Layout from '../../components/_shared/Layout';
|
import Layout from '../../components/_shared/Layout';
|
||||||
import { formatDate } from '@/utils/formatDate';
|
import { formatDate } from '@/utils/formatDate';
|
||||||
import parse from '../../lib/markdown';
|
import parse from '../../lib/markdown';
|
||||||
import DataRichDocument from '../../components/DataRichDocument';
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
const DataRichDocument = dynamic(
|
||||||
|
() => import('../../components/DataRichDocument'),
|
||||||
|
{ ssr: false }
|
||||||
|
);
|
||||||
|
|
||||||
export default function Page({ source, meta }) {
|
export default function Page({ source, meta }) {
|
||||||
return (
|
return (
|
||||||
@@ -46,7 +51,10 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
|
|||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const mddb = await clientPromise;
|
const mddb = await clientPromise;
|
||||||
let allDocuments = await mddb.getFiles({ extensions: ['mdx'], folder: 'stories' });
|
let allDocuments = await mddb.getFiles({
|
||||||
|
extensions: ['mdx'],
|
||||||
|
folder: 'stories',
|
||||||
|
});
|
||||||
|
|
||||||
const paths = allDocuments
|
const paths = allDocuments
|
||||||
.filter((page) => page.metadata?.isDraft !== true)
|
.filter((page) => page.metadata?.isDraft !== true)
|
||||||
|
|||||||
21
nx.json
@@ -5,7 +5,13 @@
|
|||||||
"default": {
|
"default": {
|
||||||
"runner": "nx/tasks-runners/default",
|
"runner": "nx/tasks-runners/default",
|
||||||
"options": {
|
"options": {
|
||||||
"cacheableOperations": ["build", "lint", "test", "e2e"]
|
"cacheableOperations": [
|
||||||
|
"build",
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"e2e",
|
||||||
|
"build-storybook"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -30,6 +36,14 @@
|
|||||||
"{workspaceRoot}/.eslintrc.json",
|
"{workspaceRoot}/.eslintrc.json",
|
||||||
"{workspaceRoot}/.eslintignore"
|
"{workspaceRoot}/.eslintignore"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"build-storybook": {
|
||||||
|
"inputs": [
|
||||||
|
"default",
|
||||||
|
"^production",
|
||||||
|
"{projectRoot}/.storybook/**/*",
|
||||||
|
"{projectRoot}/tsconfig.storybook.json"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"namedInputs": {
|
"namedInputs": {
|
||||||
@@ -39,7 +53,10 @@
|
|||||||
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
|
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
|
||||||
"!{projectRoot}/tsconfig.spec.json",
|
"!{projectRoot}/tsconfig.spec.json",
|
||||||
"!{projectRoot}/jest.config.[jt]s",
|
"!{projectRoot}/jest.config.[jt]s",
|
||||||
"!{projectRoot}/.eslintrc.json"
|
"!{projectRoot}/.eslintrc.json",
|
||||||
|
"!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)",
|
||||||
|
"!{projectRoot}/.storybook/**/*",
|
||||||
|
"!{projectRoot}/tsconfig.storybook.json"
|
||||||
],
|
],
|
||||||
"sharedGlobals": ["{workspaceRoot}/babel.config.json"]
|
"sharedGlobals": ["{workspaceRoot}/babel.config.json"]
|
||||||
},
|
},
|
||||||
|
|||||||
17055
package-lock.json
generated
22
package.json
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "portaljs",
|
"name": "portaljs",
|
||||||
"workspaces": ["./packages/*"],
|
"workspaces": [
|
||||||
|
"./packages/*"
|
||||||
|
],
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -18,10 +20,20 @@
|
|||||||
"@nrwl/js": "15.9.2",
|
"@nrwl/js": "15.9.2",
|
||||||
"@nrwl/linter": "15.9.2",
|
"@nrwl/linter": "15.9.2",
|
||||||
"@nrwl/next": "15.9.2",
|
"@nrwl/next": "15.9.2",
|
||||||
"@nrwl/react": "15.9.2",
|
"@nrwl/react": "^15.9.2",
|
||||||
"@nrwl/rollup": "15.9.2",
|
"@nrwl/rollup": "15.9.2",
|
||||||
|
"@nrwl/storybook": "15.9.2",
|
||||||
|
"@nrwl/webpack": "15.9.2",
|
||||||
"@nrwl/workspace": "15.9.2",
|
"@nrwl/workspace": "15.9.2",
|
||||||
|
"@nx/js": "16.6.0",
|
||||||
"@rollup/plugin-url": "^7.0.0",
|
"@rollup/plugin-url": "^7.0.0",
|
||||||
|
"@storybook/addon-essentials": "7.0.18",
|
||||||
|
"@storybook/addon-interactions": "7.0.18",
|
||||||
|
"@storybook/core-server": "7.0.18",
|
||||||
|
"@storybook/jest": "~0.1.0",
|
||||||
|
"@storybook/react-webpack5": "^7.0.18",
|
||||||
|
"@storybook/test-runner": "^0.11.0",
|
||||||
|
"@storybook/testing-library": "~0.2.0",
|
||||||
"@svgr/rollup": "^6.1.2",
|
"@svgr/rollup": "^6.1.2",
|
||||||
"@swc/core": "^1.2.173",
|
"@swc/core": "^1.2.173",
|
||||||
"@swc/helpers": "~0.5.0",
|
"@swc/helpers": "~0.5.0",
|
||||||
@@ -37,6 +49,7 @@
|
|||||||
"@typescript-eslint/parser": "^5.36.1",
|
"@typescript-eslint/parser": "^5.36.1",
|
||||||
"babel-jest": "^29.4.1",
|
"babel-jest": "^29.4.1",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
"cypress": "^12.2.0",
|
"cypress": "^12.2.0",
|
||||||
"eslint": "~8.15.0",
|
"eslint": "~8.15.0",
|
||||||
"eslint-config-next": "13.1.1",
|
"eslint-config-next": "13.1.1",
|
||||||
@@ -56,11 +69,16 @@
|
|||||||
"react-test-renderer": "18.2.0",
|
"react-test-renderer": "18.2.0",
|
||||||
"rehype-stringify": "^9.0.3",
|
"rehype-stringify": "^9.0.3",
|
||||||
"remark": "^14.0.3",
|
"remark": "^14.0.3",
|
||||||
|
"storybook-tailwind-dark-mode": "^1.0.22",
|
||||||
"swc-loader": "0.1.15",
|
"swc-loader": "0.1.15",
|
||||||
"ts-jest": "^29.0.5",
|
"ts-jest": "^29.0.5",
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"typescript": "~4.9.5",
|
"typescript": "~4.9.5",
|
||||||
"unist-util-select": "^4.0.3",
|
"unist-util-select": "^4.0.3",
|
||||||
"unist-util-visit": "^4.1.2"
|
"unist-util-visit": "^4.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
3
packages/components/.storybook/robots.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /$
|
||||||
|
Disallow: /
|
||||||
@@ -1,5 +1,25 @@
|
|||||||
# @portaljs/components
|
# @portaljs/components
|
||||||
|
|
||||||
|
## 0.3.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#980](https://github.com/datopian/portaljs/pull/980) [`38738525`](https://github.com/datopian/portaljs/commit/3873852567b1aab4827a716bd588bd5de3223e2b) Thanks [@demenech](https://github.com/demenech)! - Fix missing CSS styles for PDF component
|
||||||
|
|
||||||
|
## 0.3.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- [`2e13c1b7`](https://github.com/datopian/portaljs/commit/2e13c1b738ddac91a9419f5c0484406328bd1cd3) Thanks [@demenech](https://github.com/demenech)! - PDF and Excel components
|
||||||
|
|
||||||
|
- [#973](https://github.com/datopian/portaljs/pull/973) [`f3c2a2ff`](https://github.com/datopian/portaljs/commit/f3c2a2ffa7dcf9693bd25318c719ce58d27070b8) Thanks [@demenech](https://github.com/demenech)! - Implement <Excel /> component
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- [`80c6221a`](https://github.com/datopian/portaljs/commit/80c6221a05733f8c1dd0431bed4d72b1f9d7d636) Thanks [@luccasmmg](https://github.com/luccasmmg)! - Added the OpenLayers and the Map(Leaflet based) component
|
||||||
|
|
||||||
## 0.1.12
|
## 0.1.12
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@portaljs/components",
|
"name": "@portaljs/components",
|
||||||
"version": "0.1.12",
|
"version": "0.3.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "https://portaljs.org",
|
"description": "https://portaljs.org",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -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 && cp ./.storybook/robots.txt ./storybook-static",
|
||||||
"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/style.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,19 +28,29 @@
|
|||||||
"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",
|
||||||
|
"ag-grid-react": "^30.0.4",
|
||||||
|
"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",
|
||||||
|
"postcss-url": "^10.1.3",
|
||||||
"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",
|
||||||
|
"@react-pdf-viewer/core": "3.6.0",
|
||||||
|
"@react-pdf-viewer/default-layout": "3.6.0",
|
||||||
|
"pdfjs-dist": "2.15.349",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/addon-essentials": "^7.0.7",
|
"@storybook/addon-essentials": "^7.0.7",
|
||||||
@@ -48,13 +60,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 +77,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"
|
||||||
@@ -81,7 +99,7 @@
|
|||||||
"require": "./dist/components.umd.js"
|
"require": "./dist/components.umd.js"
|
||||||
},
|
},
|
||||||
"./styles.css": {
|
"./styles.css": {
|
||||||
"import": "./dist/styles.css"
|
"import": "./dist/style.css"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
BIN
packages/components/portaljs-components-0.1.12.tgz
Normal file
@@ -1,6 +1,10 @@
|
|||||||
|
console.log('PostCSS');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
plugins: {
|
plugins: {
|
||||||
|
'postcss-import': {},
|
||||||
|
'postcss-url': { url: 'inline' },
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
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 });
|
||||||
99
packages/components/src/components/Excel.tsx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import LoadingSpinner from './LoadingSpinner';
|
||||||
|
import { read, utils } from 'xlsx';
|
||||||
|
import { AgGridReact } from 'ag-grid-react';
|
||||||
|
import 'ag-grid-community/styles/ag-grid.css';
|
||||||
|
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
||||||
|
|
||||||
|
export type ExcelProps = {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Excel({ url }: ExcelProps) {
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
const [activeSheetName, setActiveSheetName] = useState<string>();
|
||||||
|
const [workbook, setWorkbook] = useState<any>();
|
||||||
|
const [rows, setRows] = useState<any>();
|
||||||
|
const [cols, setCols] = useState<any>();
|
||||||
|
|
||||||
|
const loadSpreadsheet = (wb: any, name: string) => {
|
||||||
|
setActiveSheetName(name);
|
||||||
|
const ws = wb.Sheets[name];
|
||||||
|
|
||||||
|
const range = utils.decode_range(ws['!ref'] || 'A1');
|
||||||
|
const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({
|
||||||
|
field: utils.encode_col(i),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const rowsAr = utils.sheet_to_json(ws, { header: 1 });
|
||||||
|
const rows = rowsAr.map((row) => {
|
||||||
|
const obj = {};
|
||||||
|
columns.forEach((col, i) => {
|
||||||
|
obj[col.field] = row[i];
|
||||||
|
});
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
setRows(rows);
|
||||||
|
setCols(columns);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then((res) => res.arrayBuffer())
|
||||||
|
.then((f) => {
|
||||||
|
const wb = read(f);
|
||||||
|
setWorkbook(wb);
|
||||||
|
loadSpreadsheet(wb, wb.SheetNames[0]);
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
|
return isLoading ? (
|
||||||
|
<div className="w-full flex items-center justify-center w-[600px] h-[300px]">
|
||||||
|
<LoadingSpinner />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{cols && rows && (
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className="ag-theme-alpine"
|
||||||
|
style={{ height: 400, width: '100%' }}
|
||||||
|
>
|
||||||
|
<AgGridReact
|
||||||
|
rowData={rows}
|
||||||
|
columnDefs={cols}
|
||||||
|
defaultColDef={{
|
||||||
|
resizable: true,
|
||||||
|
minWidth: 200,
|
||||||
|
flex: 1,
|
||||||
|
sortable: true,
|
||||||
|
filter: true,
|
||||||
|
}}
|
||||||
|
></AgGridReact>
|
||||||
|
</div>
|
||||||
|
<div className="border-t">
|
||||||
|
{workbook.SheetNames.map((name: string, idx: number) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
key={idx}
|
||||||
|
className={`text-sm px-3 pb-2 pt-4 border-b border-l border-r ${
|
||||||
|
name == activeSheetName ? 'font-semibold' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => loadSpreadsheet(workbook, name)}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
233
packages/components/src/components/Map.tsx
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
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,
|
||||||
|
LayersControl,
|
||||||
|
} from 'react-leaflet';
|
||||||
|
|
||||||
|
import 'leaflet/dist/leaflet.css';
|
||||||
|
import * as L from 'leaflet';
|
||||||
|
|
||||||
|
export type MapProps = {
|
||||||
|
layers: {
|
||||||
|
data: string | GeoJSON.GeoJSON;
|
||||||
|
name: string;
|
||||||
|
colorScale?: {
|
||||||
|
starting: string;
|
||||||
|
ending: string;
|
||||||
|
};
|
||||||
|
tooltip?:
|
||||||
|
| {
|
||||||
|
propNames: string[];
|
||||||
|
}
|
||||||
|
| boolean;
|
||||||
|
_id?: number;
|
||||||
|
}[];
|
||||||
|
title?: string;
|
||||||
|
center?: { latitude: number | undefined; longitude: number | undefined };
|
||||||
|
zoom?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Map({
|
||||||
|
layers = [
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
name: null,
|
||||||
|
colorScale: { starting: 'blue', ending: 'red' },
|
||||||
|
tooltip: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
center = { latitude: 45, longitude: 45 },
|
||||||
|
zoom = 2,
|
||||||
|
title = '',
|
||||||
|
}: MapProps) {
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
const [layersData, setLayersData] = useState<any>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadDataPromises = layers.map(async (layer) => {
|
||||||
|
let layerData: any;
|
||||||
|
|
||||||
|
if (typeof layer.data === 'string') {
|
||||||
|
// If "data" is string, assume it's a URL
|
||||||
|
setIsLoading(true);
|
||||||
|
layerData = await loadData(layer.data).then((res: any) => {
|
||||||
|
return JSON.parse(res);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Else, expect raw GeoJSON
|
||||||
|
layerData = layer.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer.colorScale) {
|
||||||
|
const colorScaleAr = chroma
|
||||||
|
.scale([layer.colorScale.starting, layer.colorScale.ending])
|
||||||
|
.mode('lch')
|
||||||
|
.colors(layerData.features.length);
|
||||||
|
|
||||||
|
layerData.features.forEach((feature, i) => {
|
||||||
|
// Only style if the feature doesn't have a color prop
|
||||||
|
if (feature.color === undefined) {
|
||||||
|
feature.color = colorScaleAr[i];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { name: layer.name, data: layerData };
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all(loadDataPromises).then((values) => {
|
||||||
|
setLayersData(values);
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return isLoading ? (
|
||||||
|
<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) => {
|
||||||
|
// Enable zoom using scroll wheel
|
||||||
|
map.target.scrollWheelZoom.enable();
|
||||||
|
|
||||||
|
// Create the title box
|
||||||
|
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);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TileLayer
|
||||||
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
/>
|
||||||
|
<LayersControl position="bottomright">
|
||||||
|
{layers.map((layer) => {
|
||||||
|
const data = layersData.find(
|
||||||
|
(layerData) => layerData.name === layer.name
|
||||||
|
)?.data;
|
||||||
|
|
||||||
|
return (
|
||||||
|
data && (
|
||||||
|
<LayersControl.Overlay key={layer.name} checked name={layer.name}>
|
||||||
|
<GeoJSONLayer
|
||||||
|
data={data}
|
||||||
|
// @ts-ignore
|
||||||
|
pointToLayer={(feature, latlng) => {
|
||||||
|
// This resolver an issue in which the bundled map was
|
||||||
|
// not finding the images
|
||||||
|
const leafletBase =
|
||||||
|
'https://unpkg.com/leaflet@1.9.4/dist/images/';
|
||||||
|
|
||||||
|
const icon = new L.Icon({
|
||||||
|
iconUrl: leafletBase + 'marker-icon.png',
|
||||||
|
iconRetinaUrl: leafletBase + 'marker-icon-2x.png',
|
||||||
|
shadowUrl: leafletBase + 'marker-shadow.png',
|
||||||
|
iconSize: [25, 41],
|
||||||
|
iconAnchor: [12, 41],
|
||||||
|
popupAnchor: [1, -34],
|
||||||
|
tooltipAnchor: [16, -28],
|
||||||
|
shadowSize: [41, 41],
|
||||||
|
});
|
||||||
|
|
||||||
|
const iconMarker = L.marker(latlng, { icon });
|
||||||
|
return iconMarker;
|
||||||
|
}}
|
||||||
|
style={(geoJsonFeature: any) => {
|
||||||
|
// Set the fill color of each feature when appliable
|
||||||
|
if (
|
||||||
|
!['Point', 'MultiPoint'].includes(geoJsonFeature.type)
|
||||||
|
) {
|
||||||
|
return { color: geoJsonFeature?.color };
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
eventHandlers={{
|
||||||
|
add: (e) => {
|
||||||
|
const featureGroup = e.target;
|
||||||
|
const tooltip = layer.tooltip;
|
||||||
|
|
||||||
|
featureGroup.eachLayer((featureLayer) => {
|
||||||
|
const feature = featureLayer.feature;
|
||||||
|
const geometryType = feature.geometry.type;
|
||||||
|
|
||||||
|
if (tooltip) {
|
||||||
|
const featurePropNames = Object.keys(
|
||||||
|
feature.properties
|
||||||
|
);
|
||||||
|
let includedFeaturePropNames;
|
||||||
|
|
||||||
|
if (tooltip === true) {
|
||||||
|
includedFeaturePropNames = featurePropNames;
|
||||||
|
} else {
|
||||||
|
includedFeaturePropNames = tooltip.propNames.filter(
|
||||||
|
(name) => featurePropNames.includes(name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includedFeaturePropNames) {
|
||||||
|
const tooltipContent = includedFeaturePropNames
|
||||||
|
.map(
|
||||||
|
(name) =>
|
||||||
|
`<b>${name}:</b> ${feature.properties[name]}`
|
||||||
|
)
|
||||||
|
.join('<br />');
|
||||||
|
|
||||||
|
featureLayer.bindTooltip(tooltipContent, {
|
||||||
|
direction: 'center',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
featureLayer.on({
|
||||||
|
mouseover: (event) => {
|
||||||
|
if (
|
||||||
|
['Polygon', 'MultiPolygon'].includes(geometryType)
|
||||||
|
) {
|
||||||
|
event.target.setStyle({
|
||||||
|
fillOpacity: 0.5,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mouseout: (event) => {
|
||||||
|
if (
|
||||||
|
['Polygon', 'MultiPolygon'].includes(geometryType)
|
||||||
|
) {
|
||||||
|
event.target.setStyle({
|
||||||
|
fillOpacity: 0.2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
;
|
||||||
|
</LayersControl.Overlay>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</LayersControl>
|
||||||
|
</MapContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
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
@@ -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
@@ -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
@@ -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 default 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
@@ -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
32
packages/components/src/components/PdfViewer.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Core viewer
|
||||||
|
import { Viewer, Worker, SpecialZoomLevel } from '@react-pdf-viewer/core';
|
||||||
|
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
|
||||||
|
|
||||||
|
// Import styles
|
||||||
|
import '@react-pdf-viewer/core/lib/styles/index.css';
|
||||||
|
import '@react-pdf-viewer/default-layout/lib/styles/index.css';
|
||||||
|
|
||||||
|
export interface PdfViewerProps {
|
||||||
|
url: string;
|
||||||
|
layout: boolean;
|
||||||
|
parentClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PdfViewer({
|
||||||
|
url,
|
||||||
|
layout = false,
|
||||||
|
parentClassName,
|
||||||
|
}: PdfViewerProps) {
|
||||||
|
const defaultLayoutPluginInstance = defaultLayoutPlugin();
|
||||||
|
return (
|
||||||
|
<Worker workerUrl="https://unpkg.com/pdfjs-dist@2.15.349/build/pdf.worker.js">
|
||||||
|
<div className={parentClassName}>
|
||||||
|
<Viewer
|
||||||
|
defaultScale={SpecialZoomLevel.PageWidth}
|
||||||
|
fileUrl={url}
|
||||||
|
plugins={layout ? [defaultLayoutPluginInstance] : []}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Worker>
|
||||||
|
);
|
||||||
|
}
|
||||||
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,11 @@
|
|||||||
@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 "include";
|
||||||
max-width: 100px;
|
@import "leaflet";
|
||||||
}
|
@import '@react-pdf-viewer/core/lib/styles/index.css';
|
||||||
}
|
@import '@react-pdf-viewer/default-layout/lib/styles/index.css';
|
||||||
|
@import 'ag-grid-community/styles/ag-grid.css';
|
||||||
|
@import 'ag-grid-community/styles/ag-theme-alpine.css';
|
||||||
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
export * from "./components/Table";
|
export * from './components/Table';
|
||||||
export * from "./components/Catalog";
|
export * from './components/Catalog';
|
||||||
export * from "./components/LineChart";
|
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';
|
||||||
|
export * from './components/PdfViewer';
|
||||||
|
export * from "./components/Excel";
|
||||||
|
|||||||
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[];
|
||||||
|
}
|
||||||
|
}
|
||||||
34
packages/components/stories/Excel.stories.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Excel, ExcelProps } from '../src/components/Excel';
|
||||||
|
|
||||||
|
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Components/Excel',
|
||||||
|
component: Excel,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
argTypes: {
|
||||||
|
url: {
|
||||||
|
description:
|
||||||
|
'Url of the file to be displayed e.g.: "https://url.to/data.csv"',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<ExcelProps>;
|
||||||
|
|
||||||
|
export const SingleSheet: Story = {
|
||||||
|
name: 'Excel file with just one sheet',
|
||||||
|
args: {
|
||||||
|
url: 'https://sheetjs.com/pres.xlsx',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MultipleSheet: Story = {
|
||||||
|
name: 'Excel file with multiple sheets',
|
||||||
|
args: {
|
||||||
|
url: 'https://storage.portaljs.org/IC-Gantt-Chart-Project-Template-8857.xlsx',
|
||||||
|
},
|
||||||
|
};
|
||||||
91
packages/components/stories/Map.stories.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
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: {
|
||||||
|
layers: {
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||||
|
name: 'Polygons',
|
||||||
|
tooltip: { propNames: ['name'] },
|
||||||
|
colorScale: {
|
||||||
|
starting: '#ff0000',
|
||||||
|
ending: '#00ff00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: 'Seas and Oceans Map',
|
||||||
|
center: { latitude: 45, longitude: 0 },
|
||||||
|
zoom: 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GeoJSONPoints: Story = {
|
||||||
|
name: 'GeoJSON points map',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||||
|
name: 'Points',
|
||||||
|
tooltip: { propNames: ['Location'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: 'Roads in York',
|
||||||
|
center: { latitude: 53.9614, longitude: -1.0739 },
|
||||||
|
zoom: 12,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GeoJSONMultipleLayers: Story = {
|
||||||
|
name: 'GeoJSON polygons and points map',
|
||||||
|
args: {
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson',
|
||||||
|
name: 'Points',
|
||||||
|
tooltip: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson',
|
||||||
|
name: 'Polygons',
|
||||||
|
tooltip: true,
|
||||||
|
colorScale: {
|
||||||
|
starting: '#ff0000',
|
||||||
|
ending: '#00ff00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: 'Polygons and points',
|
||||||
|
center: { latitude: 45, longitude: 0 },
|
||||||
|
zoom: 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
50
packages/components/stories/PdfViewer.stories.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { PdfViewer, PdfViewerProps } from '../src/components/PdfViewer';
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Components/PdfViewer',
|
||||||
|
component: PdfViewer,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
argTypes: {
|
||||||
|
url: {
|
||||||
|
description: 'URL to PDF file',
|
||||||
|
},
|
||||||
|
parentClassName: {
|
||||||
|
description: 'Classname for the parent div of the pdf viewer',
|
||||||
|
},
|
||||||
|
layour: {
|
||||||
|
description:
|
||||||
|
'Set to true if you want to have a layout with zoom level, page count, printing button etc',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<PdfViewerProps>;
|
||||||
|
|
||||||
|
export const PdfViewerStory: Story = {
|
||||||
|
name: 'PdfViewer',
|
||||||
|
args: {
|
||||||
|
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PdfViewerStoryWithLayout: Story = {
|
||||||
|
name: 'PdfViewer with the default layout',
|
||||||
|
args: {
|
||||||
|
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||||
|
layout: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PdfViewerStoryWithHeight: Story = {
|
||||||
|
name: 'PdfViewer with a custom height',
|
||||||
|
args: {
|
||||||
|
url: 'https://cdn.filestackcontent.com/wcrjf9qPTCKXV3hMXDwK',
|
||||||
|
parentClassName: 'h-96',
|
||||||
|
layout: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
content: [
|
||||||
theme: {
|
'./index.html',
|
||||||
extend: {},
|
'./src/**/*.{js,ts,jsx,tsx}',
|
||||||
},
|
'./stories/*.{js,ts,jsx,tsx}',
|
||||||
|
],
|
||||||
|
theme: {},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,29 +1,14 @@
|
|||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react';
|
||||||
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"
|
|
||||||
|
|
||||||
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 +19,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 +27,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 +56,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
|
||||||
21
packages/core/.storybook/main.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { StorybookConfig } from '@storybook/react-webpack5';
|
||||||
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
||||||
|
addons: [
|
||||||
|
'@storybook/addon-essentials',
|
||||||
|
'@storybook/addon-interactions',
|
||||||
|
'@nrwl/react/plugins/storybook',
|
||||||
|
'storybook-tailwind-dark-mode'
|
||||||
|
],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-webpack5',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|
||||||
|
// To customize your webpack configuration you can use the webpackFinal field.
|
||||||
|
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
|
||||||
|
// and https://nx.dev/packages/storybook/documents/custom-builder-configs
|
||||||
14
packages/core/.storybook/preview.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import './tailwind-imports.css';
|
||||||
|
|
||||||
|
const preview = {
|
||||||
|
globalTypes: {
|
||||||
|
darkMode: {
|
||||||
|
defaultValue: false, // Enable dark mode by default on all stories
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
defaultValue: 'dark', // Set your custom dark mode class name
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default preview;
|
||||||
3
packages/core/.storybook/tailwind-imports.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
31
packages/core/.storybook/tsconfig.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"outDir": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"../../node_modules/@nx/react/typings/styled-jsx.d.ts",
|
||||||
|
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.test.js"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.stories.ts",
|
||||||
|
"src/**/*.stories.js",
|
||||||
|
"src/**/*.stories.jsx",
|
||||||
|
"src/**/*.stories.tsx",
|
||||||
|
"src/**/*.stories.mdx",
|
||||||
|
".storybook/*.js",
|
||||||
|
".storybook/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
11
packages/core/postcss.config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// libs/shared/ui/postcss.config.js
|
||||||
|
const { join } = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {
|
||||||
|
config: join(__dirname, 'tailwind.config.js'),
|
||||||
|
},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -34,6 +34,37 @@
|
|||||||
"jestConfig": "packages/core/jest.config.ts",
|
"jestConfig": "packages/core/jest.config.ts",
|
||||||
"passWithNoTests": true
|
"passWithNoTests": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"storybook": {
|
||||||
|
"executor": "@nrwl/storybook:storybook",
|
||||||
|
"options": {
|
||||||
|
"port": 4400,
|
||||||
|
"configDir": "packages/core/.storybook"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"quiet": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"build-storybook": {
|
||||||
|
"executor": "@nrwl/storybook:build",
|
||||||
|
"outputs": ["{options.outputDir}"],
|
||||||
|
"options": {
|
||||||
|
"outputDir": "dist/storybook/core",
|
||||||
|
"configDir": "packages/core/.storybook"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"quiet": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-storybook": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"command": "test-storybook -c packages/core/.storybook --url=http://localhost:4400"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
packages/core/src/ui/Card/Card.stories.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Card } from './Card';
|
||||||
|
|
||||||
|
const meta: Meta<typeof Card> = {
|
||||||
|
component: Card,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Card>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
|
||||||
|
* See https://storybook.js.org/docs/react/api/csf
|
||||||
|
* to learn how to use render functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const blog = {
|
||||||
|
urlPath: "#",
|
||||||
|
title: "Card title goes here",
|
||||||
|
date: "2021-01-01",
|
||||||
|
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, diam quis accumsan maximus, quam libero porttitor nisl, vita",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Primary: Story = {
|
||||||
|
render: () => (
|
||||||
|
<Card className="md:col-span-3">
|
||||||
|
<Card.Title href={`${blog.urlPath}`}>
|
||||||
|
{blog.title}
|
||||||
|
</Card.Title>
|
||||||
|
<Card.Eyebrow
|
||||||
|
as="time"
|
||||||
|
dateTime={blog.date}
|
||||||
|
className="md:hidden"
|
||||||
|
decorate
|
||||||
|
>
|
||||||
|
{blog.date}
|
||||||
|
</Card.Eyebrow>
|
||||||
|
{blog.description && (
|
||||||
|
<Card.Description>
|
||||||
|
{blog.description}
|
||||||
|
</Card.Description>
|
||||||
|
)}
|
||||||
|
<Card.Cta>Read article</Card.Cta>
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
};
|
||||||
44
packages/core/tailwind.config.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind');
|
||||||
|
const { join } = require('path');
|
||||||
|
// const defaultTheme = require("tailwindcss/defaultTheme");
|
||||||
|
const colors = require("tailwindcss/colors");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
join(__dirname, './src/**/*.{js,ts,jsx,tsx}'),
|
||||||
|
...createGlobPatternsForDependencies(__dirname),
|
||||||
|
],
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
// support wider width for large screens >1440px eg. in hero
|
||||||
|
maxWidth: {
|
||||||
|
"8xl": "88rem",
|
||||||
|
},
|
||||||
|
// fontFamily: {
|
||||||
|
// sans: ["ui-sans-serif", ...defaultTheme.fontFamily.sans],
|
||||||
|
// serif: ["ui-serif", ...defaultTheme.fontFamily.serif],
|
||||||
|
// mono: ["ui-monospace", ...defaultTheme.fontFamily.mono],
|
||||||
|
// headings: ["-apple-system", ...defaultTheme.fontFamily.sans],
|
||||||
|
// },
|
||||||
|
colors: {
|
||||||
|
background: {
|
||||||
|
DEFAULT: colors.white,
|
||||||
|
dark: colors.slate[900],
|
||||||
|
},
|
||||||
|
primary: {
|
||||||
|
DEFAULT: colors.gray[700],
|
||||||
|
dark: colors.gray[300],
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: colors.sky[400],
|
||||||
|
dark: colors.sky[400],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* eslint global-require: off */
|
||||||
|
// plugins: [
|
||||||
|
// require("@tailwindcss/typography")
|
||||||
|
// ],
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"module": "es2020",
|
"module": "es2020",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
@@ -22,6 +23,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./tsconfig.spec.json"
|
"path": "./tsconfig.spec.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.storybook/tsconfig.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,11 @@
|
|||||||
"**/*.spec.js",
|
"**/*.spec.js",
|
||||||
"**/*.test.js",
|
"**/*.test.js",
|
||||||
"**/*.spec.jsx",
|
"**/*.spec.jsx",
|
||||||
"**/*.test.jsx"
|
"**/*.test.jsx",
|
||||||
|
"**/*.stories.ts",
|
||||||
|
"**/*.stories.js",
|
||||||
|
"**/*.stories.jsx",
|
||||||
|
"**/*.stories.tsx"
|
||||||
],
|
],
|
||||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,16 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
|||||||
if (isEmbed) {
|
if (isEmbed) {
|
||||||
const [isSupportedFormat, format] = isSupportedFileFormat(target);
|
const [isSupportedFormat, format] = isSupportedFileFormat(target);
|
||||||
if (!isSupportedFormat) {
|
if (!isSupportedFormat) {
|
||||||
|
// Temporarily render note transclusion as a regular wiki link
|
||||||
|
if (!format) {
|
||||||
|
wikiLink.data.hName = "a";
|
||||||
|
wikiLink.data.hProperties = {
|
||||||
|
className: classNames + " " + "transclusion",
|
||||||
|
href: hrefTemplate(link) + headingId,
|
||||||
|
};
|
||||||
|
wikiLink.data.hChildren = [{ type: "text", value: displayName }];
|
||||||
|
|
||||||
|
} else {
|
||||||
wikiLink.data.hName = "p";
|
wikiLink.data.hName = "p";
|
||||||
wikiLink.data.hChildren = [
|
wikiLink.data.hChildren = [
|
||||||
{
|
{
|
||||||
@@ -132,6 +142,7 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
|||||||
value: `![[${target}]]`,
|
value: `![[${target}]]`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
}
|
||||||
} else if (format === "pdf") {
|
} else if (format === "pdf") {
|
||||||
wikiLink.data.hName = "iframe";
|
wikiLink.data.hName = "iframe";
|
||||||
wikiLink.data.hProperties = {
|
wikiLink.data.hProperties = {
|
||||||
|
|||||||
@@ -108,7 +108,16 @@ function html(opts: HtmlOptions = {}) {
|
|||||||
if (isEmbed) {
|
if (isEmbed) {
|
||||||
const [isSupportedFormat, format] = isSupportedFileFormat(target);
|
const [isSupportedFormat, format] = isSupportedFileFormat(target);
|
||||||
if (!isSupportedFormat) {
|
if (!isSupportedFormat) {
|
||||||
|
// Temporarily render note transclusion as a regular wiki link
|
||||||
|
if (!format) {
|
||||||
|
this.tag(
|
||||||
|
`<a href="${hrefTemplate(link + headingId)}" class="${classNames} transclusion">`
|
||||||
|
);
|
||||||
|
this.raw(displayName);
|
||||||
|
this.tag("</a>");
|
||||||
|
} else {
|
||||||
this.raw(`![[${target}]]`);
|
this.raw(`![[${target}]]`);
|
||||||
|
}
|
||||||
} else if (format === "pdf") {
|
} else if (format === "pdf") {
|
||||||
this.tag(
|
this.tag(
|
||||||
`<iframe width="100%" src="${hrefTemplate(
|
`<iframe width="100%" src="${hrefTemplate(
|
||||||
|
|||||||
@@ -309,4 +309,16 @@ describe("micromark-extension-wiki-link", () => {
|
|||||||
expect(serialized).toBe('<p><a href="/" class="internal">/index</a></p>');
|
expect(serialized).toBe('<p><a href="/" class="internal">/index</a></p>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("transclusions", () => {
|
||||||
|
test("parsers a transclusion as a regular wiki link", () => {
|
||||||
|
const serialized = micromark("![[Some Page]]", "ascii", {
|
||||||
|
extensions: [syntax()],
|
||||||
|
htmlExtensions: [html() as any], // TODO type fix
|
||||||
|
});
|
||||||
|
expect(serialized).toBe(
|
||||||
|
'<p><a href="Some Page" class="internal new transclusion">Some Page</a></p>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -535,4 +535,28 @@ describe("remark-wiki-link", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("transclusions", () => {
|
||||||
|
test("replaces a transclusion with a regular wiki link", () => {
|
||||||
|
const processor = unified().use(markdown).use(wikiLinkPlugin);
|
||||||
|
|
||||||
|
let ast = processor.parse("![[Some Page]]");
|
||||||
|
ast = processor.runSync(ast);
|
||||||
|
|
||||||
|
expect(select("wikiLink", ast)).not.toEqual(null);
|
||||||
|
|
||||||
|
visit(ast, "wikiLink", (node: Node) => {
|
||||||
|
expect(node.data?.isEmbed).toEqual(true);
|
||||||
|
expect(node.data?.exists).toEqual(false);
|
||||||
|
expect(node.data?.permalink).toEqual("Some Page");
|
||||||
|
expect(node.data?.alias).toEqual(null);
|
||||||
|
expect(node.data?.hName).toEqual("a");
|
||||||
|
expect((node.data?.hProperties as any).className).toEqual(
|
||||||
|
"internal new transclusion"
|
||||||
|
);
|
||||||
|
expect((node.data?.hProperties as any).href).toEqual("Some Page");
|
||||||
|
expect((node.data?.hChildren as any)[0].value).toEqual("Some Page");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
5
site/.gitignore
vendored
@@ -35,3 +35,8 @@ yarn-error.log*
|
|||||||
|
|
||||||
# markdowndb
|
# markdowndb
|
||||||
markdown.db
|
markdown.db
|
||||||
|
|
||||||
|
# seo
|
||||||
|
robots.txt
|
||||||
|
sitemap-0.xml
|
||||||
|
sitemap.xml
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useEffect, useState } from 'react';
|
|||||||
const Stat = ({ title, value, ...props }) => {
|
const Stat = ({ title, value, ...props }) => {
|
||||||
return (
|
return (
|
||||||
<div {...props}>
|
<div {...props}>
|
||||||
<span className="text-6xl font-bold text-secondary">{value}</span>
|
<span className="text-4xl sm:text-6xl font-bold text-secondary">{value}</span>
|
||||||
<p className="text-lg font-medium">{title}</p>
|
<p className="text-lg font-medium">{title}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export default function Features() {
|
|||||||
>
|
>
|
||||||
<div className="absolute -inset-px rounded-xl border-2 border-transparent opacity-0 [background:linear-gradient(var(--quick-links-hover-bg,theme(colors.sky.50)),var(--quick-links-hover-bg,theme(colors.sky.50)))_padding-box,linear-gradient(to_top,theme(colors.blue.300),theme(colors.blue.400),theme(colors.blue.500))_border-box] group-hover:opacity-100 dark:[--quick-links-hover-bg:theme(colors.slate.800)]" />
|
<div className="absolute -inset-px rounded-xl border-2 border-transparent opacity-0 [background:linear-gradient(var(--quick-links-hover-bg,theme(colors.sky.50)),var(--quick-links-hover-bg,theme(colors.sky.50)))_padding-box,linear-gradient(to_top,theme(colors.blue.300),theme(colors.blue.400),theme(colors.blue.500))_border-box] group-hover:opacity-100 dark:[--quick-links-hover-bg:theme(colors.slate.800)]" />
|
||||||
<div className="relative overflow-hidden rounded-xl p-6">
|
<div className="relative overflow-hidden rounded-xl p-6">
|
||||||
<img src={feature.icon} alt="" className="h-24 w-auto" />
|
<img src={feature.icon} alt={feature.title} className="h-24 w-auto" />
|
||||||
<h2 className="mt-4 font-display text-base text-primary dark:text-primary-dark">
|
<h2 className="mt-4 font-display text-base text-primary dark:text-primary-dark">
|
||||||
<span className="absolute -inset-px rounded-xl" />
|
<span className="absolute -inset-px rounded-xl" />
|
||||||
{feature.title}
|
{feature.title}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useRef } from 'react';
|
|||||||
import ButtonLink from './ButtonLink';
|
import ButtonLink from './ButtonLink';
|
||||||
import NewsletterForm from './NewsletterForm';
|
import NewsletterForm from './NewsletterForm';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import DatahubExampleImg from "@/public/images/showcases/datahub.png"
|
import DatahubExampleImg from '@/public/images/showcases/datahub.webp';
|
||||||
|
|
||||||
const codeLanguage = 'javascript';
|
const codeLanguage = 'javascript';
|
||||||
const code = `export default {
|
const code = `export default {
|
||||||
@@ -41,7 +41,7 @@ export function Hero() {
|
|||||||
{/* Commented code on line 37, 39 and 113 will reenable the two columns hero */}
|
{/* Commented code on line 37, 39 and 113 will reenable the two columns hero */}
|
||||||
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-y-16 gap-x-8 px-4 lg:max-w-8xl lg:grid-cols-2 lg:px-8 xl:gap-x-16 xl:px-12">
|
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-y-16 gap-x-8 px-4 lg:max-w-8xl lg:grid-cols-2 lg:px-8 xl:gap-x-16 xl:px-12">
|
||||||
<div className="relative mb-10 lg:mb-0 md:text-center lg:text-left">
|
<div className="relative mb-10 lg:mb-0 md:text-center lg:text-left">
|
||||||
<div role="heading">
|
<div>
|
||||||
<h1 className="inline bg-gradient-to-r from-blue-500 via-blue-300 to-blue-500 bg-clip-text text-5xl tracking-tight text-transparent">
|
<h1 className="inline bg-gradient-to-r from-blue-500 via-blue-300 to-blue-500 bg-clip-text text-5xl tracking-tight text-transparent">
|
||||||
The JavaScript framework for data portals
|
The JavaScript framework for data portals
|
||||||
</h1>
|
</h1>
|
||||||
@@ -72,9 +72,11 @@ export function Hero() {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<img
|
<Image
|
||||||
src="/images/datopian_logo.png"
|
src="/images/datopian_logo.png"
|
||||||
alt="Datopian"
|
alt="Datopian"
|
||||||
|
width={24}
|
||||||
|
height={20}
|
||||||
className="mx-2 mb-1 h-6 inline bg-black rounded-full"
|
className="mx-2 mb-1 h-6 inline bg-black rounded-full"
|
||||||
/>
|
/>
|
||||||
<span>Datopian</span>
|
<span>Datopian</span>
|
||||||
@@ -85,7 +87,12 @@ export function Hero() {
|
|||||||
<div className="relative rounded-2xl bg-[#0A101F]/80 ring-1 ring-white/10 backdrop-blur">
|
<div className="relative rounded-2xl bg-[#0A101F]/80 ring-1 ring-white/10 backdrop-blur">
|
||||||
<div className="absolute -top-px left-20 right-11 h-px bg-gradient-to-r from-sky-300/0 via-sky-300/70 to-sky-300/0" />
|
<div className="absolute -top-px left-20 right-11 h-px bg-gradient-to-r from-sky-300/0 via-sky-300/70 to-sky-300/0" />
|
||||||
<div className="absolute -bottom-px left-11 right-20 h-px bg-gradient-to-r from-blue-400/0 via-blue-400 to-blue-400/0" />
|
<div className="absolute -bottom-px left-11 right-20 h-px bg-gradient-to-r from-blue-400/0 via-blue-400 to-blue-400/0" />
|
||||||
<Image src={DatahubExampleImg} alt="opendata.datahub.io" />
|
<Image
|
||||||
|
height={400}
|
||||||
|
width={600}
|
||||||
|
src={DatahubExampleImg}
|
||||||
|
alt="opendata.datahub.io"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
65
site/components/JSONLD.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { ArticleJsonLd } from 'next-seo';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
export default function JSONLD({
|
||||||
|
meta,
|
||||||
|
source,
|
||||||
|
}: {
|
||||||
|
meta: any;
|
||||||
|
source: string;
|
||||||
|
}): JSX.Element {
|
||||||
|
if (!source) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://portaljs.org';
|
||||||
|
const pageUrl = `${baseUrl}/${meta.urlPath}`;
|
||||||
|
|
||||||
|
const imageMatches = source.match(
|
||||||
|
/(?<=src: ")(.*)\.((png)|(jpg)|(jpeg))(?=")/g
|
||||||
|
);
|
||||||
|
let images = [];
|
||||||
|
if (imageMatches) {
|
||||||
|
images = [...imageMatches];
|
||||||
|
images = images.map((img) =>
|
||||||
|
img.startsWith('http')
|
||||||
|
? img
|
||||||
|
: `${baseUrl}${img.startsWith('/') ? '' : '/'}${img}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Component: JSX.Element;
|
||||||
|
|
||||||
|
const isBlog: boolean =
|
||||||
|
/^blog\/.*/.test(meta.urlPath) || meta.filetype === 'blog';
|
||||||
|
const isDoc: boolean = /^((docs)|(howtos\/)|(guide\/)).*/.test(meta.urlPath);
|
||||||
|
|
||||||
|
if (isBlog) {
|
||||||
|
Component = (
|
||||||
|
<ArticleJsonLd
|
||||||
|
type="BlogPosting"
|
||||||
|
url={pageUrl}
|
||||||
|
title={meta.title}
|
||||||
|
datePublished={meta.date}
|
||||||
|
dateModified={meta.date}
|
||||||
|
authorName={meta.authors.length ? meta.authors[0].name : 'PortalJS'}
|
||||||
|
description={meta.description}
|
||||||
|
images={images}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (isDoc) {
|
||||||
|
Component = (
|
||||||
|
<ArticleJsonLd
|
||||||
|
url={pageUrl}
|
||||||
|
title={meta.title}
|
||||||
|
images={images}
|
||||||
|
datePublished={meta.date}
|
||||||
|
dateModified={meta.date}
|
||||||
|
authorName={meta.authors.length ? meta.authors[0].name : 'PortalJS'}
|
||||||
|
description={meta.description}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Component;
|
||||||
|
}
|
||||||
@@ -54,12 +54,14 @@ function useTableOfContents(tableOfContents) {
|
|||||||
export default function Layout({
|
export default function Layout({
|
||||||
children,
|
children,
|
||||||
title,
|
title,
|
||||||
|
description,
|
||||||
tableOfContents = [],
|
tableOfContents = [],
|
||||||
isHomePage = false,
|
isHomePage = false,
|
||||||
sidebarTree = [],
|
sidebarTree = [],
|
||||||
}: {
|
}: {
|
||||||
children;
|
children;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
description?: string;
|
||||||
tableOfContents?;
|
tableOfContents?;
|
||||||
urlPath?: string;
|
urlPath?: string;
|
||||||
sidebarTree?: [];
|
sidebarTree?: [];
|
||||||
@@ -82,9 +84,9 @@ export default function Layout({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{title && <NextSeo title={title} />}
|
{title && <NextSeo title={title} description={description} />}
|
||||||
<Nav />
|
<Nav />
|
||||||
<div className="mx-auto p-6 bg-background dark:bg-background-dark">
|
<div className="mx-auto p-2 sm:p-6 bg-background dark:bg-background-dark">
|
||||||
{isHomePage && <Hero />}
|
{isHomePage && <Hero />}
|
||||||
|
|
||||||
<div className="relative mx-auto flex max-w-8xl justify-center sm:px-2 lg:px-8 xl:px-12">
|
<div className="relative mx-auto flex max-w-8xl justify-center sm:px-2 lg:px-8 xl:px-12">
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export default function MDXPage({ source, frontMatter }) {
|
|||||||
return <LayoutComponent {...frontMatter}>{children}</LayoutComponent>;
|
return <LayoutComponent {...frontMatter}>{children}</LayoutComponent>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<MDXRemote {...source} components={{ DocsPagination, NextSeo, Hero }} />
|
<MDXRemote {...source} components={{ DocsPagination, NextSeo, Hero }} />
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default function MobileNavigation({ navigation }) {
|
|||||||
>
|
>
|
||||||
{/* <Logomark className="h-9 w-9" /> */}
|
{/* <Logomark className="h-9 w-9" /> */}
|
||||||
<div className="font-extrabold text-slate-900 dark:text-white text-2xl ml-6">
|
<div className="font-extrabold text-slate-900 dark:text-white text-2xl ml-6">
|
||||||
{siteConfig.title}
|
PortalJS
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -95,7 +95,10 @@ export default function Nav() {
|
|||||||
<MobileNavigation navigation={siteConfig.navLinks} />
|
<MobileNavigation navigation={siteConfig.navLinks} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-none items-center">
|
<div className="flex flex-none items-center">
|
||||||
|
<div className="hidden sm:block">
|
||||||
<NavbarTitle />
|
<NavbarTitle />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="hidden lg:flex ml-8 mr-6 sm:mr-8 md:mr-0">
|
<div className="hidden lg:flex ml-8 mr-6 sm:mr-8 md:mr-0">
|
||||||
{siteConfig.navLinks.map((item) => (
|
{siteConfig.navLinks.map((item) => (
|
||||||
<NavItem item={item} key={item.name} />
|
<NavItem item={item} key={item.name} />
|
||||||
@@ -123,9 +126,8 @@ export default function Nav() {
|
|||||||
)}
|
)}
|
||||||
{siteConfig.github && (
|
{siteConfig.github && (
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
<
|
{/* @ts-ignore */}
|
||||||
// @ts-ignore
|
<GitHubButton
|
||||||
GitHubButton
|
|
||||||
href={siteConfig.github}
|
href={siteConfig.github}
|
||||||
data-color-scheme="no-preference: light; light: light; dark: dark;"
|
data-color-scheme="no-preference: light; light: light; dark: dark;"
|
||||||
data-size="large"
|
data-size="large"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default function NavItem({ item }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu as="div" className="relative">
|
<Menu as="div" role="menu" className="relative">
|
||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
{Object.prototype.hasOwnProperty.call(item, 'href') ? (
|
{Object.prototype.hasOwnProperty.call(item, 'href') ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ import Script from 'next/script';
|
|||||||
export default function NewsletterForm() {
|
export default function NewsletterForm() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://sibforms.com/forms/end-form/build/sib-styles.css"
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
id="sib-form-container"
|
id="sib-form-container"
|
||||||
className="mt-8 sm:mx-auto sm:text-center lg:text-left lg:mx-0"
|
className="mt-8 sm:mx-auto sm:text-center lg:text-left lg:mx-0"
|
||||||
@@ -119,6 +115,7 @@ export default function NewsletterForm() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Script
|
<Script
|
||||||
|
strategy="worker"
|
||||||
id="newsletter-submit-form"
|
id="newsletter-submit-form"
|
||||||
src="https://sibforms.com/forms/end-form/build/main.js"
|
src="https://sibforms.com/forms/end-form/build/main.js"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,26 +5,26 @@ const items = [
|
|||||||
{
|
{
|
||||||
title: 'Open Data Northern Ireland',
|
title: 'Open Data Northern Ireland',
|
||||||
href: 'https://www.opendatani.gov.uk/',
|
href: 'https://www.opendatani.gov.uk/',
|
||||||
image: '/images/showcases/odni.png',
|
image: '/images/showcases/odni.webp',
|
||||||
description: 'Government Open Data Portal',
|
description: 'Government Open Data Portal',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Birmingham City Observatory',
|
title: 'Birmingham City Observatory',
|
||||||
href: 'https://www.cityobservatory.birmingham.gov.uk/',
|
href: 'https://www.cityobservatory.birmingham.gov.uk/',
|
||||||
image: '/images/showcases/birmingham.png',
|
image: '/images/showcases/birmingham.webp',
|
||||||
description: 'Government Open Data Portal',
|
description: 'Government Open Data Portal',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'UAE Open Data',
|
title: 'UAE Open Data',
|
||||||
href: 'https://opendata.fcsc.gov.ae/',
|
href: 'https://opendata.fcsc.gov.ae/',
|
||||||
image: '/images/showcases/uae.png',
|
image: '/images/showcases/uae.webp',
|
||||||
description: 'Government Open Data Portal',
|
description: 'Government Open Data Portal',
|
||||||
sourceUrl: 'https://github.com/FCSCOpendata/frontend',
|
sourceUrl: 'https://github.com/FCSCOpendata/frontend',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Datahub Open Data',
|
title: 'Datahub Open Data',
|
||||||
href: 'https://opendata.datahub.io/',
|
href: 'https://opendata.datahub.io/',
|
||||||
image: '/images/showcases/datahub.png',
|
image: '/images/showcases/datahub.webp',
|
||||||
description: 'Demo Data Portal by DataHub',
|
description: 'Demo Data Portal by DataHub',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
BIN
site/content/assets/blog/2023-07-18-map-polygons-and-points.png
Normal file
|
After Width: | Height: | Size: 416 KiB |
BIN
site/content/assets/blog/2023-07-18-map-polygons-on-region.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
site/content/assets/blog/2023-07-18-map-tooltips.png
Normal file
|
After Width: | Height: | Size: 467 KiB |
BIN
site/content/assets/blog/gh-authorize.png
Normal file
|
After Width: | Height: | Size: 792 KiB |
BIN
site/content/assets/blog/gh-desktop-clone-path-select.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
site/content/assets/blog/gh-desktop-clone-signin.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
site/content/assets/blog/gh-desktop-clone.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
site/content/assets/blog/gh-desktop-no-local-changes.png
Normal file
|
After Width: | Height: | Size: 237 KiB |
BIN
site/content/assets/blog/gh-desktop-signin-using-browser.png
Normal file
|
After Width: | Height: | Size: 233 KiB |
BIN
site/content/assets/blog/gh-desktop-starting-screen.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
site/content/assets/blog/github-desktop-add-commit-message.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
site/content/assets/blog/github-desktop-all-changed-files.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
site/content/assets/blog/github-desktop-commit-message.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
site/content/assets/blog/github-desktop-history-after-push.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
site/content/assets/blog/github-desktop-history.png
Normal file
|
After Width: | Height: | Size: 277 KiB |
BIN
site/content/assets/blog/live-book-home-page.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
site/content/assets/blog/live-book.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
site/content/assets/blog/obsidian-content-add-folder-2.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
site/content/assets/blog/obsidian-content-add-folder.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
site/content/assets/blog/obsidian-content-book-index-2.png
Normal file
|
After Width: | Height: | Size: 260 KiB |
BIN
site/content/assets/blog/obsidian-content-book-index-3.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
site/content/assets/blog/obsidian-content-book-index.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
site/content/assets/blog/obsidian-content-book.png
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
site/content/assets/blog/obsidian-content-index-add-link-2.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
site/content/assets/blog/obsidian-content-index-add-link.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 254 KiB |
BIN
site/content/assets/blog/obsidian-content-index-callout.png
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
site/content/assets/blog/obsidian-content-index-edit.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
site/content/assets/blog/obsidian-content-index-link-aliases.png
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
site/content/assets/blog/obsidian-content-start.png
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
site/content/assets/blog/obsidian-starting.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
site/content/assets/blog/tutorial-2-result.png
Normal file
|
After Width: | Height: | Size: 305 KiB |
BIN
site/content/assets/blog/vercel-dashboard.png
Normal file
|
After Width: | Height: | Size: 277 KiB |
BIN
site/content/assets/blog/vercel-project-dashboard.png
Normal file
|
After Width: | Height: | Size: 444 KiB |