diff --git a/package.json b/package.json index 6953e55..068e34c 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "@types/chart.js": "^2.9.41", "astro": "^4.2.4", "chart.js": "^4.4.1", + "chartjs-adapter-date-fns": "^3.0.0", + "date-fns": "^3.3.1", "lodash": "^4.17.21", "lucide-solid": "^0.319.0", "lucide-static": "^0.319.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 227118e..32b183a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,12 +1,16 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@astrojs/node': specifier: ^7.0.4 version: 7.0.4(astro@4.2.4) '@astrojs/solid-js': specifier: ^4.0.1 - version: 4.0.1(solid-js@1.8.12)(vite@5.1.1) + version: 4.0.1(solid-js@1.8.12)(vite@5.0.12) '@astrojs/tailwind': specifier: ^5.1.0 version: 5.1.0(astro@4.2.4)(tailwindcss@3.4.1) @@ -31,6 +35,12 @@ dependencies: chart.js: specifier: ^4.4.1 version: 4.4.1 + chartjs-adapter-date-fns: + specifier: ^3.0.0 + version: 3.0.0(chart.js@4.4.1)(date-fns@3.3.1) + date-fns: + specifier: ^3.3.1 + version: 3.3.1 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -160,14 +170,14 @@ packages: dependencies: prismjs: 1.29.0 - /@astrojs/solid-js@4.0.1(solid-js@1.8.12)(vite@5.1.1): + /@astrojs/solid-js@4.0.1(solid-js@1.8.12)(vite@5.0.12): resolution: {integrity: sha512-XjViecwQDEO/e3OWCCORPYtYLS7MUNWvAWGVvNkzhAyVYZbM2fzckp94WkhX/qPu1rPUyNxSMXnN6IXkiVRTwA==} engines: {node: '>=18.14.1'} peerDependencies: solid-js: ^1.8.5 dependencies: solid-js: 1.8.12 - vite-plugin-solid: 2.9.1(solid-js@1.8.12)(vite@5.1.1) + vite-plugin-solid: 2.9.1(solid-js@1.8.12)(vite@5.0.12) transitivePeerDependencies: - '@testing-library/jest-dom' - supports-color @@ -737,14 +747,6 @@ packages: engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true - /@rollup/rollup-android-arm-eabi@4.10.0: - resolution: {integrity: sha512-/MeDQmcD96nVoRumKUljsYOLqfv1YFJps+0pTrb2Z9Nl/w5qNUysMaWQsrd1mvAlNT4yza1iVyIu4Q4AgF6V3A==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-android-arm-eabi@4.9.6: resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==} cpu: [arm] @@ -752,14 +754,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-android-arm64@4.10.0: - resolution: {integrity: sha512-lvu0jK97mZDJdpZKDnZI93I0Om8lSDaiPx3OiCk0RXn3E8CMPJNS/wxjAvSJJzhhZpfjXsjLWL8LnS6qET4VNQ==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-android-arm64@4.9.6: resolution: {integrity: sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==} cpu: [arm64] @@ -767,14 +761,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-darwin-arm64@4.10.0: - resolution: {integrity: sha512-uFpayx8I8tyOvDkD7X6n0PriDRWxcqEjqgtlxnUA/G9oS93ur9aZ8c8BEpzFmsed1TH5WZNG5IONB8IiW90TQg==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-darwin-arm64@4.9.6: resolution: {integrity: sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==} cpu: [arm64] @@ -782,14 +768,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-darwin-x64@4.10.0: - resolution: {integrity: sha512-nIdCX03qFKoR/MwQegQBK+qZoSpO3LESurVAC6s6jazLA1Mpmgzo3Nj3H1vydXp/JM29bkCiuF7tDuToj4+U9Q==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-darwin-x64@4.9.6: resolution: {integrity: sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==} cpu: [x64] @@ -797,14 +775,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.10.0: - resolution: {integrity: sha512-Fz7a+y5sYhYZMQFRkOyCs4PLhICAnxRX/GnWYReaAoruUzuRtcf+Qnw+T0CoAWbHCuz2gBUwmWnUgQ67fb3FYw==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.9.6: resolution: {integrity: sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==} cpu: [arm] @@ -812,14 +782,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.10.0: - resolution: {integrity: sha512-yPtF9jIix88orwfTi0lJiqINnlWo6p93MtZEoaehZnmCzEmLL0eqjA3eGVeyQhMtxdV+Mlsgfwhh0+M/k1/V7Q==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-linux-arm64-gnu@4.9.6: resolution: {integrity: sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==} cpu: [arm64] @@ -827,14 +789,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-linux-arm64-musl@4.10.0: - resolution: {integrity: sha512-9GW9yA30ib+vfFiwjX+N7PnjTnCMiUffhWj4vkG4ukYv1kJ4T9gHNg8zw+ChsOccM27G9yXrEtMScf1LaCuoWQ==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-linux-arm64-musl@4.9.6: resolution: {integrity: sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==} cpu: [arm64] @@ -842,14 +796,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.10.0: - resolution: {integrity: sha512-X1ES+V4bMq2ws5fF4zHornxebNxMXye0ZZjUrzOrf7UMx1d6wMQtfcchZ8SqUnQPPHdOyOLW6fTcUiFgHFadRA==} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-linux-riscv64-gnu@4.9.6: resolution: {integrity: sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==} cpu: [riscv64] @@ -857,14 +803,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-linux-x64-gnu@4.10.0: - resolution: {integrity: sha512-w/5OpT2EnI/Xvypw4FIhV34jmNqU5PZjZue2l2Y3ty1Ootm3SqhI+AmfhlUYGBTd9JnpneZCDnt3uNOiOBkMyw==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-linux-x64-gnu@4.9.6: resolution: {integrity: sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==} cpu: [x64] @@ -872,14 +810,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-linux-x64-musl@4.10.0: - resolution: {integrity: sha512-q/meftEe3QlwQiGYxD9rWwB21DoKQ9Q8wA40of/of6yGHhZuGfZO0c3WYkN9dNlopHlNT3mf5BPsUSxoPuVQaw==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-linux-x64-musl@4.9.6: resolution: {integrity: sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==} cpu: [x64] @@ -887,14 +817,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.10.0: - resolution: {integrity: sha512-NrR6667wlUfP0BHaEIKgYM/2va+Oj+RjZSASbBMnszM9k+1AmliRjHc3lJIiOehtSSjqYiO7R6KLNrWOX+YNSQ==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-win32-arm64-msvc@4.9.6: resolution: {integrity: sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==} cpu: [arm64] @@ -902,14 +824,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.10.0: - resolution: {integrity: sha512-FV0Tpt84LPYDduIDcXvEC7HKtyXxdvhdAOvOeWMWbQNulxViH2O07QXkT/FffX4FqEI02jEbCJbr+YcuKdyyMg==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-win32-ia32-msvc@4.9.6: resolution: {integrity: sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==} cpu: [ia32] @@ -917,14 +831,6 @@ packages: requiresBuild: true optional: true - /@rollup/rollup-win32-x64-msvc@4.10.0: - resolution: {integrity: sha512-OZoJd+o5TaTSQeFFQ6WjFCiltiYVjIdsXxwu/XZ8qRpsvMQr4UsVrE5UyT9RIvsnuF47DqkJKhhVZ2Q9YW9IpQ==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false - optional: true - /@rollup/rollup-win32-x64-msvc@4.9.6: resolution: {integrity: sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==} cpu: [x64] @@ -1457,6 +1363,16 @@ packages: '@kurkle/color': 0.3.2 dev: false + /chartjs-adapter-date-fns@3.0.0(chart.js@4.4.1)(date-fns@3.3.1): + resolution: {integrity: sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==} + peerDependencies: + chart.js: '>=2.8.0' + date-fns: '>=2.0.0' + dependencies: + chart.js: 4.4.1 + date-fns: 3.3.1 + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1590,6 +1506,10 @@ packages: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} dev: false + /date-fns@3.3.1: + resolution: {integrity: sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==} + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -3096,15 +3016,6 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /postcss@8.4.35: - resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.0.2 - dev: false - /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} engines: {node: '>=10'} @@ -3397,29 +3308,6 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - /rollup@4.10.0: - resolution: {integrity: sha512-t2v9G2AKxcQ8yrG+WGxctBes1AomT0M4ND7jTFBCVPXQ/WFTvNSefIrNSmLKhIKBrvN8SG+CZslimJcT3W2u2g==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.10.0 - '@rollup/rollup-android-arm64': 4.10.0 - '@rollup/rollup-darwin-arm64': 4.10.0 - '@rollup/rollup-darwin-x64': 4.10.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.10.0 - '@rollup/rollup-linux-arm64-gnu': 4.10.0 - '@rollup/rollup-linux-arm64-musl': 4.10.0 - '@rollup/rollup-linux-riscv64-gnu': 4.10.0 - '@rollup/rollup-linux-x64-gnu': 4.10.0 - '@rollup/rollup-linux-x64-musl': 4.10.0 - '@rollup/rollup-win32-arm64-msvc': 4.10.0 - '@rollup/rollup-win32-ia32-msvc': 4.10.0 - '@rollup/rollup-win32-x64-msvc': 4.10.0 - fsevents: 2.3.3 - dev: false - /rollup@4.9.6: resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4081,7 +3969,7 @@ packages: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - /vite-plugin-solid@2.9.1(solid-js@1.8.12)(vite@5.1.1): + /vite-plugin-solid@2.9.1(solid-js@1.8.12)(vite@5.0.12): resolution: {integrity: sha512-RC4hj+lbvljw57BbMGDApvEOPEh14lwrr/GeXRLNQLcR1qnOdzOwwTSFy13Gj/6FNIZpBEl0bWPU+VYFawrqUw==} peerDependencies: '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* @@ -4097,8 +3985,8 @@ packages: merge-anything: 5.1.7 solid-js: 1.8.12 solid-refresh: 0.6.3(solid-js@1.8.12) - vite: 5.1.1(@types/node@20.11.17) - vitefu: 0.2.5(vite@5.1.1) + vite: 5.0.12(@types/node@20.11.17) + vitefu: 0.2.5(vite@5.0.12) transitivePeerDependencies: - supports-color dev: false @@ -4138,42 +4026,6 @@ packages: optionalDependencies: fsevents: 2.3.3 - /vite@5.1.1(@types/node@20.11.17): - resolution: {integrity: sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 20.11.17 - esbuild: 0.19.12 - postcss: 8.4.35 - rollup: 4.10.0 - optionalDependencies: - fsevents: 2.3.3 - dev: false - /vitefu@0.2.5(vite@5.0.12): resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} peerDependencies: @@ -4184,17 +4036,6 @@ packages: dependencies: vite: 5.0.12(@types/node@20.11.17) - /vitefu@0.2.5(vite@5.1.1): - resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - vite: - optional: true - dependencies: - vite: 5.1.1(@types/node@20.11.17) - dev: false - /web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -4297,7 +4138,3 @@ packages: astro: 4.2.4(@types/node@20.11.17) ultrahtml: 1.5.2 dev: true - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false diff --git a/src/components/widgets/BarChart.tsx b/src/components/widgets/BarChart.tsx new file mode 100644 index 0000000..49286d1 --- /dev/null +++ b/src/components/widgets/BarChart.tsx @@ -0,0 +1,64 @@ +// @ts-nocheck + +import { onMount } from "solid-js" +import { Chart, Title, Tooltip, Colors, TimeScale, type ChartOptions, type ChartData } from "chart.js" +import { Bar } from "solid-chartjs" +import "chartjs-adapter-date-fns" + +type BarChartProps = { + labels: string[] + data: number[] + labelObjectName: string + useTimeScale?: boolean +} + +const longNumberFormatter = new Intl.NumberFormat("en-us") + +export function BarChart(props: BarChartProps) { + let canvas: HTMLCanvasElement + onMount(() => { + Chart.register(Title, Tooltip, Colors, TimeScale) + }) + + const chartData: ChartData = { + labels: props.labels, + datasets: [ + { + data: props.data, + backgroundColor: "#5EC269", + }, + ], + } + + const chartOptions: ChartOptions = { + responsive: true, + maintainAspectRatio: true, + animation: false, + interaction: { + intersect: false, + mode: "index", + }, + scales: { + x: props.useTimeScale + ? { + type: "time", + time: { unit: "day", tooltipFormat: "d MMM, y" }, + } + : {}, + }, + plugins: { + tooltip: { + displayColors: false, + callbacks: { + label: (c) => `${longNumberFormatter.format(c.parsed.y)} ${props.labelObjectName}`, + }, + }, + }, + } + + return ( +
+ (canvas = c)} /> +
+ ) +} diff --git a/src/components/widgets/WinrateChart.tsx b/src/components/widgets/WinrateChart.tsx index d5c5ff2..687e0f8 100644 --- a/src/components/widgets/WinrateChart.tsx +++ b/src/components/widgets/WinrateChart.tsx @@ -5,7 +5,6 @@ import { Chart, Title, Tooltip, - Legend, Colors, type ChartOptions, type ChartData, diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 2b28612..160a6e9 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -8,7 +8,8 @@ export { OpenAPI } from "./core/OpenAPI" export type { OpenAPIConfig } from "./core/OpenAPI" export type { ActivityStatistics } from "./models/ActivityStatistics" -export type { ActivityStatisticsDayEntry } from "./models/ActivityStatisticsDayEntry" +export type { ActivityStatisticsActivity } from "./models/ActivityStatisticsActivity" +export type { ActivityStatisticsEntry } from "./models/ActivityStatisticsEntry" export type { ActivityStatisticsServerEntry } from "./models/ActivityStatisticsServerEntry" export type { ErrorResponse } from "./models/ErrorResponse" export { Leaderboard } from "./models/Leaderboard" diff --git a/src/lib/api/models/ActivityStatistics.ts b/src/lib/api/models/ActivityStatistics.ts index 44facc5..765f8ef 100644 --- a/src/lib/api/models/ActivityStatistics.ts +++ b/src/lib/api/models/ActivityStatistics.ts @@ -2,9 +2,11 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ActivityStatisticsDayEntry } from "./ActivityStatisticsDayEntry" +import type { ActivityStatisticsActivity } from "./ActivityStatisticsActivity" import type { ActivityStatisticsServerEntry } from "./ActivityStatisticsServerEntry" export type ActivityStatistics = { - activity: Array + since: string + until: string + activity: ActivityStatisticsActivity servers: Array } diff --git a/src/lib/api/models/ActivityStatisticsActivity.ts b/src/lib/api/models/ActivityStatisticsActivity.ts new file mode 100644 index 0000000..ae99489 --- /dev/null +++ b/src/lib/api/models/ActivityStatisticsActivity.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ActivityStatisticsEntry } from "./ActivityStatisticsEntry" +export type ActivityStatisticsActivity = { + aggregated: ActivityStatisticsEntry + history: Array +} diff --git a/src/lib/api/models/ActivityStatisticsDayEntry.ts b/src/lib/api/models/ActivityStatisticsEntry.ts similarity index 76% rename from src/lib/api/models/ActivityStatisticsDayEntry.ts rename to src/lib/api/models/ActivityStatisticsEntry.ts index 7dc6a49..2fefb0c 100644 --- a/src/lib/api/models/ActivityStatisticsDayEntry.ts +++ b/src/lib/api/models/ActivityStatisticsEntry.ts @@ -2,8 +2,8 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type ActivityStatisticsDayEntry = { - date: string +export type ActivityStatisticsEntry = { + date?: string | null matches: number players: number match_length_average: number diff --git a/src/lib/api/models/PlayerResponse.ts b/src/lib/api/models/PlayerResponse.ts index 776d2d6..ab4b0f9 100644 --- a/src/lib/api/models/PlayerResponse.ts +++ b/src/lib/api/models/PlayerResponse.ts @@ -11,4 +11,5 @@ export type PlayerResponse = { avatar_url?: string | null leaderboard_entries: Array last_match_ended_at?: string | null + last_match_started_at?: string | null } diff --git a/src/lib/api/services/StatisticsApi.ts b/src/lib/api/services/StatisticsApi.ts index a3f2f89..f4aa664 100644 --- a/src/lib/api/services/StatisticsApi.ts +++ b/src/lib/api/services/StatisticsApi.ts @@ -13,10 +13,20 @@ export class StatisticsApi { * @returns ActivityStatistics Stats * @throws ApiError */ - public static getStatisticsActivity(): CancelablePromise { + public static getStatisticsActivity({ + since, + until, + }: { + since?: string | null + until?: string | null + }): CancelablePromise { return __request(OpenAPI, { method: "GET", url: "/v0/statistics/activity", + query: { + since: since, + until: until, + }, errors: { 500: `Server error`, }, diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 9bdf4d8..14d6d8b 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -33,3 +33,14 @@ export function formatDuration(seconds?: number | null) { export function urlencode(str: string) { return encodeURIComponent(str).replace(/%20/g, "-").replace(/%2F/g, "-") } + +export async function getDataOrErrorResponse( + ...values: T +): Promise<[{ -readonly [P in keyof T]: Awaited }, error: Response | null]> { + try { + const result = await Promise.all(values) + return [result, null] + } catch (e) { + return [[] as any, new Response(null, { status: 500, statusText: `${e}` })] + } +} diff --git a/src/pages/players/[id]-[username].astro b/src/pages/players/[id]-[username].astro index 7f33c18..00fca1b 100644 --- a/src/pages/players/[id]-[username].astro +++ b/src/pages/players/[id]-[username].astro @@ -21,23 +21,12 @@ import Section from "../../components/layout/Section.astro" import Main from "../../components/layout/Main.astro" import Sidebar from "../../components/layout/Sidebar.astro" import { formatDateRelative } from "../../lib/format" +import { getDataOrErrorResponse } from "../../lib/utils" import PlayerFactionCard from "../../components/widgets/PlayerFactionCard.astro" import Box from "../../components/layout/Box.astro" type Theme = keyof typeof styles.badges -// to be moved to own file -async function getDataOrErrorResponse( - ...values: T -): Promise<[{ -readonly [P in keyof T]: Awaited }, error: Response | null]> { - try { - const result = await Promise.all(values) - return [result, null] - } catch (e) { - return [[] as any, new Response(null, { status: 500, statusText: `${e}` })] - } -} - const playerId = Astro.params.id! const [[player, playerMatches, playerActivity, playerMatchupStats, playerOpponents], error] = await getDataOrErrorResponse( diff --git a/src/pages/stats.astro b/src/pages/stats.astro index 93a6c3f..86fdd28 100644 --- a/src/pages/stats.astro +++ b/src/pages/stats.astro @@ -3,23 +3,45 @@ export const prerender = false import { Image } from "astro:assets" import { WinrateChart } from "../components/widgets/WinrateChart" +import { BarChart } from "../components/widgets/BarChart" + import Layout from "../layouts/Layout.astro" -import { Race, type StatsByTimeEntry } from "../lib/api" +import { League, Race, type StatsByTimeEntry } from "../lib/api" import { StatisticsApi } from "../lib/api/services/StatisticsApi" -import { formatNumber } from "../lib/utils" -import Timeago from "../components/Timeago.astro" +import { formatNumber, getDataOrErrorResponse } from "../lib/utils" import { LeagueDropdown } from "../components/widgets/LeagueDropdown" import Header from "../components/layout/Header.astro" import Section from "../components/layout/Section.astro" import HeaderMeta from "../components/layout/HeaderMeta.astro" import { formatDateRelative } from "../lib/format" -import Main from "../components/layout/Main.astro" +import { Widget } from "../components/ui/Widget" const league = new URLSearchParams(Astro.url.search).get("league") -const { races, cached_at } = await StatisticsApi.getStatistics({ league }) + +const longNumberFormatter = new Intl.NumberFormat("en-us") + +const [[{ races, cached_at }, { activity }], error] = await getDataOrErrorResponse( + StatisticsApi.getStatistics({ league: league ? (league as League) : null }), + StatisticsApi.getStatisticsActivity({}) +) +if (error) return error + const durationLabels = ["0-300", "301-600", "601-900", "901-1200", "1201+"] const durationPrettyLabels = ["0-5m", "5-10m", "10-15m", "15-20m", "20m+"] +const numberPlayers: number[] = [] +const numberMatches: number[] = [] +const dateLabels: string[] = [] +for (const entry of activity.history) { + if (entry.date) { + dateLabels.push(entry.date) + numberMatches.push(entry.matches) + numberPlayers.push(entry.players) + } +} + +const earliestDate = new Date(dateLabels[0]) + function mapFactionWinrate(race: StatsByTimeEntry) { const round = (value: number) => Math.round(value * 10) / 10 const winrate = round(race.aggregated.win_rate!) @@ -95,8 +117,7 @@ const factions = [
{ factions.map((faction) => ( -
-

{faction.name}

+
Vanguard
@@ -121,13 +142,30 @@ const factions = [ Based on {formatNumber(faction.stats.matches.count!)} matches in the past 7 days, excl.{" "} {formatNumber(faction.stats.matches.mirrors!)} mirrors

-
+ )) }
-
-

More stats soon

-
+
+ +
+
+ + +

+ In total, {longNumberFormatter.format(activity.aggregated.matches)} ranked games were played since { + earliestDate.toLocaleDateString("en", { dateStyle: "long" }) + }. +

+
+ + +

+ In total, {longNumberFormatter.format(activity.aggregated.players)} persons played on the ladder since { + earliestDate.toLocaleDateString("en", { dateStyle: "long" }) + }. +

+