diff options
author | mat <github@matdoes.dev> | 2022-03-04 18:32:23 +0000 |
---|---|---|
committer | mat <github@matdoes.dev> | 2022-03-04 18:32:23 +0000 |
commit | bdec09128e134238e3e0efdaa7cf6e7c46c19c94 (patch) | |
tree | a083c5f2354ac15d4771eb168267d49d55e84076 /src | |
parent | 8168f3807966913640e95e074248f31e7444416c (diff) | |
download | skyblock-stats-bdec09128e134238e3e0efdaa7cf6e7c46c19c94.tar.gz skyblock-stats-bdec09128e134238e3e0efdaa7cf6e7c46c19c94.tar.bz2 skyblock-stats-bdec09128e134238e3e0efdaa7cf6e7c46c19c94.zip |
add leaderboards
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/utils.ts | 20 | ||||
-rw-r--r-- | src/routes/leaderboard/[name].ts | 10 | ||||
-rw-r--r-- | src/routes/leaderboard/index.ts | 8 | ||||
-rw-r--r-- | src/routes/leaderboards/[name].svelte | 86 | ||||
-rw-r--r-- | src/routes/leaderboards/index.svelte | 54 |
5 files changed, 178 insertions, 0 deletions
diff --git a/src/lib/utils.ts b/src/lib/utils.ts index c581af0..aabd981 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -114,6 +114,13 @@ export function cleanId(id: string) { .replace(/_/g, ' ') } +export function toTitleCase(s: string) { + return s.replace( + /\w\S*/g, + w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase() + ) +} + export function toRomanNumerals(number: number) { return ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX'][number] } @@ -151,4 +158,17 @@ export function formatNumber(n: number, digits = 3) { ] const item = numberSymbolsLookup.slice().reverse().find(item => n >= item.value) return (n / (item?.value ?? 1)).toPrecision(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + (item?.symbol ?? '') +} + +export function formatNumberFromUnit(n: number, unit: null | 'date' | 'time' | string) { + switch (unit) { + case null: + return n.toLocaleString() + case 'date': + return (new Date(n * 1000)).toUTCString() + case 'time': + return millisecondsToTime(Math.abs(n)) + default: + return `${n.toLocaleString()} ${unit}` + } }
\ No newline at end of file diff --git a/src/routes/leaderboard/[name].ts b/src/routes/leaderboard/[name].ts new file mode 100644 index 0000000..fac1ee9 --- /dev/null +++ b/src/routes/leaderboard/[name].ts @@ -0,0 +1,10 @@ +// The route /leaderboard/<name> was moved to /leaderboards/<name> for +// consistency. +export async function get({ params }) { + return { + status: 303, + headers: { + location: `/leaderboards/${params.name}` + } + } +} diff --git a/src/routes/leaderboard/index.ts b/src/routes/leaderboard/index.ts new file mode 100644 index 0000000..beda8d6 --- /dev/null +++ b/src/routes/leaderboard/index.ts @@ -0,0 +1,8 @@ +export async function get({ request }) { + return { + status: 303, + headers: { + location: '/leaderboards' + } + } +} diff --git a/src/routes/leaderboards/[name].svelte b/src/routes/leaderboards/[name].svelte new file mode 100644 index 0000000..2aec4b3 --- /dev/null +++ b/src/routes/leaderboards/[name].svelte @@ -0,0 +1,86 @@ +<script lang="ts" context="module"> + import type { Load } from '@sveltejs/kit' + import { API_URL } from '$lib/api' + + export const load: Load = async ({ params, fetch }) => { + const data = await fetch(`${API_URL}leaderboard/${params.name}`).then(r => r.json()) + + if (data.list.length === 0) return { fallthrough: true } as unknown + + return { + props: { + data, + }, + } as any + } +</script> + +<script lang="ts"> + import Header from '$lib/Header.svelte' + import Head from '$lib/Head.svelte' + import Toc from '$lib/Toc.svelte' + import Collapsible from '$lib/Collapsible.svelte' + import { skyblockItemNameToItem, skyblockItemToUrl } from '$lib/minecraft/inventory' + import { cleanId, formatNumberFromUnit, toTitleCase } from '$lib/utils' + import ListItemWithIcon from '$lib/ListItemWithIcon.svelte' + import Leaderboards from '$lib/sections/Leaderboards.svelte' + import Username from '$lib/minecraft/Username.svelte' + + export let data + + $: imageUrl = data.name.startsWith('collection_') ? skyblockItemToUrl(data.name.slice(11)) : null +</script> + +<Head title={`${cleanId(data.name)} - SkyBlock Leaderboards`} /> +<Header backArrowHref="/leaderboards" /> + +<main> + <h1> + {#if imageUrl} + <img src={imageUrl} alt={cleanId(data.name.slice(11))} /> + {/if} + {toTitleCase(cleanId(data.name))} + </h1> + {#if data.info} + <p class="leaderboard-info">{data.info}</p> + {/if} + + <ol class="leaderboard-profile-list"> + {#each data.list as leaderboardItem} + <li> + <span> + {formatNumberFromUnit( + leaderboardItem.value, + leaderboardItem.unit ?? cleanId(data.name).toLowerCase() + )} + </span> + {#if leaderboardItem.player} + <Username + player={leaderboardItem.player} + headType="2d" + hyperlinkToProfile={leaderboardItem.profileUuid} + /> + {:else if leaderboardItem.players} + {#each leaderboardItem.players as player} + <span class="leaderboard-profile-player"> + <Username {player} headType="2d" hyperlinkToProfile /> + </span> + {/each} + {:else} + Unknown player + {/if} + </li> + {/each} + </ol> +</main> + +<style> + h1 > img { + height: 1em; + vertical-align: text-top; + } + + .leaderboard-profile-player { + margin-right: 0.5em; + } +</style> diff --git a/src/routes/leaderboards/index.svelte b/src/routes/leaderboards/index.svelte new file mode 100644 index 0000000..b6815e5 --- /dev/null +++ b/src/routes/leaderboards/index.svelte @@ -0,0 +1,54 @@ +<script lang="ts" context="module"> + import type { Load } from '@sveltejs/kit' + import { API_URL } from '$lib/api' + + export const load: Load = async ({ params, fetch }) => { + const data = await fetch(`${API_URL}leaderboards`).then(r => r.json()) + + return { + props: { + data, + }, + } + } +</script> + +<script lang="ts"> + import Header from '$lib/Header.svelte' + import Head from '$lib/Head.svelte' + import Toc from '$lib/Toc.svelte' + import Collapsible from '$lib/Collapsible.svelte' + import { skyblockItemNameToItem, skyblockItemToUrl } from '$lib/minecraft/inventory' + import { cleanId } from '$lib/utils' + import ListItemWithIcon from '$lib/ListItemWithIcon.svelte' + + export let data: { [category: string]: string[] } +</script> + +<Head title="Hypixel SkyBlock Leaderboards" /> +<Header /> + +<main> + <Toc categories={Object.keys(data)} /> + + {#each Object.entries(data) as [category, leaderboards]} + <section> + <Collapsible id={category}> + <ul> + {#each leaderboards as leaderboard} + {@const imageUrl = leaderboard.startsWith('collection_') + ? skyblockItemToUrl(leaderboard.slice(11)) + : null} + {#if imageUrl} + <ListItemWithIcon url={imageUrl}> + <a href="/leaderboards/{leaderboard}">{cleanId(leaderboard)}</a> + </ListItemWithIcon> + {:else} + <li><a href="/leaderboards/{leaderboard}">{cleanId(leaderboard)}</a></li> + {/if} + {/each} + </ul> + </Collapsible> + </section> + {/each} +</main> |