Compare commits
1 Commits
19-markdow
...
fivethirty
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c85934d17a |
1
.gitignore
vendored
@@ -16,7 +16,6 @@ node_modules
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
.obsidian
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
|
||||
@@ -140,7 +140,7 @@ function MobileNavigation(props) {
|
||||
</div>
|
||||
<nav className="mt-6">
|
||||
<ul className="-my-2 divide-y divide-zinc-100 text-base text-zinc-800 dark:divide-zinc-100/5 dark:text-zinc-300">
|
||||
<MobileNavItem href="https://github.com/datopian/portaljs/tree/main/examples/turing">
|
||||
<MobileNavItem href="https://github.com/leondz/hatespeechdata">
|
||||
View on Github <GithubIcon />
|
||||
</MobileNavItem>
|
||||
</ul>
|
||||
@@ -179,7 +179,7 @@ function DesktopNavigation(props) {
|
||||
return (
|
||||
<nav {...props}>
|
||||
<ul className="flex rounded-full bg-white/90 px-3 text-sm font-medium text-zinc-800 shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur dark:bg-zinc-800/90 dark:text-zinc-200 dark:ring-white/10">
|
||||
<NavItem href="https://github.com/datopian/portaljs/tree/main/examples/turing">
|
||||
<NavItem href="https://github.com/leondz/hatespeechdata">
|
||||
View on Github <GithubIcon />
|
||||
</NavItem>
|
||||
</ul>
|
||||
@@ -36,7 +36,7 @@ In the following page type `content/datasets/<name-of-the-file>.md`. if you want
|
||||
|
||||
### Fill in content
|
||||
|
||||
Copy the contents of `templates/dataset.md` or `templates/keywords.md` respectively to the camp below, filling out the fields with the correct data format. Everything below the second `---` will automatically get rendered into the page, so you may add any standard markdown fields e.g tables, headings, lists...
|
||||
Copy the contents of `templates/dataset.md` or `templates/keywords.md` respectively to the camp below, filling out the fields with the correct data format
|
||||
|
||||

|
||||
|
||||
BIN
examples/alan-turing-portal/markdown.db
Normal file
@@ -23,8 +23,13 @@
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.4",
|
||||
"@tanstack/react-table": "^8.8.5",
|
||||
"@types/node": "18.16.0",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-dom": "18.2.0",
|
||||
"autoprefixer": "^10.4.12",
|
||||
"clsx": "^1.2.1",
|
||||
"eslint": "8.39.0",
|
||||
"eslint-config-next": "13.3.1",
|
||||
"fast-glob": "^3.2.11",
|
||||
"feed": "^4.2.2",
|
||||
"flexsearch": "^0.7.31",
|
||||
@@ -56,9 +61,6 @@
|
||||
"tailwindcss": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.16.0",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-dom": "18.2.0",
|
||||
"eslint": "8.26.0",
|
||||
"eslint-config-next": "13.0.2",
|
||||
"prettier": "^2.8.7",
|
||||
@@ -550,9 +552,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
@@ -582,9 +584,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/source-map": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
|
||||
"integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==",
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
@@ -598,13 +600,13 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.18",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
|
||||
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
|
||||
"version": "0.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
|
||||
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/ssr-dom-shim": {
|
||||
@@ -1346,7 +1348,6 @@
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-8yQrvS6sMpSwIovhPOwfyNf2Wz6v/B62LFSVYQ85+Rq3tLsBIG7rP5geMxaijTUxSkrO6RzN/IRuIAADYQsleA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
@@ -1477,148 +1478,148 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||
"integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
|
||||
"@webassemblyjs/helper-numbers": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/floating-point-hex-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
|
||||
"integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-api-error": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
|
||||
"integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
|
||||
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
|
||||
"integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
|
||||
"integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
|
||||
"integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
|
||||
"integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
|
||||
"integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
|
||||
"integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-buffer": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/wasm-gen": "1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ieee754": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
|
||||
"integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
|
||||
"integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@xtuc/ieee754": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/leb128": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
|
||||
"integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
|
||||
"integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/utf8": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
|
||||
"integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
|
||||
"integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
|
||||
"integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-opt": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6",
|
||||
"@webassemblyjs/wast-printer": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-buffer": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.1",
|
||||
"@webassemblyjs/wasm-gen": "1.11.1",
|
||||
"@webassemblyjs/wasm-opt": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1",
|
||||
"@webassemblyjs/wast-printer": "1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-gen": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
|
||||
"integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
|
||||
"integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
"@webassemblyjs/utf8": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/ieee754": "1.11.1",
|
||||
"@webassemblyjs/leb128": "1.11.1",
|
||||
"@webassemblyjs/utf8": "1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
|
||||
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
|
||||
"integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-buffer": "1.11.1",
|
||||
"@webassemblyjs/wasm-gen": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
|
||||
"integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
"@webassemblyjs/utf8": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/ieee754": "1.11.1",
|
||||
"@webassemblyjs/leb128": "1.11.1",
|
||||
"@webassemblyjs/utf8": "1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
|
||||
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
|
||||
"integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
@@ -3650,9 +3651,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz",
|
||||
"integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==",
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
|
||||
"integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
@@ -3727,9 +3728,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz",
|
||||
"integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==",
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
|
||||
"integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/es-shim-unscopables": {
|
||||
@@ -5409,9 +5410,9 @@
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
|
||||
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
|
||||
},
|
||||
"node_modules/http-proxy-agent": {
|
||||
"version": "4.0.1",
|
||||
@@ -6117,9 +6118,9 @@
|
||||
"integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA=="
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
@@ -10807,9 +10808,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/schema-utils": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz",
|
||||
"integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
@@ -10875,9 +10876,9 @@
|
||||
"integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA=="
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
||||
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
|
||||
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"randombytes": "^2.1.0"
|
||||
@@ -11495,9 +11496,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.17.3",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz",
|
||||
"integrity": "sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==",
|
||||
"version": "5.14.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
||||
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
@@ -11513,16 +11514,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
"version": "5.3.8",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz",
|
||||
"integrity": "sha512-WiHL3ElchZMsK27P8uIUh4604IgJyAW47LVXGbEoB21DbQcZ+OuMpGjVYnEUaqcWM6dO8uS2qUbA7LSCWqvsbg==",
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz",
|
||||
"integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"@jridgewell/trace-mapping": "^0.3.7",
|
||||
"jest-worker": "^27.4.5",
|
||||
"schema-utils": "^3.1.1",
|
||||
"serialize-javascript": "^6.0.1",
|
||||
"terser": "^5.16.8"
|
||||
"serialize-javascript": "^6.0.0",
|
||||
"terser": "^5.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
@@ -12812,22 +12813,22 @@
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.82.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz",
|
||||
"integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==",
|
||||
"version": "5.74.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
|
||||
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
"@webassemblyjs/ast": "^1.11.5",
|
||||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"@types/estree": "^0.0.51",
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/wasm-edit": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.13.0",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"enhanced-resolve": "^5.10.0",
|
||||
"es-module-lexer": "^0.9.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -12836,9 +12837,9 @@
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.1.2",
|
||||
"schema-utils": "^3.1.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.7",
|
||||
"terser-webpack-plugin": "^5.1.3",
|
||||
"watchpack": "^2.4.0",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
@@ -12875,6 +12876,12 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/@types/estree": {
|
||||
"version": "0.0.51",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
|
||||
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/webpack/node_modules/eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
@@ -13701,9 +13708,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
@@ -13724,9 +13731,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"@jridgewell/source-map": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
|
||||
"integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==",
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
@@ -13740,13 +13747,13 @@
|
||||
"peer": true
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.18",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
|
||||
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
|
||||
"version": "0.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
|
||||
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"@lit-labs/ssr-dom-shim": {
|
||||
@@ -14272,7 +14279,6 @@
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-8yQrvS6sMpSwIovhPOwfyNf2Wz6v/B62LFSVYQ85+Rq3tLsBIG7rP5geMxaijTUxSkrO6RzN/IRuIAADYQsleA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
@@ -14355,148 +14361,148 @@
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||
"integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
|
||||
"@webassemblyjs/helper-numbers": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/floating-point-hex-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
|
||||
"integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
|
||||
"peer": true
|
||||
},
|
||||
"@webassemblyjs/helper-api-error": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
|
||||
"integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
|
||||
"peer": true
|
||||
},
|
||||
"@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
|
||||
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
|
||||
"integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
|
||||
"peer": true
|
||||
},
|
||||
"@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
|
||||
"integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
|
||||
"integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/helper-wasm-bytecode": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
|
||||
"integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
|
||||
"peer": true
|
||||
},
|
||||
"@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
|
||||
"integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
|
||||
"integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-buffer": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/wasm-gen": "1.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ieee754": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
|
||||
"integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
|
||||
"integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@xtuc/ieee754": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/leb128": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
|
||||
"integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
|
||||
"integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/utf8": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
|
||||
"integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
|
||||
"peer": true
|
||||
},
|
||||
"@webassemblyjs/wasm-edit": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
|
||||
"integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
|
||||
"integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-opt": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6",
|
||||
"@webassemblyjs/wast-printer": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-buffer": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.1",
|
||||
"@webassemblyjs/wasm-gen": "1.11.1",
|
||||
"@webassemblyjs/wasm-opt": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1",
|
||||
"@webassemblyjs/wast-printer": "1.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/wasm-gen": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
|
||||
"integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
|
||||
"integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
"@webassemblyjs/utf8": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/ieee754": "1.11.1",
|
||||
"@webassemblyjs/leb128": "1.11.1",
|
||||
"@webassemblyjs/utf8": "1.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
|
||||
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
|
||||
"integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-buffer": "1.11.1",
|
||||
"@webassemblyjs/wasm-gen": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
|
||||
"integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
"@webassemblyjs/utf8": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
|
||||
"@webassemblyjs/ieee754": "1.11.1",
|
||||
"@webassemblyjs/leb128": "1.11.1",
|
||||
"@webassemblyjs/utf8": "1.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
|
||||
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
|
||||
"integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
@@ -15979,9 +15985,9 @@
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz",
|
||||
"integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==",
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
|
||||
"integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
@@ -16038,9 +16044,9 @@
|
||||
}
|
||||
},
|
||||
"es-module-lexer": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz",
|
||||
"integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==",
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
|
||||
"integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
|
||||
"peer": true
|
||||
},
|
||||
"es-shim-unscopables": {
|
||||
@@ -17299,9 +17305,9 @@
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
|
||||
},
|
||||
"http-cache-semantics": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
|
||||
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
|
||||
},
|
||||
"http-proxy-agent": {
|
||||
"version": "4.0.1",
|
||||
@@ -17788,9 +17794,9 @@
|
||||
"integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA=="
|
||||
},
|
||||
"json5": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.0"
|
||||
@@ -21042,9 +21048,9 @@
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz",
|
||||
"integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
@@ -21090,9 +21096,9 @@
|
||||
"integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA=="
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
||||
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
|
||||
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"randombytes": "^2.1.0"
|
||||
@@ -21543,9 +21549,9 @@
|
||||
"integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.17.3",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz",
|
||||
"integrity": "sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==",
|
||||
"version": "5.14.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
||||
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
@@ -21555,16 +21561,16 @@
|
||||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "5.3.8",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz",
|
||||
"integrity": "sha512-WiHL3ElchZMsK27P8uIUh4604IgJyAW47LVXGbEoB21DbQcZ+OuMpGjVYnEUaqcWM6dO8uS2qUbA7LSCWqvsbg==",
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz",
|
||||
"integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"@jridgewell/trace-mapping": "^0.3.7",
|
||||
"jest-worker": "^27.4.5",
|
||||
"schema-utils": "^3.1.1",
|
||||
"serialize-javascript": "^6.0.1",
|
||||
"terser": "^5.16.8"
|
||||
"serialize-javascript": "^6.0.0",
|
||||
"terser": "^5.7.2"
|
||||
}
|
||||
},
|
||||
"text-table": {
|
||||
@@ -22598,22 +22604,22 @@
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.82.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz",
|
||||
"integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==",
|
||||
"version": "5.74.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
|
||||
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
"@webassemblyjs/ast": "^1.11.5",
|
||||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"@types/estree": "^0.0.51",
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/wasm-edit": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.13.0",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"enhanced-resolve": "^5.10.0",
|
||||
"es-module-lexer": "^0.9.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -22622,13 +22628,19 @@
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.1.2",
|
||||
"schema-utils": "^3.1.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.7",
|
||||
"terser-webpack-plugin": "^5.1.3",
|
||||
"watchpack": "^2.4.0",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/estree": {
|
||||
"version": "0.0.51",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
|
||||
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
|
||||
"peer": true
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
@@ -6,6 +6,7 @@ import { Card } from '../components/Card'
|
||||
import Head from 'next/head'
|
||||
import parse from '../lib/markdown'
|
||||
import { Mermaid } from '@flowershow/core';
|
||||
import { Header } from '../components/Header';
|
||||
|
||||
export const getStaticProps = async ({ params }) => {
|
||||
const urlPath = params.slug ? params.slug.join('/') : ''
|
||||
@@ -81,13 +82,15 @@ export default function DRDPage({ mdxSource }) {
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<Head>
|
||||
<title>{meta.title}</title>
|
||||
</Head>
|
||||
<Container className="mt-9 relative">
|
||||
<Container className="mt-16 lg:mt-32 relative">
|
||||
<Header />
|
||||
<article>
|
||||
<header className="flex flex-col">
|
||||
<h1 className="text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
|
||||
<h1 className="mt-6 text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
|
||||
{meta.title}
|
||||
</h1>
|
||||
<Card as="article">
|
||||
|
Before Width: | Height: | Size: 566 B After Width: | Height: | Size: 566 B |
@@ -1,10 +1,4 @@
|
||||
This is a replica of the awesome data.fivethirtyeight.com using PortalJS.
|
||||
|
||||
You might be asking why we did that, there are three main reasons:
|
||||
|
||||
- The website has a great UI, with multiple datasets being displayed elegantly and with simplicity.
|
||||
- PortalJS allows us to add more functionality to it e.g dataset previews and search functionality.
|
||||
- The project follows our same principles of open sourcing and free data, with every dataset being publicly available on Github.
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -1,11 +1,46 @@
|
||||
[
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-forecasts",
|
||||
"name": "nba-forecasts",
|
||||
"displayName": "nba-<span class=\"lastword\">forecasts</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-08T22:33:43.000Z",
|
||||
"title": "2022-23 NBA Predictions",
|
||||
"url": "https://projects.fivethirtyeight.com/2023-nba-predictions/"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"https://projects.fivethirtyeight.com/nba-model/nba_elo.csv",
|
||||
"https://projects.fivethirtyeight.com/nba-model/nba_elo_latest.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/soccer-spi",
|
||||
"name": "soccer-spi",
|
||||
"displayName": "soccer-<span class=\"lastword\">spi</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-08T22:17:18.000Z",
|
||||
"title": "Club Soccer Predictions",
|
||||
"url": "https://projects.fivethirtyeight.com/soccer-predictions/"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches_latest.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/club/spi_global_rankings.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/international/spi_matches_intl.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/international/spi_global_rankings_intl.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/polls",
|
||||
"name": "polls",
|
||||
"displayName": "<span class=\"lastword\">polls</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T14:35:40.000Z",
|
||||
"date": "2023-05-08T20:36:59.000Z",
|
||||
"title": "Latest Polls",
|
||||
"url": "https://projects.fivethirtyeight.com/polls/"
|
||||
}
|
||||
@@ -28,45 +63,13 @@
|
||||
"https://projects.fivethirtyeight.com/2020-general-data/presidential_poll_averages_2020.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-generic-ballot",
|
||||
"name": "congress-generic-ballot",
|
||||
"displayName": "congress-generic-<span class=\"lastword\">ballot</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T14:35:40.000Z",
|
||||
"title": "Do Voters Want Democrats Or Republicans In Congress?",
|
||||
"url": "https://projects.fivethirtyeight.com/congress-generic-ballot-polls/"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"https://projects.fivethirtyeight.com/generic-ballot-data/generic_polllist.csv",
|
||||
"https://projects.fivethirtyeight.com/polls/data/generic_ballot_averages.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-forecasts",
|
||||
"name": "nba-forecasts",
|
||||
"displayName": "nba-<span class=\"lastword\">forecasts</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T11:15:46.000Z",
|
||||
"title": "2022-23 NBA Predictions",
|
||||
"url": "https://projects.fivethirtyeight.com/2023-nba-predictions/"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"https://projects.fivethirtyeight.com/nba-model/nba_elo.csv",
|
||||
"https://projects.fivethirtyeight.com/nba-model/nba_elo_latest.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-raptor",
|
||||
"name": "nba-raptor",
|
||||
"displayName": "nba-<span class=\"lastword\">raptor</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T11:13:20.000Z",
|
||||
"date": "2023-05-08T11:15:48.000Z",
|
||||
"title": "The Best NBA Players, According To RAPTOR",
|
||||
"rowspan": 3,
|
||||
"url": "https://projects.fivethirtyeight.com/nba-player-ratings/"
|
||||
@@ -89,32 +92,13 @@
|
||||
"https://projects.fivethirtyeight.com/nba-model/2023/latest_RAPTOR_by_player.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/soccer-spi",
|
||||
"name": "soccer-spi",
|
||||
"displayName": "soccer-<span class=\"lastword\">spi</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T05:25:51.000Z",
|
||||
"title": "Club Soccer Predictions",
|
||||
"url": "https://projects.fivethirtyeight.com/soccer-predictions/"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches_latest.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/club/spi_global_rankings.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/international/spi_matches_intl.csv",
|
||||
"https://projects.fivethirtyeight.com/soccer-api/international/spi_global_rankings_intl.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/nhl-forecasts",
|
||||
"name": "nhl-forecasts",
|
||||
"displayName": "nhl-<span class=\"lastword\">forecasts</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T04:53:22.000Z",
|
||||
"date": "2023-05-08T04:18:20.000Z",
|
||||
"title": "2022-23 NHL Predictions",
|
||||
"url": "https://projects.fivethirtyeight.com/2023-nhl-predictions/"
|
||||
}
|
||||
@@ -130,7 +114,7 @@
|
||||
"displayName": "mlb-<span class=\"lastword\">elo</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-11T02:35:49.000Z",
|
||||
"date": "2023-05-08T02:25:55.000Z",
|
||||
"title": "2023 MLB Predictions",
|
||||
"url": "https://projects.fivethirtyeight.com/2023-mlb-predictions/"
|
||||
}
|
||||
@@ -140,6 +124,22 @@
|
||||
"https://projects.fivethirtyeight.com/mlb-api/mlb_elo_latest.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-generic-ballot",
|
||||
"name": "congress-generic-ballot",
|
||||
"displayName": "congress-generic-<span class=\"lastword\">ballot</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-05-02T13:48:41.000Z",
|
||||
"title": "Do Voters Want Democrats Or Republicans In Congress?",
|
||||
"url": "https://projects.fivethirtyeight.com/congress-generic-ballot-polls/"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"https://projects.fivethirtyeight.com/generic-ballot-data/generic_polllist.csv",
|
||||
"https://projects.fivethirtyeight.com/polls/data/generic_ballot_averages.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-demographics",
|
||||
"name": "congress-demographics",
|
||||
@@ -211,6 +211,18 @@
|
||||
"https://projects.fivethirtyeight.com/nfl-api/nfl_elo_latest.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/checking-our-work-data",
|
||||
"name": "checking-our-work-data",
|
||||
"displayName": "checking-our-work-<span class=\"lastword\">data</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2023-02-02T16:30:00.000Z",
|
||||
"title": "How Good Are FiveThirtyEight Forecasts?",
|
||||
"url": "https://projects.fivethirtyeight.com/checking-our-work/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/world-cup-2022",
|
||||
"name": "world-cup-2022",
|
||||
@@ -227,6 +239,18 @@
|
||||
"https://projects.fivethirtyeight.com/soccer-api/international/2022/wc_forecasts.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/covid-19-polls",
|
||||
"name": "covid-19-polls",
|
||||
"displayName": "covid-19-<span class=\"lastword\">polls</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2022-11-29T20:20:08.000Z",
|
||||
"title": "How Americans View Biden’s Response To The Coronavirus Crisis",
|
||||
"url": "https://projects.fivethirtyeight.com/coronavirus-polls/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/election-deniers",
|
||||
"name": "election-deniers",
|
||||
@@ -347,6 +371,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/nfl-elo-game",
|
||||
"name": "nfl-elo-game",
|
||||
"displayName": "nfl-elo-<span class=\"lastword\">game</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2022-02-14T03:03:26.000Z",
|
||||
"title": "Can You Beat FiveThirtyEight’s NFL Forecasts?",
|
||||
"url": "https://projects.fivethirtyeight.com/2021-nfl-forecasting-game/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/redlining",
|
||||
"name": "redlining",
|
||||
@@ -371,6 +407,42 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/negro-leagues-player-ratings",
|
||||
"name": "negro-leagues-player-ratings",
|
||||
"displayName": "negro-leagues-player-<span class=\"lastword\">ratings</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2021-02-25T11:00:00.000Z",
|
||||
"title": "The Negro League Stars That MLB Kept Out — And Is Finally Recognizing",
|
||||
"url": "https://projects.fivethirtyeight.com/negro-leagues-mlb/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/police-settlements",
|
||||
"name": "police-settlements",
|
||||
"displayName": "police-<span class=\"lastword\">settlements</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2021-02-22T11:00:49.000Z",
|
||||
"title": "Cities Spend Millions On Police Misconduct Every Year. Here’s Why It’s So Difficult to Hold Departments Accountable.",
|
||||
"url": "https://fivethirtyeight.com/features/police-misconduct-costs-cities-millions-every-year-but-thats-where-the-accountability-ends/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/superbowl-ads",
|
||||
"name": "superbowl-ads",
|
||||
"displayName": "superbowl-<span class=\"lastword\">ads</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2021-02-04T16:11:00.000Z",
|
||||
"title": "According To Super Bowl Ads, Americans Love America, Animals And Sex",
|
||||
"url": "https://projects.fivethirtyeight.com/super-bowl-ads/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/trump-approval-ratings",
|
||||
"name": "trump-approval-ratings",
|
||||
@@ -403,6 +475,18 @@
|
||||
"https://projects.fivethirtyeight.com/congress-tracker-data/csv/vote_predictions.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/election-results",
|
||||
"name": "election-results",
|
||||
"displayName": "election-<span class=\"lastword\">results</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2020-11-03T05:33:43.000Z",
|
||||
"title": "2020 Election Forecast",
|
||||
"url": "https://projects.fivethirtyeight.com/2020-election-forecast/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/election-forecasts-2020",
|
||||
"name": "election-forecasts-2020",
|
||||
@@ -473,6 +557,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/WNBA-stats",
|
||||
"name": "WNBA-stats",
|
||||
"displayName": "WNBA-<span class=\"lastword\">stats</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2020-05-27T19:06:43.000Z",
|
||||
"title": "It’s Time To Give Basketball’s Other GOAT Her Due",
|
||||
"url": "https://fivethirtyeight.com/features/its-time-to-give-basketballs-other-goat-her-due/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/covid-geography",
|
||||
"name": "covid-geography",
|
||||
@@ -512,6 +608,18 @@
|
||||
"https://projects.fivethirtyeight.com/endorsements-2020-data/endorsements-2020.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/nba-player-advanced-metrics",
|
||||
"name": "nba-player-advanced-metrics",
|
||||
"displayName": "nba-player-advanced-<span class=\"lastword\">metrics</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2020-03-09T15:27:37.000Z",
|
||||
"title": "Luka Dončić And The Mavs Are Pushing The Limits Of Offensive Efficiency",
|
||||
"url": "https://fivethirtyeight.com/features/luka-doncic-and-the-mavs-are-pushing-the-limits-of-offensive-efficiency/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/impeachment-polls",
|
||||
"name": "impeachment-polls",
|
||||
@@ -603,6 +711,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/candidate-emails",
|
||||
"name": "candidate-emails",
|
||||
"displayName": "candidate-<span class=\"lastword\">emails</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2019-07-11T15:33:15.000Z",
|
||||
"title": "What Our Inbox Tells Us About How Democrats Are Tackling Trump",
|
||||
"url": "https://fivethirtyeight.com/features/which-democrats-are-campaigning-on-trump/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-draymond",
|
||||
"name": "nba-draymond",
|
||||
@@ -643,6 +763,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/twitter-overlap",
|
||||
"name": "twitter-overlap",
|
||||
"displayName": "twitter-<span class=\"lastword\">overlap</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2019-06-12T15:24:07.000Z",
|
||||
"title": "Which 2020 Candidates Have The Most In Common … On Twitter?",
|
||||
"url": "https://fivethirtyeight.com/features/which-2020-candidates-have-the-most-in-common-on-twitter/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/trump-lawsuits",
|
||||
"name": "trump-lawsuits",
|
||||
@@ -825,6 +957,18 @@
|
||||
"https://projects.fivethirtyeight.com/congress-model-2018/governor_state_forecast.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/actblue-analysis",
|
||||
"name": "actblue-analysis",
|
||||
"displayName": "actblue-<span class=\"lastword\">analysis</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2018-10-25T17:31:42.000Z",
|
||||
"title": "How ActBlue Is Trying To Turn Small Donations Into A Blue Wave",
|
||||
"url": "https://fivethirtyeight.com/features/how-actblue-is-trying-to-turn-small-donations-into-a-blue-wave"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/primary-candidates-2018",
|
||||
"name": "primary-candidates-2018",
|
||||
@@ -1035,6 +1179,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/redistricting-atlas-data",
|
||||
"name": "redistricting-atlas-data",
|
||||
"displayName": "redistricting-atlas-<span class=\"lastword\">data</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2018-01-25T11:00:00.000Z",
|
||||
"title": "The Atlas Of Redistricting",
|
||||
"url": "https://projects.fivethirtyeight.com/redistricting-maps/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/next-bechdel",
|
||||
"name": "next-bechdel",
|
||||
@@ -1464,6 +1620,37 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/uber-tlc-foil-response",
|
||||
"name": "uber-tlc-foil-response",
|
||||
"displayName": "uber-tlc-foil-<span class=\"lastword\">response</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2015-12-09T16:19:40.000Z",
|
||||
"title": "Is Uber Making NYC Rush-Hour Traffic Worse?",
|
||||
"rowspan": 4,
|
||||
"url": "https://fivethirtyeight.com/features/is-uber-making-nyc-rush-hour-traffic-worse/"
|
||||
},
|
||||
{
|
||||
"date": "2015-10-13T20:44:12.000Z",
|
||||
"title": "Uber Is Taking Millions Of Manhattan Rides Away From Taxis",
|
||||
"rowspan": 0,
|
||||
"url": "https://fivethirtyeight.com/features/uber-is-taking-millions-of-manhattan-rides-away-from-taxis/"
|
||||
},
|
||||
{
|
||||
"date": "2015-08-28T10:30:36.000Z",
|
||||
"title": "Public Transit Should Be Uber’s New Best Friend",
|
||||
"rowspan": 0,
|
||||
"url": "https://fivethirtyeight.com/features/public-transit-should-be-ubers-new-best-friend/"
|
||||
},
|
||||
{
|
||||
"date": "2015-08-10T18:06:17.000Z",
|
||||
"title": "Uber Is Serving New York’s Outer Boroughs More Than Taxis Are",
|
||||
"rowspan": 0,
|
||||
"url": "https://fivethirtyeight.com/features/uber-is-serving-new-yorks-outer-boroughs-more-than-taxis-are/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/tarantino",
|
||||
"name": "tarantino",
|
||||
@@ -1982,6 +2169,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/comma-survey-data",
|
||||
"name": "comma-survey-data",
|
||||
"displayName": "comma-survey-<span class=\"lastword\">data</span>",
|
||||
"articles": [
|
||||
{
|
||||
"date": "2014-06-17T16:28:55.000Z",
|
||||
"title": "Elitist, Superfluous, Or Popular? We Polled Americans on the Oxford Comma",
|
||||
"url": "http://fivethirtyeight.com/features/elitist-superfluous-or-popular-we-polled-americans-on-the-oxford-comma/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fivethirtyeight/data/tree/master/world-cup-predictions",
|
||||
"name": "world-cup-predictions",
|
||||
@@ -1,9 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
serverRuntimeConfig: {
|
||||
github_pat: process.env.GITHUB_PAT ? process.env.GITHUB_PAT : null,
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
@@ -9,27 +9,16 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@portaljs/components": "^0.1.0",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@types/node": "20.1.1",
|
||||
"@types/react": "18.2.6",
|
||||
"@types/react-dom": "18.2.4",
|
||||
"autoprefixer": "10.4.14",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-config-next": "13.4.1",
|
||||
"flexsearch": "^0.7.31",
|
||||
"next": "13.4.1",
|
||||
"next-mdx-remote": "^4.4.1",
|
||||
"next-seo": "^6.0.0",
|
||||
"octokit": "^2.0.14",
|
||||
"postcss": "8.4.23",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-markdown": "^8.0.7",
|
||||
"remark-code-frontmatter": "^1.0.0",
|
||||
"remark-extract-frontmatter": "^3.2.0",
|
||||
"remark-frontmatter": "^4.0.1",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"tailwindcss": "3.3.2",
|
||||
"timeago.js": "^4.0.2",
|
||||
"typescript": "5.0.4"
|
||||
@@ -1,6 +1,4 @@
|
||||
import '@/styles/globals.css'
|
||||
import '@portaljs/components/styles.css'
|
||||
|
||||
import type { AppProps } from 'next/app'
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
13
examples/fiverthirtyeight-example/pages/_document.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
13
examples/fiverthirtyeight-example/pages/api/hello.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
type Data = {
|
||||
name: string
|
||||
}
|
||||
|
||||
export default function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<Data>
|
||||
) {
|
||||
res.status(200).json({ name: 'John Doe' })
|
||||
}
|
||||
@@ -1,53 +1,41 @@
|
||||
import Image from 'next/image';
|
||||
import { Inter } from 'next/font/google';
|
||||
import { format } from 'timeago.js';
|
||||
import { format } from 'timeago.js'
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import { NextSeo } from 'next-seo';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export interface Article {
|
||||
interface Article {
|
||||
date: string;
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface Dataset {
|
||||
interface Dataset {
|
||||
url: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
articles: Article[];
|
||||
files?: string[];
|
||||
}
|
||||
|
||||
// Request a weekday along with a long date
|
||||
const options = {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
} as const;
|
||||
|
||||
export function MobileItem({ dataset }: { dataset: Dataset }) {
|
||||
export function MobileItem({dataset} : { dataset: Dataset}) {
|
||||
return (
|
||||
<div className="flex gap-x-2 pb-2 py-4 items-center justify-between border-b border-zinc-600">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-mono font-light">{dataset.name}</span>
|
||||
<span className="font-light">{dataset.name}</span>
|
||||
{dataset.articles.map((article) => (
|
||||
<div key={article.title} className="py-1 flex flex-col">
|
||||
<div className='py-1 flex flex-col'>
|
||||
<span className="font-bold hover:underline">{article.title}</span>
|
||||
<span className="font-light text-base">
|
||||
{format(article.date).includes('years')
|
||||
? new Date(article.date).toLocaleString('en-US', options)
|
||||
: format(article.date)}
|
||||
</span>{' '}
|
||||
<span className="font-light text-base">{format(article.date)}</span>{' '}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col justify-start">
|
||||
<a
|
||||
className="ml-2 border border-zinc-900 font-light px-4 py-1 text-sm transition hover:bg-zinc-900 hover:text-white"
|
||||
className="border border-zinc-900 font-light px-4 py-1 text-sm transition hover:bg-zinc-900 hover:text-white"
|
||||
href={dataset.url}
|
||||
target="_blank"
|
||||
>
|
||||
info
|
||||
</a>
|
||||
@@ -71,37 +59,24 @@ export function MobileItem({ dataset }: { dataset: Dataset }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function DesktopItem({ dataset }: { dataset: Dataset }) {
|
||||
export function DesktopItem({dataset} : { dataset: Dataset}) {
|
||||
return (
|
||||
<>
|
||||
{dataset.articles.map((article, index) => (
|
||||
<tr
|
||||
key={article.url}
|
||||
className={`${
|
||||
index === dataset.articles.length - 1 ? 'border-b' : ''
|
||||
} border-zinc-400`}
|
||||
>
|
||||
<td className="py-8 font-light font-mono text-[13px] text-zinc-700">
|
||||
{index === 0 ? dataset.name : ''}
|
||||
</td>
|
||||
<tr className={`${index === (dataset.articles.length - 1) ? 'border-b' : ''} border-zinc-400`}>
|
||||
<td className="py-8 font-light">{index === 0 ? dataset.name : ''}</td>
|
||||
<td>
|
||||
<a
|
||||
className="py-8 font-bold hover:underline pr-2"
|
||||
href={article.url}
|
||||
>
|
||||
<a className="py-8 font-bold hover:underline" href={article.url}>
|
||||
{article.title}
|
||||
</a>
|
||||
</td>
|
||||
<td className="py-8 font-light text-[14px] min-w-[138px] font-mono text-[#999]">
|
||||
{format(article.date).includes('years')
|
||||
? new Date(article.date).toLocaleString('en-US', options)
|
||||
: format(article.date)}
|
||||
</td>
|
||||
<td className="py-8 font-light text-base min-w-[120px]">{format(article.date)}</td>
|
||||
<td className="py-8">
|
||||
{index === 0 && (
|
||||
<a
|
||||
className="ml-2 border border-zinc-900 font-light px-[25px] py-2.5 text-sm transition hover:bg-zinc-900 hover:text-white"
|
||||
className="border border-zinc-900 font-light px-[25px] py-2.5 text-sm transition hover:bg-zinc-900 hover:text-white"
|
||||
href={dataset.url}
|
||||
target="_blank"
|
||||
>
|
||||
info
|
||||
</a>
|
||||
@@ -131,18 +106,35 @@ export function DesktopItem({ dataset }: { dataset: Dataset }) {
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const jsonDirectory = path.join(process.cwd(), '/datasets.json');
|
||||
const jsonDirectory = path.join(
|
||||
process.cwd(),
|
||||
'/datasets.json'
|
||||
);
|
||||
const datasetString = await fs.readFile(jsonDirectory, 'utf8');
|
||||
const datasets = JSON.parse(datasetString);
|
||||
const datasets = JSON.parse(datasetString)
|
||||
return {
|
||||
props: { datasets },
|
||||
};
|
||||
}
|
||||
|
||||
export default function Home({ datasets }: { datasets: Dataset[] }) {
|
||||
export default function Home( { datasets }: { datasets: Dataset[] }) {
|
||||
return (
|
||||
<>
|
||||
<NextSeo title="FiveThirtyEight tribute by PortalJS" />
|
||||
<header className="max-w-5xl mx-auto mt-8 w-full">
|
||||
<div className="border-b-2 pb-2.5 mx-2 border-zinc-800">
|
||||
<h1>
|
||||
<span className="sr-only">FiveThirtyEight</span>
|
||||
<a className='flex gap-x-2 items-center' href="http://fivethirtyeight.com">
|
||||
<img
|
||||
width="197"
|
||||
height="25"
|
||||
alt="FiveThirtyEight"
|
||||
src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MjEgNTMuNzYiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojMDEwMTAxO308L3N0eWxlPjwvZGVmcz48dGl0bGU+QXJ0Ym9hcmQgOTU8L3RpdGxlPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTAgMGgyNXY4SDl2MTBoMTV2OEg5djE3SDBWMHpNMzEgMzZoNVYxOGgtNXYtOGgxM3YyNmg0djdIMzF6bTUtMzZoOHY4aC04ek0xNzkgMzZoNVYxOGgtNXYtOGgxM3YyNmg0djdoLTE3em01LTM2aDh2OGgtOHpNMzE2IDM2aDVWMThoLTV2LThoMTN2MjZoNHY3aC0xN3ptNS0zNmg4djhoLTh6TTU0IDI3VjEwaDh2MTVsNCA5Ljk4aDFMNzEgMjVWMTBoOHYxN2wtNyAxNkg2MWwtNy0xNnpNMTExIDQzSDk3LjQyQzg5LjIzIDQzIDg1IDM5LjE5IDg1IDMxLjE3VjIyYzAtNy41NyA0LjMtMTMgMTMtMTMgOS4zMyAwIDEzIDUuMDcgMTMgMTR2N0g5NHYxLjc0YzAgMi42MiAxIDQuMjYgMy40MiA0LjI2SDExMXpNOTQgMjNoOHYtMS41NWMwLTIuNjItMS4wNi01LjQ1LTQuMTMtNS40NS0yLjc5IDAtMy44NyAyLjItMy44NyA1LjQ1ek0xMjUgOGgtMTBWMGgyOXY4aC0xMHYzNWgtOVY4ek0yMDIgNDNWMTBoOHY0YzEuMTQtMi40NSAzLjc1LTQgNy4yMi00SDIyMHY4aC02Yy0yLjg0IDAtNCAuOTQtNCAzLjlWNDN6TTI0NSA0M2gtNC44NEMyMzMuMDUgNDMgMjMwIDM5LjMxIDIzMCAzMS44NVYxOGgtNnYtOGg2VjNoOHY3aDd2OGgtN2wtLjA3IDEzLjkzYzAgMi4yMi45MyA0LjA3IDMuNjYgNC4wN0gyNDV6TTQyMSA0M2gtNC44NEM0MDkuMDUgNDMgNDA2IDM5LjMxIDQwNiAzMS44NVYxOGgtNnYtOGg2VjNoOHY3aDd2OGgtN2wtLjA3IDEzLjkzYzAgMi4yMi45MyA0LjA3IDMuNjYgNC4wN0g0MjF6TTI1NC4yNiA1My43Nmw0LjYxLTkuNUwyNTEgMjdWMTBoOHYxNWw0IDEwaDFsNC0xMFYxMGg4djE3bC0xMi4zIDI2Ljc2aC05LjQ0ek0yODQgMGgyNXY4aC0xNnY5aDE1djhoLTE1djEwaDE2djhoLTI1VjB6TTMzNyA0OHYtMmgxNi4xYzIgMCAyLjktLjE4IDIuOS0xLjI3di0uMzRjMC0xLjA4LS45MS0xLjM5LTIuOS0xLjM5SDM0MHYtNWw1LTVjLTUuMjktMS40OC04LTUuNDMtOC0xMXYtMWMwLTcuNTYgNC40NC0xMiAxNC0xMmEyMS45MyAyMS45MyAwIDAgMSA1Ljk1IDFMMzYxIDRsNSAzLTQgNmMxLjM3IDEuOTMgMyA0LjkzIDMgOHYxYzAgNy0zLjMgMTAuNjYtMTIgMTFsLTMgNGg2YzUuOTIgMCA5IDIuNjIgOSA3LjY4di4xMWMwIDUuMDYtMi43MSA4LjIxLTguNjIgOC4yMWgtMTNjLTQuMjkgMC02LjM4LTEuODQtNi4zOC01em0xOS0yNXYtM2MwLTMuMy0xLjMzLTQtNS00cy01IC43LTUgNHYzYzAgMy4zIDEuMzkgNCA1IDRzNS0uNyA1LTR6TTM4MCA0M2gtOFYwaDh2MTRjMS4xNC0yLjY3IDMuNC00IDctNCA2LjI2IDAgOSAzLjA4IDkgMTAuNzZWNDNoLThWMjJjMC0zLjEzLTEuMDctNS00LTVzLTQgMS44Ny00IDV6TTE1NyA0M2gtOFYwaDh2MTRjMS4xNC0yLjY3IDMuOTEtNCA3LjQ5LTQgNi4yNiAwIDguNTEgMy4xMyA4LjUxIDEwLjgxVjQzaC04VjIxYzAtMy4xMy0xLjA3LTQuNDQtNC00LjQ0cy00IDIuMjYtNCA1LjM5eiIvPjwvc3ZnPg=="
|
||||
/> by PortalJS
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<main
|
||||
className={`flex min-h-screen flex-col items-center max-w-5xl mx-auto pt-20 px-2.5 ${inter.className}`}
|
||||
>
|
||||
@@ -150,36 +142,28 @@ export default function Home({ datasets }: { datasets: Dataset[] }) {
|
||||
<h1 className="text-[40px] font-bold text-zinc-800 text-center">
|
||||
Our Data
|
||||
</h1>
|
||||
<p className="max-w-[600px] text-[17px] text-center text-[#6d6f71]">
|
||||
<p className="max-w-2xl text-lg text-center text-zinc-700">
|
||||
We’re sharing the data and code behind some of our articles and
|
||||
graphics. We hope you’ll use it to check our work and to create
|
||||
stories and visualizations of your own.
|
||||
</p>
|
||||
</div>
|
||||
<article className="w-full px-2 md:hidden py-4">
|
||||
{datasets.map((dataset) => (
|
||||
<MobileItem key={dataset.name} dataset={dataset} />
|
||||
))}
|
||||
</article>
|
||||
<article className="w-full px-2 md:hidden py-4">{datasets.map(dataset => <MobileItem dataset={dataset} />)}</article>
|
||||
<table className="w-full mt-10 mb-4 hidden md:table">
|
||||
<thead className="border-b-4 pb-2 border-zinc-900">
|
||||
<tr>
|
||||
<th className="uppercase text-left font-normal text-xs pb-3">
|
||||
<th className="uppercase text-left font-light text-xs pb-3">
|
||||
data set
|
||||
</th>
|
||||
<th className="uppercase text-left font-normal text-xs pb-3">
|
||||
<th className="uppercase text-left font-light text-xs pb-3">
|
||||
related content
|
||||
</th>
|
||||
<th className="uppercase text-left font-normal text-xs pb-3">
|
||||
<th className="uppercase text-left font-light text-xs pb-3">
|
||||
last updated
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{datasets.map((dataset) => (
|
||||
<DesktopItem key={dataset.name} dataset={dataset} />
|
||||
))}
|
||||
</tbody>
|
||||
<tbody>{datasets.map(dataset => <DesktopItem dataset={dataset} />)}</tbody>
|
||||
</table>
|
||||
<p className="text-[13px] py-8">
|
||||
Unless otherwise noted, our data sets are available under the{' '}
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 629 B |
3
examples/fiverthirtyeight-example/styles/globals.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -14,5 +14,5 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('@tailwindcss/typography')],
|
||||
};
|
||||
plugins: [],
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import Link from "next/link";
|
||||
|
||||
function HomeIcon({ className = "" }) {
|
||||
return <div className={`inline-block w-4 ${className}`}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M 12 2 A 1 1 0 0 0 11.289062 2.296875 L 1.203125 11.097656 A 0.5 0.5 0 0 0 1 11.5 A 0.5 0.5 0 0 0 1.5 12 L 4 12 L 4 20 C 4 20.552 4.448 21 5 21 L 9 21 C 9.552 21 10 20.552 10 20 L 10 14 L 14 14 L 14 20 C 14 20.552 14.448 21 15 21 L 19 21 C 19.552 21 20 20.552 20 20 L 20 12 L 22.5 12 A 0.5 0.5 0 0 0 23 11.5 A 0.5 0.5 0 0 0 22.796875 11.097656 L 12.716797 2.3027344 A 1 1 0 0 0 12.710938 2.296875 A 1 1 0 0 0 12 2 z"/></svg></div>
|
||||
}
|
||||
|
||||
export default function Breadcrumbs({ links }: { links: { title: string, href?: string, target?: string }[] }) {
|
||||
const current = links.at(-1);
|
||||
|
||||
return <div className="flex items-center uppercase font-black text-xs">
|
||||
<Link className="flex items-center" href='/'><HomeIcon /></Link>
|
||||
|
||||
{/* {links.length > 1 && links.slice(0, -1).map((link) => {
|
||||
return <>
|
||||
<span className="mx-4">/</span>
|
||||
<Link href={link.href}>{link.title}</Link>
|
||||
</>
|
||||
})} */}
|
||||
|
||||
<span className="mx-4">/</span>
|
||||
<span>{current?.title}</span>
|
||||
</div >
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Octokit } from 'octokit';
|
||||
|
||||
export interface GithubProject {
|
||||
owner: string;
|
||||
repo: string;
|
||||
branch: string;
|
||||
files: string[];
|
||||
readme: string;
|
||||
description?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export async function getProjectReadme(
|
||||
owner: string,
|
||||
repo: string,
|
||||
branch: string,
|
||||
readme: string,
|
||||
github_pat?: string
|
||||
) {
|
||||
const octokit = new Octokit({ auth: github_pat });
|
||||
try {
|
||||
const response = await octokit.rest.repos.getContent({
|
||||
owner,
|
||||
repo,
|
||||
path: readme,
|
||||
ref: branch,
|
||||
});
|
||||
const data = response.data as { content?: string };
|
||||
const fileContent = data.content ? data.content : '';
|
||||
if (fileContent === '') {
|
||||
return null;
|
||||
}
|
||||
const decodedContent = Buffer.from(fileContent, 'base64').toString();
|
||||
return decodedContent;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://projects.fivethirtyeight.com/shared/favicon.ico"
|
||||
/>
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://portaljs-fivethirtyeight.vercel.app/share_image.png"
|
||||
/>
|
||||
<meta
|
||||
property="twitter:image"
|
||||
content="https://portaljs-fivethirtyeight.vercel.app/share_image.png"
|
||||
/>
|
||||
</Head>
|
||||
<body>
|
||||
<div className="px-2 max-w-5xl mx-auto pb-2">
|
||||
<div className="mt-2 px-2 bg-[#3c3c3c] text-white">
|
||||
<div className="p-2 text-center">
|
||||
This is a replica to the awesome{' '}
|
||||
<a
|
||||
className="hover:underline font-bold"
|
||||
href="https://data.fivethirtyeight.com"
|
||||
>
|
||||
data.fivethirtyeight.com
|
||||
</a>{' '}
|
||||
website.{' '}
|
||||
<a
|
||||
className="hover:underline font-bold"
|
||||
href="https://github.com/datopian/portaljs/tree/main/examples/fivethirtyeight"
|
||||
>
|
||||
Read more here
|
||||
</a>{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<header className="max-w-5xl mx-auto mt-8 w-full">
|
||||
<div className="border-b-2 pb-2.5 mx-2 border-zinc-800 flex justify-between">
|
||||
<h1 className="flex gap-x-1 items-end">
|
||||
<span className="sr-only">FiveThirtyEight</span>
|
||||
<img
|
||||
width="197"
|
||||
height="25"
|
||||
alt="FiveThirtyEight"
|
||||
src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MjEgNTMuNzYiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojMDEwMTAxO308L3N0eWxlPjwvZGVmcz48dGl0bGU+QXJ0Ym9hcmQgOTU8L3RpdGxlPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTAgMGgyNXY4SDl2MTBoMTV2OEg5djE3SDBWMHpNMzEgMzZoNVYxOGgtNXYtOGgxM3YyNmg0djdIMzF6bTUtMzZoOHY4aC04ek0xNzkgMzZoNVYxOGgtNXYtOGgxM3YyNmg0djdoLTE3em01LTM2aDh2OGgtOHpNMzE2IDM2aDVWMThoLTV2LThoMTN2MjZoNHY3aC0xN3ptNS0zNmg4djhoLTh6TTU0IDI3VjEwaDh2MTVsNCA5Ljk4aDFMNzEgMjVWMTBoOHYxN2wtNyAxNkg2MWwtNy0xNnpNMTExIDQzSDk3LjQyQzg5LjIzIDQzIDg1IDM5LjE5IDg1IDMxLjE3VjIyYzAtNy41NyA0LjMtMTMgMTMtMTMgOS4zMyAwIDEzIDUuMDcgMTMgMTR2N0g5NHYxLjc0YzAgMi42MiAxIDQuMjYgMy40MiA0LjI2SDExMXpNOTQgMjNoOHYtMS41NWMwLTIuNjItMS4wNi01LjQ1LTQuMTMtNS40NS0yLjc5IDAtMy44NyAyLjItMy44NyA1LjQ1ek0xMjUgOGgtMTBWMGgyOXY4aC0xMHYzNWgtOVY4ek0yMDIgNDNWMTBoOHY0YzEuMTQtMi40NSAzLjc1LTQgNy4yMi00SDIyMHY4aC02Yy0yLjg0IDAtNCAuOTQtNCAzLjlWNDN6TTI0NSA0M2gtNC44NEMyMzMuMDUgNDMgMjMwIDM5LjMxIDIzMCAzMS44NVYxOGgtNnYtOGg2VjNoOHY3aDd2OGgtN2wtLjA3IDEzLjkzYzAgMi4yMi45MyA0LjA3IDMuNjYgNC4wN0gyNDV6TTQyMSA0M2gtNC44NEM0MDkuMDUgNDMgNDA2IDM5LjMxIDQwNiAzMS44NVYxOGgtNnYtOGg2VjNoOHY3aDd2OGgtN2wtLjA3IDEzLjkzYzAgMi4yMi45MyA0LjA3IDMuNjYgNC4wN0g0MjF6TTI1NC4yNiA1My43Nmw0LjYxLTkuNUwyNTEgMjdWMTBoOHYxNWw0IDEwaDFsNC0xMFYxMGg4djE3bC0xMi4zIDI2Ljc2aC05LjQ0ek0yODQgMGgyNXY4aC0xNnY5aDE1djhoLTE1djEwaDE2djhoLTI1VjB6TTMzNyA0OHYtMmgxNi4xYzIgMCAyLjktLjE4IDIuOS0xLjI3di0uMzRjMC0xLjA4LS45MS0xLjM5LTIuOS0xLjM5SDM0MHYtNWw1LTVjLTUuMjktMS40OC04LTUuNDMtOC0xMXYtMWMwLTcuNTYgNC40NC0xMiAxNC0xMmEyMS45MyAyMS45MyAwIDAgMSA1Ljk1IDFMMzYxIDRsNSAzLTQgNmMxLjM3IDEuOTMgMyA0LjkzIDMgOHYxYzAgNy0zLjMgMTAuNjYtMTIgMTFsLTMgNGg2YzUuOTIgMCA5IDIuNjIgOSA3LjY4di4xMWMwIDUuMDYtMi43MSA4LjIxLTguNjIgOC4yMWgtMTNjLTQuMjkgMC02LjM4LTEuODQtNi4zOC01em0xOS0yNXYtM2MwLTMuMy0xLjMzLTQtNS00cy01IC43LTUgNHYzYzAgMy4zIDEuMzkgNCA1IDRzNS0uNyA1LTR6TTM4MCA0M2gtOFYwaDh2MTRjMS4xNC0yLjY3IDMuNC00IDctNCA2LjI2IDAgOSAzLjA4IDkgMTAuNzZWNDNoLThWMjJjMC0zLjEzLTEuMDctNS00LTVzLTQgMS44Ny00IDV6TTE1NyA0M2gtOFYwaDh2MTRjMS4xNC0yLjY3IDMuOTEtNCA3LjQ5LTQgNi4yNiAwIDguNTEgMy4xMyA4LjUxIDEwLjgxVjQzaC04VjIxYzAtMy4xMy0xLjA3LTQuNDQtNC00LjQ0cy00IDIuMjYtNCA1LjM5eiIvPjwvc3ZnPg=="
|
||||
/>{' '}
|
||||
<span className="-mb-0.5 text-[#3c3c3c]">replica</span>
|
||||
</h1>
|
||||
<div className="md:flex items-center gap-x-3 text-[#3c3c3c] -mb-1 hidden">
|
||||
<a
|
||||
className="hover:opacity-75 transition"
|
||||
href="https://portaljs.org"
|
||||
>
|
||||
Built with 🌀PortalJS
|
||||
</a>
|
||||
<hr className="h-[80%] border border-[#3c3c3c] opacity-75 my-2"></hr>
|
||||
<a
|
||||
className="hover:opacity-75 transition"
|
||||
href="https://github.com/datopian/portaljs/tree/main/examples/fivethirtyeight"
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-2 py-1.5 text-[14px] text-[#3c3c3c] md:hidden">
|
||||
<ul className="flex gap-x-4">
|
||||
<li>
|
||||
<a
|
||||
className="hover:opacity-75 transition"
|
||||
href="https://portaljs.org"
|
||||
>
|
||||
PortalJS
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="hover:opacity-75 transition"
|
||||
href="https://github.com/datopian/portaljs/tree/main/examples/fivethirtyeight"
|
||||
>
|
||||
View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
import { NextSeo } from 'next-seo';
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import getConfig from 'next/config';
|
||||
import { getProjectReadme, GithubProject } from '@/lib/octokit';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import extract from 'remark-extract-frontmatter';
|
||||
import { Dataset } from '..';
|
||||
import { GetStaticProps } from 'next';
|
||||
import { Table } from '@portaljs/components';
|
||||
import Breadcrumbs from '@/components/Breadcrumbs';
|
||||
import { ReactMarkdown } from 'react-markdown/lib/react-markdown';
|
||||
import remarkFrontmatter from 'remark-frontmatter';
|
||||
|
||||
export default function DatasetPage({
|
||||
dataset,
|
||||
}: {
|
||||
dataset: Dataset & {
|
||||
readme: string | null;
|
||||
};
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<NextSeo title={`${dataset.name} page`} />
|
||||
<main className="max-w-5xl px-2 prose mx-auto my-8 prose-thead:border-b-4 prose-table:max-w-5xl prose-table:overflow-scroll prose-thead:overflow-scroll prose-tbody:overflow-scroll prose-thead:pb-2 prose-thead:border-zinc-900 prose-th:uppercase prose-th:text-left prose-th:font-light prose-th:text-xs">
|
||||
<Breadcrumbs links={[{ title: dataset.name, href: '' }]} />
|
||||
<h1 className="uppercase mb-0 mt-16">{dataset.name}</h1>
|
||||
<p className="mb-8">
|
||||
<span className="font-semibold">Repository:</span>{' '}
|
||||
<a target="_blank" href={dataset.url}>
|
||||
{dataset.url}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h2 className="mb-0 mt-10">FILES</h2>
|
||||
<div className="inline-block min-w-full py-2 align-middle">
|
||||
<table className="min-w-full divide-y divide-gray-300">
|
||||
<thead className="border-b-4 pb-2 border-zinc-900">
|
||||
<tr>
|
||||
<th
|
||||
className="uppercase text-left font-light text-xs pb-3"
|
||||
scope="col"
|
||||
>
|
||||
Name
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{dataset.files?.map((file) => (
|
||||
<tr key={file}>
|
||||
<td className="whitespace-nowrap text-left py-4 text-sm text-gray-500">
|
||||
<a href={file}>{file.split('/').slice(-1)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{dataset.files && dataset.files.length > 0 && (
|
||||
<>
|
||||
<h2 className="mb-0 mt-10">DATA PREVIEWS</h2>
|
||||
{dataset.files?.map((file) => (
|
||||
<div key={file} className="preview-table my-8">
|
||||
<h3>{file.split('/').slice(-1)}</h3>
|
||||
<Table url={file} />
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{dataset.readme && (
|
||||
<>
|
||||
<h2 className="uppercase font-black">Readme</h2>
|
||||
{dataset.readme && (
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[
|
||||
remarkFrontmatter,
|
||||
remarkGfm,
|
||||
[extract, { remove: true }],
|
||||
]}
|
||||
>
|
||||
{dataset.readme}
|
||||
</ReactMarkdown>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const datasetsFile = path.join(process.cwd(), 'datasets.json');
|
||||
const datasets = await fs.readFile(datasetsFile, 'utf8');
|
||||
|
||||
return {
|
||||
paths: JSON.parse(datasets).map((dataset: Dataset) => {
|
||||
return {
|
||||
params: { datasetName: dataset.name },
|
||||
};
|
||||
}),
|
||||
fallback: false, // can also be true or 'blocking'
|
||||
};
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async ({ params }) => {
|
||||
const datasetsFile = path.join(process.cwd(), 'datasets.json');
|
||||
const datasetsString = await fs.readFile(datasetsFile, 'utf8');
|
||||
const datasets: Dataset[] = JSON.parse(datasetsString);
|
||||
const dataset: Dataset | undefined = datasets.find(
|
||||
(_dataset) => _dataset.name === params?.datasetName
|
||||
);
|
||||
const github_pat = getConfig().serverRuntimeConfig.github_pat;
|
||||
const readmes = await Promise.all(['/README.md', '/readme.md', '/Readme.md'].map(async (readme) => await getProjectReadme(
|
||||
'fivethirtyeight',
|
||||
'data',
|
||||
'master',
|
||||
dataset?.name + readme,
|
||||
github_pat
|
||||
)));
|
||||
const readme = readmes.find(item => item !== null)
|
||||
if (!readme) console.log('Readme not found for ' + dataset?.name)
|
||||
return {
|
||||
props: {
|
||||
dataset: {
|
||||
...dataset,
|
||||
readme,
|
||||
files: dataset && dataset.files ? dataset.files : null,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
Before Width: | Height: | Size: 81 KiB |
@@ -1,8 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.preview-table > div {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"extends": ["next", "next/core-web-vitals"],
|
||||
"ignorePatterns": ["!**/*", ".next/**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {
|
||||
"@next/next/no-html-link-for-pages": [
|
||||
"error",
|
||||
"examples/simple-example/pages"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
],
|
||||
"rules": {
|
||||
"@next/next/no-html-link-for-pages": "off"
|
||||
},
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
node_modules
|
||||
**/.next/**
|
||||
**/_next/**
|
||||
**/dist/**
|
||||
**/__tmp__/**
|
||||
lerna.json
|
||||
.github
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,101 +0,0 @@
|
||||
# A data catalog with data on GitHub
|
||||
|
||||
This example showcases a simple data catalog that get its data from a list of GitHub repos that serve as datasets.
|
||||
|
||||
A `datasets.json` file is used to specify which datasets are going to be part of the data catalog.
|
||||
|
||||
The application contains an index page, which lists all the datasets specified in the `datasets.json` file, and users can see more information about each dataset, such as the list of data files in it and the README, by clicking the "info" button on the list.
|
||||
|
||||
You can read more about it on the [Data catalog with data on GitHub](https://portaljs.org/docs/examples/github-backed-catalog) blog post.
|
||||
|
||||
## Demo
|
||||
|
||||
https://example.portaljs.org/
|
||||
|
||||
## Deploy your own
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdatopian%2Fportaljs%2Ftree%2Fmain%2Fexamples%2Fgithub-backed-catalog)
|
||||
|
||||
By clicking on this button, you will be redirected to a page which will allow you to clone the content into your own GitHub/GitLab/Bitbucket account and automatically deploy everything.
|
||||
|
||||
## How to use
|
||||
|
||||
### Install
|
||||
|
||||
Execute `create-next-app` to bootstrap the example:
|
||||
|
||||
```
|
||||
npx create-next-app <app-name> --example https://github.com/datopian/portaljs/tree/main/examples/github-backed-catalog
|
||||
cd <app-name>
|
||||
```
|
||||
|
||||
### Set environment variables
|
||||
|
||||
This project uses the GitHub API, which for anonymous users will cap at 50 requests per hour, so you might want to get a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) and add it to a `.env` file inside the folder like so
|
||||
|
||||
```
|
||||
GITHUB_PAT=<github token>
|
||||
```
|
||||
|
||||
### Change datasets
|
||||
|
||||
You can change the datasets that will be displayed in the data catalog by editing the file `datasets.json`. Some examples can be found inside [this repo](https://github.com/datasets).
|
||||
|
||||
### Run in development mode
|
||||
|
||||
Run the app using:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open http://localhost:3000 from your browser. You should see something similar to this:
|
||||
|
||||

|
||||
|
||||
If click on the `info` button for a dataset you will see a page similar to this:
|
||||
|
||||

|
||||
|
||||
## Notes
|
||||
|
||||
### Structure of `datasets.json`
|
||||
|
||||
The `datasets.json` file is simply a list of datasets, below you can see a minimal example of a dataset:
|
||||
|
||||
```json
|
||||
{
|
||||
"owner": "fivethirtyeight",
|
||||
"repo": "data",
|
||||
"branch": "master",
|
||||
"files": ["nba-raptor/historical_RAPTOR_by_player.csv", "nba-raptor/historical_RAPTOR_by_team.csv"],
|
||||
"readme": "nba-raptor/README.md"
|
||||
}
|
||||
```
|
||||
|
||||
It has:
|
||||
|
||||
- A `owner` which is going to be the github repo owner
|
||||
- A `repo` which is going to be the github repo name
|
||||
- A `branch` which is going to be the branch to which we need to get the files and the readme
|
||||
- A list of `files` which is going to be a list of paths with files that you want to show to the world
|
||||
- A `readme` which is going to be the path to your data description, it can also be a subpath eg: `example/README.md`
|
||||
|
||||
You can also add:
|
||||
|
||||
- A `description` which is useful if you have more than one dataset for each repo, if not provided we are just going to use the repo description
|
||||
- A `Name` which is useful if you want to give your dataset a nice name, if not provided we are going to use the junction of the `owner` the `repo` + the path of the README, in the exaple above it will be `fivethirtyeight/data/nba-raptor`
|
||||
|
||||
### Extra commands
|
||||
|
||||
You can also build the project for production with:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
And run the production build with:
|
||||
|
||||
```
|
||||
npm run start
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import HomeIcon from "../icons/HomeIcon";
|
||||
|
||||
export default function Breadcrumbs({
|
||||
links,
|
||||
}: {
|
||||
links: { title: string; href?: string; target?: string }[];
|
||||
}) {
|
||||
const current = links.at(-1);
|
||||
|
||||
return (
|
||||
<div className="flex items-center uppercase font-black text-xs">
|
||||
<Link className="flex items-center" href="/">
|
||||
<HomeIcon />
|
||||
</Link>
|
||||
|
||||
{/* {links.length > 1 && links.slice(0, -1).map((link) => {
|
||||
return <>
|
||||
<span className="mx-4">/</span>
|
||||
<Link href={link.href}>{link.title}</Link>
|
||||
</>
|
||||
})} */}
|
||||
|
||||
<span className="mx-4">/</span>
|
||||
<span>{current.title}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export default function ExternalLinkIcon({ className = "" }) {
|
||||
return (
|
||||
<div className={`inline-block w-4 ${className}`}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 64 64"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M 40 10 C 38.896 10 38 10.896 38 12 C 38 13.104 38.896 14 40 14 L 47.171875 14 L 30.585938 30.585938 C 29.804938 31.366938 29.804938 32.633063 30.585938 33.414062 C 30.976938 33.805063 31.488 34 32 34 C 32.512 34 33.023063 33.805062 33.414062 33.414062 L 50 16.828125 L 50 24 C 50 25.104 50.896 26 52 26 C 53.104 26 54 25.104 54 24 L 54 12 C 54 10.896 53.104 10 52 10 L 40 10 z M 18 12 C 14.691 12 12 14.691 12 18 L 12 46 C 12 49.309 14.691 52 18 52 L 46 52 C 49.309 52 52 49.309 52 46 L 52 34 C 52 32.896 51.104 32 50 32 C 48.896 32 48 32.896 48 34 L 48 46 C 48 47.103 47.103 48 46 48 L 18 48 C 16.897 48 16 47.103 16 46 L 16 18 C 16 16.897 16.897 16 18 16 L 30 16 C 31.104 16 32 15.104 32 14 C 32 12.896 31.104 12 30 12 L 18 12 z" />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export default function HomeIcon({ className = "" }) {
|
||||
return (
|
||||
<div className={`inline-block w-4 ${className}`}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
{" "}
|
||||
<path d="M 12 2 A 1 1 0 0 0 11.289062 2.296875 L 1.203125 11.097656 A 0.5 0.5 0 0 0 1 11.5 A 0.5 0.5 0 0 0 1.5 12 L 4 12 L 4 20 C 4 20.552 4.448 21 5 21 L 9 21 C 9.552 21 10 20.552 10 20 L 10 14 L 14 14 L 14 20 C 14 20.552 14.448 21 15 21 L 19 21 C 19.552 21 20 20.552 20 20 L 20 12 L 22.5 12 A 0.5 0.5 0 0 0 23 11.5 A 0.5 0.5 0 0 0 22.796875 11.097656 L 12.716797 2.3027344 A 1 1 0 0 0 12.710938 2.296875 A 1 1 0 0 0 12 2 z" />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
6
examples/github-backed-catalog/index.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
declare module "*.svg" {
|
||||
const content: any;
|
||||
export const ReactComponent: any;
|
||||
export default content;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
const nextConfig = {
|
||||
async rewrites() {
|
||||
return {
|
||||
beforeFiles: [
|
||||
{
|
||||
source: "/@:org/:project*",
|
||||
destination: "/@org/:org/:project*",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
serverRuntimeConfig: {
|
||||
github_pat: process.env.GITHUB_PAT ? process.env.GITHUB_PAT : null,
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
@@ -1,18 +0,0 @@
|
||||
import { AppProps } from "next/app";
|
||||
import Head from "next/head";
|
||||
import "./styles.css";
|
||||
|
||||
function CustomApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>GitHub Datasets</title>
|
||||
</Head>
|
||||
<main className="app">
|
||||
<Component {...pageProps} />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomApp;
|
||||
@@ -1,139 +0,0 @@
|
||||
import { promises as fs } from "fs";
|
||||
import path from "path";
|
||||
import { getProject } from "../lib/octokit";
|
||||
import getConfig from "next/config";
|
||||
import ExternalLinkIcon from "../components/icons/ExternalLinkIcon";
|
||||
import TimeAgo from "react-timeago";
|
||||
import Link from "next/link";
|
||||
import { NextSeo } from "next-seo";
|
||||
|
||||
export async function getStaticProps() {
|
||||
const jsonDirectory = path.join(process.cwd(), "/datasets.json");
|
||||
const repos = await fs.readFile(jsonDirectory, "utf8");
|
||||
const github_pat = getConfig().serverRuntimeConfig.github_pat;
|
||||
|
||||
const projects = await Promise.all(
|
||||
JSON.parse(repos).map(async (repo) => {
|
||||
const project = await getProject(repo, github_pat);
|
||||
return { ...project, repo_config: repo };
|
||||
})
|
||||
);
|
||||
return {
|
||||
props: {
|
||||
projects,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function Datasets({ projects }) {
|
||||
return (
|
||||
<>
|
||||
<NextSeo title="GitHub Datasets" />
|
||||
<div className="bg-white min-h-screen">
|
||||
<div className="mx-auto max-w-7xl px-6 py-16 sm:py-24 lg:px-8">
|
||||
<div className="text-center">
|
||||
<h2 className="text-3xl font-bold leading-10 tracking-tight">
|
||||
GitHub Datasets
|
||||
</h2>
|
||||
<p className="mt-3 mx-auto max-w-2xl text-base leading-7 text-gray-500">
|
||||
Data catalog with datasets hosted on GitHub by{" "}
|
||||
<Link
|
||||
target="_blank"
|
||||
className="underline"
|
||||
href="https://portaljs.org/"
|
||||
>
|
||||
🌀 PortalJS
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-20">
|
||||
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
||||
<table className="min-w-full divide-y divide-gray-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
|
||||
>
|
||||
Name
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
|
||||
>
|
||||
Repository
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
|
||||
>
|
||||
Description
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
|
||||
>
|
||||
Last updated
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="relative py-3.5 pl-3 pr-4 sm:pr-0"
|
||||
></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{projects.map((project) => (
|
||||
<tr key={project.id}>
|
||||
<td className="whitespace-nowrap px-3 py-6 text-sm text-gray-500">
|
||||
{project.repo_config.name
|
||||
? project.repo_config.name
|
||||
: project.full_name +
|
||||
(project.base_path === "/"
|
||||
? ""
|
||||
: "/" + project.base_path)}
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-3 py-6 text-sm group text-gray-500 hover:text-gray-900 transition-all duration-250">
|
||||
<a
|
||||
href={project.html_url}
|
||||
target="_blank"
|
||||
className="flex items-center"
|
||||
>
|
||||
@{project.full_name}{" "}
|
||||
<ExternalLinkIcon className="ml-1" />
|
||||
</a>
|
||||
</td>
|
||||
<td className="px-3 py-4 text-sm text-gray-500">
|
||||
{project.repo_config.description
|
||||
? project.repo_config.description
|
||||
: project.description}
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-3 py-6 text-sm text-gray-500">
|
||||
<TimeAgo date={new Date(project.last_updated)} />
|
||||
</td>
|
||||
<td className="relative whitespace-nowrap py-6 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
||||
<a
|
||||
href={`/@${project.repo_config.owner}/${
|
||||
project.repo_config.repo
|
||||
}/${
|
||||
project.base_path === "/" ? "" : project.base_path
|
||||
}`}
|
||||
className="border border-gray-900 text-gray-900 px-4 py-2 transition-all hover:bg-gray-900 hover:text-white"
|
||||
>
|
||||
info
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Datasets;
|
||||
@@ -1,80 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||
Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif,
|
||||
Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
||||
line-height: 1.5;
|
||||
tab-size: 4;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
body {
|
||||
font-family: inherit;
|
||||
line-height: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
p,
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
border-color: currentColor;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
Liberation Mono, Courier New, monospace;
|
||||
}
|
||||
svg {
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
shape-rendering: auto;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
pre {
|
||||
background-color: rgba(55, 65, 81, 1);
|
||||
border-radius: 0.25rem;
|
||||
color: rgba(229, 231, 235, 1);
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
Liberation Mono, Courier New, monospace;
|
||||
overflow: scroll;
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow: 0 0 #0000, 0 0 #0000, 0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
||||
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.rounded {
|
||||
border-radius: 1.5rem;
|
||||
}
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 768px;
|
||||
padding-bottom: 3rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
color: rgba(55, 65, 81, 1);
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require("@tailwindcss/typography")],
|
||||
};
|
||||
35
examples/openspending/.gitignore
vendored
@@ -1,35 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -1,102 +0,0 @@
|
||||
# A data catalog with data on GitHub
|
||||
|
||||
This example showcases a simple data catalog that get its data from a list of GitHub repos that serve as datasets.
|
||||
|
||||
A `datasets.json` file is used to specify which datasets are going to be part of the data catalog.
|
||||
|
||||
The application contains an index page, which lists all the datasets specified in the `datasets.json` file, and users can see more information about each dataset, such as the list of data files in it and the README, by clicking the "info" button on the list.
|
||||
|
||||
You can read more about it on the [Data catalog with data on GitHub](https://portaljs.org/docs/examples/github-backed-catalog) blog post.
|
||||
|
||||
## Demo
|
||||
|
||||
https://example.portaljs.org/
|
||||
|
||||
## Deploy your own
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdatopian%2Fportaljs%2Ftree%2Fmain%2Fexamples%2Fgithub-backed-catalog)
|
||||
|
||||
By clicking on this button, you will be redirected to a page which will allow you to clone the content into your own GitHub/GitLab/Bitbucket account and automatically deploy everything.
|
||||
|
||||
## How to use
|
||||
|
||||
### Install
|
||||
|
||||
Execute `create-next-app` to bootstrap the example:
|
||||
|
||||
```
|
||||
npx create-next-app <app-name> --example https://github.com/datopian/portaljs/tree/main/examples/github-backed-catalog
|
||||
cd <app-name>
|
||||
```
|
||||
|
||||
### Set environment variables
|
||||
|
||||
This project uses the GitHub API, which for anonymous users will cap at 50 requests per hour, so you might want to get a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) and add it to a `.env` file inside the folder like so
|
||||
|
||||
```
|
||||
GITHUB_PAT=<github token>
|
||||
```
|
||||
|
||||
### Change datasets
|
||||
|
||||
You can change the datasets that will be displayed in the data catalog by editing the file `datasets.json`. Some examples can be found inside [this repo](https://github.com/datasets).
|
||||
|
||||
### Run in development mode
|
||||
|
||||
Run the app using:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open http://localhost:3000 from your browser. You should see something similar to this:
|
||||
|
||||

|
||||
|
||||
If click on the `info` button for a dataset you will see a page similar to this:
|
||||
|
||||

|
||||
|
||||
## Notes
|
||||
|
||||
### Structure of `datasets.json`
|
||||
|
||||
The `datasets.json` file is simply a list of datasets, below you can see a minimal example of a dataset:
|
||||
|
||||
```json
|
||||
{
|
||||
"owner": "fivethirtyeight",
|
||||
"repo": "data",
|
||||
"branch": "master",
|
||||
"files": ["nba-raptor/historical_RAPTOR_by_player.csv", "nba-raptor/historical_RAPTOR_by_team.csv"],
|
||||
"readme": "nba-raptor/README.md"
|
||||
}
|
||||
```
|
||||
|
||||
It has:
|
||||
|
||||
- A `owner` which is going to be the github repo owner
|
||||
- A `repo` which is going to be the github repo name
|
||||
- A `branch` which is going to be the branch to which we need to get the files and the readme
|
||||
- A list of `files` which is going to be a list of paths with files that you want to show to the world
|
||||
- A `readme` which is going to be the path to your data description, it can also be a subpath eg: `example/README.md`
|
||||
|
||||
You can also add:
|
||||
|
||||
- A `description` which is useful if you have more than one dataset for each repo, if not provided we are just going to use the repo description
|
||||
- A `Name` which is useful if you want to give your dataset a nice name, if not provided we are going to use the junction of the `owner` the `repo` + the path of the README, in the exaple above it will be `fivethirtyeight/data/nba-raptor`
|
||||
|
||||
### Extra commands
|
||||
|
||||
You can also build the project for production with:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
And run the production build with:
|
||||
|
||||
```
|
||||
npm run start
|
||||
```
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { getAllProjectsFromOrg, getProjectDataPackage } from '../lib/project';
|
||||
import { loadDataPackage } from '../lib/loader';
|
||||
import { getProjectMetadata } from '../lib/project';
|
||||
import { getCsv, parseCsv } from '../components/Table';
|
||||
|
||||
test(
|
||||
'Test OS-Data',
|
||||
async () => {
|
||||
const repos = await getAllProjectsFromOrg(
|
||||
'os-data',
|
||||
'main',
|
||||
process.env.VITE_GITHUB_PAT
|
||||
);
|
||||
if (repos.failed.length > 0) console.log(repos.failed);
|
||||
expect(repos.failed.length).toBe(0);
|
||||
},
|
||||
{ timeout: 100000 }
|
||||
);
|
||||
|
||||
test(
|
||||
'Test Gift-Data',
|
||||
async () => {
|
||||
const repos = await getAllProjectsFromOrg(
|
||||
'gift-data',
|
||||
'main',
|
||||
process.env.VITE_GITHUB_PAT
|
||||
);
|
||||
if (repos.failed.length > 0) console.log(repos.failed);
|
||||
expect(repos.failed.length).toBe(0);
|
||||
},
|
||||
{ timeout: 100000 }
|
||||
);
|
||||
|
||||
test(
|
||||
'Test getting one dataset from github',
|
||||
async () => {
|
||||
const datapackage = await getProjectDataPackage(
|
||||
'os-data',
|
||||
'berlin-berlin',
|
||||
'main',
|
||||
process.env.VITE_GITHUB_PAT
|
||||
);
|
||||
const repo = await getProjectMetadata(
|
||||
'os-data',
|
||||
'berlin-berlin',
|
||||
process.env.VITE_GITHUB_PAT
|
||||
);
|
||||
const project = loadDataPackage(datapackage, repo);
|
||||
delete project['datapackage'];
|
||||
delete project.files[0]['dialect'];
|
||||
delete project.files[0]['schema'];
|
||||
expect(project).toStrictEqual({
|
||||
name: 'berlin-berlin',
|
||||
title: 'Berlin-Berlin',
|
||||
description: null,
|
||||
owner: {
|
||||
name: 'os-data',
|
||||
logo: 'https://avatars.githubusercontent.com/u/13695166?v=4',
|
||||
title: 'os-data',
|
||||
},
|
||||
repo: {
|
||||
name: 'berlin-berlin',
|
||||
full_name: 'os-data/berlin-berlin',
|
||||
url: 'https://github.com/os-data/berlin-berlin',
|
||||
},
|
||||
files: [
|
||||
{
|
||||
name: 'berlin-gesamt',
|
||||
format: 'csv',
|
||||
path: 'https://storage.openspending.org/berlin-berlin/berlin-gesamt.csv',
|
||||
mediatype: 'text/csv',
|
||||
bytes: 81128743,
|
||||
encoding: 'utf-8',
|
||||
},
|
||||
],
|
||||
author: 'Michael Peters <michael.peters@okfn.de>',
|
||||
cityCode: 'Berlin',
|
||||
countryCode: 'DE',
|
||||
fiscalPeriod: { start: '2014-01-01', end: '2019-12-31' },
|
||||
readme: '',
|
||||
});
|
||||
},
|
||||
{ timeout: 100000 }
|
||||
);
|
||||
|
||||
test(
|
||||
'Test getting one section of csv from R2',
|
||||
async () => {
|
||||
const rawCsv = await getCsv(
|
||||
'https://storage.openspending.org/state-of-minas-gerais-brazil-planned-budget/__os_imported__br-mg-ppagloc.csv'
|
||||
);
|
||||
const parsedCsv = await parseCsv(rawCsv);
|
||||
expect(parsedCsv.errors.length).toBe(1);
|
||||
expect(parsedCsv.data.length).toBe(10165);
|
||||
expect(parsedCsv.meta.fields).toStrictEqual([
|
||||
'function_name',
|
||||
'function_label',
|
||||
'product_name',
|
||||
'product_label',
|
||||
'area_name',
|
||||
'area_label',
|
||||
'subaction_name',
|
||||
'subaction_label',
|
||||
'region_label_map',
|
||||
'region_reg_map',
|
||||
'region_name',
|
||||
'region_label',
|
||||
'municipality_map_id',
|
||||
'municipality_name',
|
||||
'municipality_map_code',
|
||||
'municipality_label',
|
||||
'municipality_map_name_simple',
|
||||
'municipality_map_name',
|
||||
'cofog1_label_en',
|
||||
'cofog1_name',
|
||||
'cofog1_label',
|
||||
'amount',
|
||||
'subprogramme_name',
|
||||
'subprogramme_label',
|
||||
'time_name',
|
||||
'time_year',
|
||||
'time_month',
|
||||
'time_day',
|
||||
'time_week',
|
||||
'time_yearmonth',
|
||||
'time_quarter',
|
||||
'time',
|
||||
'action_name',
|
||||
'action_label',
|
||||
'subfunction_name',
|
||||
'subfunction_label',
|
||||
'programme_name',
|
||||
'programme_label',
|
||||
]);
|
||||
},
|
||||
{ timeout: 100000 }
|
||||
);
|
||||
@@ -1,15 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
import clsx from 'clsx';
|
||||
|
||||
export function Button({ href, className = '', ...props }) {
|
||||
className = clsx(
|
||||
'inline-flex justify-center rounded-2xl bg-emerald-600 p-4 text-base font-semibold text-white hover:bg-emerald-500 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500 active:text-white/70',
|
||||
className
|
||||
);
|
||||
|
||||
return href ? (
|
||||
<Link scroll={false} href={href} className={className} {...props} />
|
||||
) : (
|
||||
<button className={className} {...props} />
|
||||
);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import clsx from 'clsx'
|
||||
|
||||
export function Container({ className = "", ...props }) {
|
||||
return (
|
||||
<div
|
||||
className={clsx('mx-auto max-w-7xl px-4 sm:px-6 lg:px-8', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
import { Project } from '../lib/project.interface';
|
||||
import ExternalLinkIcon from './icons/ExternalLinkIcon';
|
||||
|
||||
export default function DatasetCard({ dataset }: { dataset: Project }) {
|
||||
return (
|
||||
<div
|
||||
key={dataset.name}
|
||||
className="overflow-hidden rounded-xl border border-gray-200"
|
||||
>
|
||||
<Link
|
||||
href={`/@${dataset.owner.name}/${dataset.repo.name}`}
|
||||
className="flex items-center gap-x-4 border-b border-gray-900/5 bg-gray-50 p-6"
|
||||
>
|
||||
<img
|
||||
src={dataset.owner.logo || '/assets/org-icon.svg'}
|
||||
alt={dataset.owner.name}
|
||||
className="h-12 w-12 flex-none rounded-lg bg-white object-cover ring-1 ring-gray-900/10 p-2"
|
||||
/>
|
||||
<div className="text-sm font-medium leading-6">
|
||||
<div className="text-gray-900 line-clamp-1">{dataset.title}</div>
|
||||
<div className="text-gray-500 line-clamp-1">
|
||||
{dataset.owner.title}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<dl className="-my-3 divide-y divide-gray-100 px-6 py-4 text-sm leading-6">
|
||||
<div className="flex justify-between gap-x-4 py-3">
|
||||
<dt className="text-gray-500">Name</dt>
|
||||
<dd className="flex items-start gap-x-2">
|
||||
<div className="font-medium text-gray-900 line-clamp-1">
|
||||
{dataset.name}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex justify-between gap-x-4 py-3">
|
||||
<dt className="text-gray-500">Country</dt>
|
||||
<dd className="flex items-start gap-x-2">
|
||||
<div className="font-medium text-gray-900">
|
||||
{dataset.countryCode}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex justify-between gap-x-4 py-3">
|
||||
<dt className="text-gray-500">Fiscal Period</dt>
|
||||
<dd className="text-gray-700">
|
||||
{dataset.fiscalPeriod?.start &&
|
||||
new Date(dataset.fiscalPeriod.start).getFullYear()}
|
||||
{dataset.fiscalPeriod?.end &&
|
||||
dataset.fiscalPeriod?.start !== dataset.fiscalPeriod?.end && (
|
||||
<>
|
||||
{' - '}
|
||||
{new Date(dataset.fiscalPeriod.end).getFullYear()}
|
||||
</>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex justify-between gap-x-4 py-3">
|
||||
<dt className="text-gray-500">Metadata</dt>
|
||||
<dd className="flex items-start gap-x-2">
|
||||
<div className="font-medium text-gray-900">
|
||||
<Link
|
||||
// TODO: this link may be incorrect for some datasets
|
||||
href={`https://github.com/${dataset.owner.name}/${dataset.repo.name}/blob/main/datapackage.json`}
|
||||
target="_blank"
|
||||
className="flex items-center hover:text-gray-700"
|
||||
>
|
||||
datapackage.json <ExternalLinkIcon className="ml-1" />
|
||||
</Link>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Project } from '../lib/project.interface';
|
||||
import DatasetCard from './DatasetCard';
|
||||
|
||||
export default function DatasetsGrid({ datasets }: { datasets: Project[] }) {
|
||||
return (
|
||||
<ul
|
||||
className="grid gap-x-6 gap-y-8 grid-cols-1 sm:grid-cols-2 md:grid-cols-3"
|
||||
role="list"
|
||||
>
|
||||
{datasets.map((dataset, idx) => {
|
||||
return (
|
||||
<li key={`datasets-grid-item-${idx}`}>
|
||||
<DatasetCard dataset={dataset} />
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
import { useForm } from 'react-hook-form';
|
||||
import DatasetsGrid from './DatasetsGrid';
|
||||
import { Project } from '../lib/project.interface';
|
||||
import { Index } from 'flexsearch';
|
||||
import {
|
||||
ChevronDoubleLeftIcon,
|
||||
ChevronDoubleRightIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
} from '@heroicons/react/24/solid';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function DatasetsSearch({
|
||||
datasets,
|
||||
availableCountries,
|
||||
}: {
|
||||
datasets: Project[];
|
||||
availableCountries;
|
||||
}) {
|
||||
const itemsPerPage = 6;
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
const index = new Index({ tokenize: 'full' });
|
||||
|
||||
datasets.forEach((dataset: Project) =>
|
||||
index.add(
|
||||
dataset.name,
|
||||
`${dataset.repo} ${dataset.name} ${dataset.title} ${dataset.author} ${dataset.title} ${dataset.cityCode} ${dataset.fiscalPeriod?.start} ${dataset.fiscalPeriod?.end}`
|
||||
)
|
||||
);
|
||||
|
||||
const { register, watch, handleSubmit, reset, resetField } = useForm({
|
||||
defaultValues: {
|
||||
searchTerm: '',
|
||||
country: '',
|
||||
minDate: '',
|
||||
maxDate: '',
|
||||
},
|
||||
});
|
||||
|
||||
const filteredDatasets = datasets
|
||||
.filter((dataset: Project) =>
|
||||
watch().searchTerm && watch().searchTerm !== ''
|
||||
? index.search(watch().searchTerm).includes(dataset.name)
|
||||
: true
|
||||
)
|
||||
.filter((dataset) =>
|
||||
watch().country && watch().country !== ''
|
||||
? dataset.countryCode === watch().country
|
||||
: true
|
||||
)
|
||||
// TODO: Does that really makes sense?
|
||||
// What if the fiscalPeriod is 2015-2017 and inputs are
|
||||
// set to 2015-2016. It's going to be filtered out but
|
||||
// it shouldn't.
|
||||
.filter((dataset) =>
|
||||
watch().minDate && watch().minDate !== ''
|
||||
? dataset.fiscalPeriod?.start >= watch().minDate
|
||||
: true
|
||||
)
|
||||
.filter((dataset) =>
|
||||
watch().maxDate && watch().maxDate !== ''
|
||||
? dataset.fiscalPeriod?.end <= watch().maxDate
|
||||
: true
|
||||
);
|
||||
|
||||
const paginatedDatasets = filteredDatasets.slice(
|
||||
(page - 1) * itemsPerPage,
|
||||
(page - 1) * itemsPerPage + itemsPerPage
|
||||
);
|
||||
|
||||
const pageCount = Math.ceil(filteredDatasets.length / itemsPerPage) || 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-3 sm:flex-row">
|
||||
<div className="min-w-0 flex-auto">
|
||||
<br />
|
||||
<div className="relative">
|
||||
<input
|
||||
placeholder="Search datasets"
|
||||
aria-label="Search datasets"
|
||||
{...register('searchTerm', { onChange: () => setPage(1) })}
|
||||
className="h-[3em] relative w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
|
||||
/>
|
||||
{watch().searchTerm !== '' && (
|
||||
<button
|
||||
onClick={() => resetField('searchTerm')}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="sm:basis-1/6">
|
||||
{/* TODO: nicer select e.g. headlessui example */}
|
||||
<label className="text-sm text-gray-600 font-medium">Country</label>
|
||||
<select
|
||||
className="h-[3em] w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
|
||||
{...register('country', { onChange: () => setPage(1) })}
|
||||
>
|
||||
<option value="">All</option>
|
||||
{availableCountries.map((country) => {
|
||||
return (
|
||||
<option key={country.code} value={country.code}>
|
||||
{country.title}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
<div className="sm:basis-1/6">
|
||||
<label className="text-sm text-gray-600 font-medium">Min. date</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
aria-label="Min. date"
|
||||
type="date"
|
||||
{...register('minDate', { onChange: () => setPage(1) })}
|
||||
className="h-[3em] w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sm:basis-1/6">
|
||||
<label className="text-sm text-gray-600 font-medium">Max. date</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
aria-label="Max. date"
|
||||
type="date"
|
||||
{...register('maxDate', { onChange: () => setPage(1) })}
|
||||
className="h-[3em] w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 mb-5">
|
||||
<span className="text-lg font-medium">
|
||||
{filteredDatasets.length} datasets found
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-full align-middle">
|
||||
<DatasetsGrid datasets={paginatedDatasets} />
|
||||
<div className="w-full flex justify-center mt-10">
|
||||
<button
|
||||
onClick={() => setPage(1)}
|
||||
disabled={page <= 1}
|
||||
className="disabled:text-gray-400"
|
||||
>
|
||||
<ChevronDoubleLeftIcon className="w-6 h-6" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (page > 1) setPage((prev) => --prev);
|
||||
}}
|
||||
disabled={page <= 1}
|
||||
className="disabled:text-gray-400"
|
||||
>
|
||||
<ChevronLeftIcon className="w-6 h-6" />
|
||||
</button>
|
||||
<span className="mx-5">
|
||||
Page {page} of {pageCount}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (page < pageCount) setPage((prev) => ++prev);
|
||||
}}
|
||||
disabled={page >= pageCount}
|
||||
className="disabled:text-gray-400"
|
||||
>
|
||||
<ChevronRightIcon className="w-6 h-6" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setPage(pageCount)}
|
||||
disabled={page >= pageCount}
|
||||
className="disabled:text-gray-400"
|
||||
>
|
||||
<ChevronDoubleRightIcon className="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const CloseIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width={20}
|
||||
height={20}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="Menu / Close_MD">
|
||||
<path
|
||||
id="Vector"
|
||||
d="M18 18L12 12M12 12L6 6M12 12L18 6M12 12L6 18"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
import Image from 'next/image';
|
||||
import { Container } from './Container';
|
||||
import logo from '../public/logo.svg';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Bars3Icon } from '@heroicons/react/24/outline';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function Header() {
|
||||
const [menuOpen, setMenuOpen] = useState<boolean>(false);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const isActive = (navLink) => {
|
||||
return router.asPath.split('?')[0] == navLink.href;
|
||||
};
|
||||
|
||||
const navLinks = [
|
||||
{
|
||||
title: 'Home',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
title: 'Datasets',
|
||||
href: '/#datasets',
|
||||
},
|
||||
// {
|
||||
// title: "Community",
|
||||
// href: "https://community.openspending.org/"
|
||||
// }
|
||||
];
|
||||
|
||||
return (
|
||||
<header className="relative z-50 pb-11 lg:pt-11">
|
||||
<Container className="flex flex-wrap items-center justify-between lg:flex-nowrap mt-10 lg:mt-0">
|
||||
<Link href="/" className="lg:mt-0 lg:grow lg:basis-0 flex items-center">
|
||||
<Image src={logo} alt="OpenSpending" className="h-12 w-auto" />
|
||||
</Link>
|
||||
<ul className="hidden list-none sm:flex gap-x-5 text-base font-medium">
|
||||
{navLinks.map((link, i) => (
|
||||
<li key={`nav-link-${i}`}>
|
||||
<Link
|
||||
className={`text-emerald-900 hover:text-emerald-600 ${
|
||||
isActive(link) ? 'text-emerald-600' : ''
|
||||
}`}
|
||||
href={link.href}
|
||||
scroll={false}
|
||||
>
|
||||
{link.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="hidden xl:block xl:grow"></div>
|
||||
<div className="sm:hidden sm:mt-10 lg:mt-0 lg:grow lg:basis-0 lg:justify-end">
|
||||
<button onClick={() => setMenuOpen(!menuOpen)}>
|
||||
<Bars3Icon className="w-8 h-8" />
|
||||
</button>
|
||||
</div>
|
||||
{menuOpen && (
|
||||
<div className={`sm:hidden basis-full mt-5 text-center`}>
|
||||
<ul className="gap-x-5 text-base font-medium">
|
||||
{navLinks.map((link, i) => (
|
||||
<li key={`nav-link-${i}`}>
|
||||
<Link
|
||||
className={`text-emerald-900 hover:text-emerald-600 ${
|
||||
isActive(link) ? 'text-emerald-600' : ''
|
||||
}`}
|
||||
href={link.href}
|
||||
scroll={false}
|
||||
>
|
||||
{link.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { Button } from './Button';
|
||||
import { Container } from './Container';
|
||||
|
||||
export function Hero({ countriesCount, datasetsCount, filesCount }) {
|
||||
return (
|
||||
<div className="relative pb-20 pt-10 sm:py-40" id="hero">
|
||||
<div className="absolute inset-x-0 -bottom-14 -top-48 overflow-hidden bg-green-50 bg-opacity-50">
|
||||
<div className="absolute inset-x-0 top-0 h-40 bg-gradient-to-b from-white" />
|
||||
<div className="absolute inset-x-0 bottom-0 h-40 bg-gradient-to-t from-white" />
|
||||
</div>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-2xl lg:max-w-4xl lg:px-12">
|
||||
<h1 className="font-display text-5xl font-bold tracking-tighter text-emerald-600 sm:text-7xl">
|
||||
It's our money!
|
||||
</h1>
|
||||
<div className="mt-6 space-y-6 font-display text-2xl tracking-tight text-emerald-900">
|
||||
<p>
|
||||
By understanding how governments spend money in our name can we
|
||||
have a say in how that money will affect our own lives. The
|
||||
journey starts here.
|
||||
</p>
|
||||
<p>
|
||||
OpenSpending is a free, open and global platform to search,
|
||||
visualise and analyse fiscal data in the public sphere.
|
||||
</p>
|
||||
</div>
|
||||
<Button href="#datasets" className="mt-10">
|
||||
Search datasets
|
||||
</Button>
|
||||
<dl className="mt-10 grid grid-cols-2 gap-x-10 gap-y-6 sm:mt-16 sm:gap-x-16 sm:gap-y-10 sm:text-center lg:auto-cols-auto lg:grid-flow-col lg:grid-cols-none lg:justify-start lg:text-left">
|
||||
{[
|
||||
// Added the plus sign because some datasets do not
|
||||
// contain defined countries
|
||||
['Countries', '+' + countriesCount],
|
||||
['Datasets', datasetsCount],
|
||||
['Files', filesCount],
|
||||
].map(([name, value]) => (
|
||||
<div key={name}>
|
||||
<dt className="font-mono text-sm text-emerald-600">{name}</dt>
|
||||
<dd className="mt-0.5 text-2xl font-semibold tracking-tight text-emerald-900">
|
||||
{value}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import {
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from 'react-query';
|
||||
import Papa from 'papaparse';
|
||||
import { Grid } from '@githubocto/flat-ui';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export async function getCsv(url: string) {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
Range: 'bytes=0-5132288',
|
||||
},
|
||||
});
|
||||
const data = await response.text();
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function parseCsv(file: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Papa.parse(file, {
|
||||
header: true,
|
||||
dynamicTyping: true,
|
||||
skipEmptyLines: true,
|
||||
transform: (value: string): string => {
|
||||
return value.trim();
|
||||
},
|
||||
complete: (results: any) => {
|
||||
return resolve(results);
|
||||
},
|
||||
error: (error: any) => {
|
||||
return reject(error);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const Spinning = () => {
|
||||
return (
|
||||
<div role="status w-fit mx-auto">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-8 h-8 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-emerald-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Table: React.FC<{ url: string }> = ({ url }) => {
|
||||
return (
|
||||
// Provide the client to your App
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TableInner url={url} />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const TableInner: React.FC<{ url: string }> = ({ url }) => {
|
||||
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
|
||||
['dataCsv', url],
|
||||
() => getCsv(url)
|
||||
);
|
||||
const { data: parsedData, isLoading: isParsing } = useQuery(
|
||||
['dataPreview', csvString],
|
||||
() => parseCsv(csvString),
|
||||
{ enabled: !!csvString }
|
||||
);
|
||||
if (isParsing || isDownloadingCSV)
|
||||
<div className="w-full">
|
||||
<Spinning />
|
||||
</div>;
|
||||
if (parsedData)
|
||||
return (
|
||||
<div className="h-[500px] overflow-scroll">
|
||||
<Grid data={parsedData.data} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import HomeIcon from "../icons/HomeIcon";
|
||||
|
||||
export default function Breadcrumbs({ links }: { links: { title: string, href?: string, target?: string }[] }) {
|
||||
const current = links.at(-1);
|
||||
|
||||
return <div className="flex items-center uppercase font-black text-xs">
|
||||
<Link className="flex items-center" href='/'><HomeIcon /></Link>
|
||||
|
||||
{/* {links.length > 1 && links.slice(0, -1).map((link) => {
|
||||
return <>
|
||||
<span className="mx-4">/</span>
|
||||
<Link href={link.href}>{link.title}</Link>
|
||||
</>
|
||||
})} */}
|
||||
|
||||
<span className="mx-4">/</span>
|
||||
<span>{current.title}</span>
|
||||
</div >
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Header } from '../Header';
|
||||
|
||||
export default function Layout({ children }) {
|
||||
return (
|
||||
<div className="bg-white min-h-screen">
|
||||
<Header />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function ExternalLinkIcon({ className = "" }) {
|
||||
return <div className={`inline-block w-4 ${className}`}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="currentColor"><path d="M 40 10 C 38.896 10 38 10.896 38 12 C 38 13.104 38.896 14 40 14 L 47.171875 14 L 30.585938 30.585938 C 29.804938 31.366938 29.804938 32.633063 30.585938 33.414062 C 30.976938 33.805063 31.488 34 32 34 C 32.512 34 33.023063 33.805062 33.414062 33.414062 L 50 16.828125 L 50 24 C 50 25.104 50.896 26 52 26 C 53.104 26 54 25.104 54 24 L 54 12 C 54 10.896 53.104 10 52 10 L 40 10 z M 18 12 C 14.691 12 12 14.691 12 18 L 12 46 C 12 49.309 14.691 52 18 52 L 46 52 C 49.309 52 52 49.309 52 46 L 52 34 C 52 32.896 51.104 32 50 32 C 48.896 32 48 32.896 48 34 L 48 46 C 48 47.103 47.103 48 46 48 L 18 48 C 16.897 48 16 47.103 16 46 L 16 18 C 16 16.897 16.897 16 18 16 L 30 16 C 31.104 16 32 15.104 32 14 C 32 12.896 31.104 12 30 12 L 18 12 z"/></svg></div>
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function HomeIcon({ className = "" }) {
|
||||
return <div className={`inline-block w-4 ${className}`}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M 12 2 A 1 1 0 0 0 11.289062 2.296875 L 1.203125 11.097656 A 0.5 0.5 0 0 0 1 11.5 A 0.5 0.5 0 0 0 1.5 12 L 4 12 L 4 20 C 4 20.552 4.448 21 5 21 L 9 21 C 9.552 21 10 20.552 10 20 L 10 14 L 14 14 L 14 20 C 14 20.552 14.448 21 15 21 L 19 21 C 19.552 21 20 20.552 20 20 L 20 12 L 22.5 12 A 0.5 0.5 0 0 0 23 11.5 A 0.5 0.5 0 0 0 22.796875 11.097656 L 12.716797 2.3027344 A 1 1 0 0 0 12.710938 2.296875 A 1 1 0 0 0 12 2 z"/></svg></div>
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
/**
|
||||
* Fiscal Data Package is a simple specification for data access and delivery of fiscal data.
|
||||
*/
|
||||
export type FiscalDataPackage = TabularDataPackage & {
|
||||
countryCode?: ISO31661Alpha2CountryCode
|
||||
regionCode?: string
|
||||
cityCode?: string
|
||||
author?: string
|
||||
readme?: string
|
||||
granularity?: GranularityOfResources
|
||||
fiscalPeriod?: FiscalPeriodForTheBudget
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* The profile of this descriptor.
|
||||
*/
|
||||
export type Profile = "tabular-data-package"
|
||||
/**
|
||||
* An identifier string. Lower case characters with `.`, `_`, `-` and `/` are allowed.
|
||||
*/
|
||||
export type Name = string
|
||||
/**
|
||||
* A property reserved for globally unique identifiers. Examples of identifiers that are unique include UUIDs and DOIs.
|
||||
*/
|
||||
export type ID = string
|
||||
/**
|
||||
* A human-readable title.
|
||||
*/
|
||||
export type Title = string
|
||||
/**
|
||||
* A text description. Markdown is encouraged.
|
||||
*/
|
||||
export type Description = string
|
||||
/**
|
||||
* The home on the web that is related to this data package.
|
||||
*/
|
||||
export type HomePage = string
|
||||
/**
|
||||
* The datetime on which this descriptor was created.
|
||||
*/
|
||||
export type Created = string
|
||||
/**
|
||||
* The contributors to this descriptor.
|
||||
*/
|
||||
export type Contributors = [Contributor, ...Contributor[]]
|
||||
/**
|
||||
* A human-readable title.
|
||||
*/
|
||||
export type Title1 = string
|
||||
/**
|
||||
* A fully qualified URL, or a POSIX file path.
|
||||
*/
|
||||
export type Path = string
|
||||
/**
|
||||
* An email address.
|
||||
*/
|
||||
export type Email = string
|
||||
/**
|
||||
* An organizational affiliation for this contributor.
|
||||
*/
|
||||
export type Organization = string
|
||||
/**
|
||||
* A list of keywords that describe this package.
|
||||
*/
|
||||
export type Keywords = [string, ...string[]]
|
||||
/**
|
||||
* A image to represent this package.
|
||||
*/
|
||||
export type Image = string
|
||||
/**
|
||||
* The license(s) under which this package is published.
|
||||
*/
|
||||
export type Licenses = [License, ...License[]]
|
||||
/**
|
||||
* A license for this descriptor.
|
||||
*/
|
||||
export type License =
|
||||
| {
|
||||
[k: string]: unknown
|
||||
}
|
||||
| {
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* An `array` of Tabular Data Resource objects, each compliant with the [Tabular Data Resource](/tabular-data-resource/) specification.
|
||||
*
|
||||
/**
|
||||
* A Tabular Data Resource.
|
||||
*/
|
||||
export interface TabularDataResource {
|
||||
format?: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
title?: string;
|
||||
schema?: Schema;
|
||||
sample?: any[];
|
||||
profile?: string;
|
||||
key?: string;
|
||||
path?: string;
|
||||
size?: number;
|
||||
bytes?: number;
|
||||
}
|
||||
|
||||
export interface Field {
|
||||
name: string;
|
||||
type: FieldType;
|
||||
}
|
||||
|
||||
export interface Schema {
|
||||
fields: Field[];
|
||||
}
|
||||
|
||||
export const OptionsFields = [
|
||||
"any",
|
||||
"array",
|
||||
"boolean",
|
||||
"date",
|
||||
"datetime",
|
||||
"duration",
|
||||
"geojson",
|
||||
"geopoint",
|
||||
"integer",
|
||||
"number",
|
||||
"object",
|
||||
"string",
|
||||
"time",
|
||||
"year",
|
||||
"yearmonth",
|
||||
] as const;
|
||||
|
||||
type FieldType = typeof OptionsFields[number];
|
||||
/**
|
||||
* A human-readable title.
|
||||
*/
|
||||
export type Title2 = string
|
||||
/**
|
||||
* A fully qualified URL, or a POSIX file path.
|
||||
*/
|
||||
export type Path1 = string
|
||||
/**
|
||||
* An email address.
|
||||
*/
|
||||
export type Email1 = string
|
||||
/**
|
||||
* The raw sources for this resource.
|
||||
*/
|
||||
export type Sources = Source[]
|
||||
|
||||
/**
|
||||
* A keyword that represents the direction of the spend, either expenditure or revenue.
|
||||
*/
|
||||
export type DirectionOfTheSpending = "expenditure" | "revenue"
|
||||
/**
|
||||
* A keyword that represents the phase of the data, can be proposed for a budget proposal, approved for an approved budget, adjusted for modified budget or executed for the enacted budget
|
||||
*/
|
||||
export type BudgetPhase = "proposed" | "approved" | "adjusted" | "executed"
|
||||
/**
|
||||
* Either an array of strings corresponding to the name attributes in a set of field objects in the fields array or a single string corresponding to one of these names. The value of primaryKey indicates the primary key or primary keys for the dimension.
|
||||
*/
|
||||
export type PrimaryKey = string | [string, ...string[]]
|
||||
/**
|
||||
* Describes what kind of a dimension it is.
|
||||
*/
|
||||
export type DimensionType =
|
||||
| "datetime"
|
||||
| "entity"
|
||||
| "classification"
|
||||
| "activity"
|
||||
| "fact"
|
||||
| "location"
|
||||
| "other"
|
||||
/**
|
||||
* The type of the classification.
|
||||
*/
|
||||
export type ClassificationType = "functional" | "administrative" | "economic"
|
||||
/**
|
||||
* A valid 2-digit ISO country code (ISO 3166-1 alpha-2), or, an array of valid ISO codes.
|
||||
*/
|
||||
export type ISO31661Alpha2CountryCode = string | [string, ...string[]]
|
||||
/**
|
||||
* A keyword that represents the type of spend data, eiter aggregated or transactional
|
||||
*/
|
||||
export type GranularityOfResources = "aggregated" | "transactional"
|
||||
|
||||
/**
|
||||
* Tabular Data Package
|
||||
*/
|
||||
export interface TabularDataPackage {
|
||||
profile: Profile
|
||||
name?: Name
|
||||
id?: ID
|
||||
title?: Title
|
||||
description?: Description
|
||||
homepage?: HomePage
|
||||
created?: Created
|
||||
contributors?: Contributors
|
||||
keywords?: Keywords
|
||||
image?: Image
|
||||
licenses?: Licenses
|
||||
resources: TabularDataResource[]
|
||||
sources?: Sources
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* A contributor to this descriptor.
|
||||
*/
|
||||
export interface Contributor {
|
||||
title: Title1
|
||||
path?: Path
|
||||
email?: Email
|
||||
organization?: Organization
|
||||
role?: string
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* A source file.
|
||||
*/
|
||||
export interface Source {
|
||||
title: Title2
|
||||
path?: Path1
|
||||
email?: Email1
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* Measures are numerical and correspond to financial amounts in the source data.
|
||||
*/
|
||||
export interface Measures {
|
||||
[k: string]: Measure
|
||||
}
|
||||
/**
|
||||
* Measure.
|
||||
*
|
||||
* This interface was referenced by `Measures`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^\w+".
|
||||
*/
|
||||
export interface Measure {
|
||||
source: string
|
||||
resource?: string
|
||||
currency: string
|
||||
factor?: number
|
||||
direction?: DirectionOfTheSpending
|
||||
phase?: BudgetPhase
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* Dimensions are groups of related fields. Dimensions cover all items other than the measure.
|
||||
*/
|
||||
export interface Dimensions {
|
||||
[k: string]: Dimension
|
||||
}
|
||||
/**
|
||||
* Dimension.
|
||||
*
|
||||
* This interface was referenced by `Dimensions`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^\w+".
|
||||
*/
|
||||
export interface Dimension {
|
||||
attributes: Attributes
|
||||
primaryKey: PrimaryKey
|
||||
dimensionType?: DimensionType
|
||||
classificationType?: ClassificationType
|
||||
[k: string]: unknown
|
||||
}
|
||||
/**
|
||||
* Attribute objects that make up the dimension
|
||||
*/
|
||||
export interface Attributes {
|
||||
/**
|
||||
* This interface was referenced by `Attributes`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^\w+".
|
||||
*/
|
||||
[k: string]: {
|
||||
source: string
|
||||
resource?: string
|
||||
constant?: string | number
|
||||
parent?: string
|
||||
labelfor?: string
|
||||
[k: string]: unknown
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The fiscal period of the dataset
|
||||
*/
|
||||
export interface FiscalPeriodForTheBudget {
|
||||
start: string
|
||||
end?: string
|
||||
[k: string]: unknown
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { FiscalDataPackage } from './datapackage.interface';
|
||||
import { Project } from './project.interface';
|
||||
|
||||
export function loadDataPackage(datapackage: FiscalDataPackage, repo): Project {
|
||||
return {
|
||||
name: datapackage.name,
|
||||
title: datapackage.title,
|
||||
description: datapackage.description || null,
|
||||
owner: {
|
||||
name: repo.owner.login,
|
||||
logo: repo.owner.avatar_url,
|
||||
// TODO: make this title work
|
||||
title: repo.owner.login,
|
||||
},
|
||||
repo: { name: repo.name, full_name: repo.full_name, url: repo.html_url },
|
||||
files: datapackage.resources,
|
||||
author: datapackage.author ? datapackage.author : null,
|
||||
cityCode: datapackage.cityCode ? datapackage.cityCode : null,
|
||||
countryCode: datapackage.countryCode
|
||||
? (datapackage.countryCode as string)
|
||||
: null,
|
||||
fiscalPeriod: datapackage.fiscalPeriod
|
||||
? {
|
||||
start: datapackage.fiscalPeriod.start
|
||||
? datapackage.fiscalPeriod.start
|
||||
: null,
|
||||
end: datapackage.fiscalPeriod.end
|
||||
? datapackage.fiscalPeriod.end
|
||||
: null,
|
||||
}
|
||||
: null,
|
||||
readme: datapackage.readme ? datapackage.readme : '',
|
||||
datapackage,
|
||||
};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import {
|
||||
FiscalDataPackage,
|
||||
TabularDataResource,
|
||||
} from './datapackage.interface';
|
||||
|
||||
export interface Project {
|
||||
owner: { name: string; logo?: string; title?: string }; // Info about the owner of the data repo
|
||||
repo: { name: string; full_name: string; url: string }; // Info about the the data repo
|
||||
files: TabularDataResource[];
|
||||
name: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
author?: string;
|
||||
cityCode?: string;
|
||||
countryCode?: string;
|
||||
fiscalPeriod?: {
|
||||
start: string;
|
||||
end: string;
|
||||
};
|
||||
readme?: string;
|
||||
datapackage: FiscalDataPackage;
|
||||
}
|
||||