diff options
author | mat <github@matdoes.dev> | 2022-02-15 21:58:20 +0000 |
---|---|---|
committer | mat <github@matdoes.dev> | 2022-02-15 21:58:20 +0000 |
commit | c060d60ba1d5f3ad9f37b48b50b694a2d19240d1 (patch) | |
tree | 23fb02b54c16c878675f47052eb4c2d5e6c7829c /src | |
parent | 235fac70c745973f0fe3f18ea900922fa4b199f8 (diff) | |
download | skyblock-stats-c060d60ba1d5f3ad9f37b48b50b694a2d19240d1.tar.gz skyblock-stats-c060d60ba1d5f3ad9f37b48b50b694a2d19240d1.tar.bz2 skyblock-stats-c060d60ba1d5f3ad9f37b48b50b694a2d19240d1.zip |
start adding profile
Diffstat (limited to 'src')
-rw-r--r-- | src/app.html | 2 | ||||
-rw-r--r-- | src/lib/Head.svelte | 20 | ||||
-rw-r--r-- | src/lib/Header.svelte | 36 | ||||
-rw-r--r-- | src/lib/Username.svelte | 8 | ||||
-rw-r--r-- | src/lib/api.ts | 8 | ||||
-rw-r--r-- | src/lib/constants.ts | 11 | ||||
-rw-r--r-- | src/lib/profile.ts | 57 | ||||
-rw-r--r-- | src/lib/utils.ts | 37 | ||||
-rw-r--r-- | src/routes/__layout.svelte | 6 | ||||
-rw-r--r-- | src/routes/player/[player]/[profile].svelte | 32 | ||||
-rw-r--r-- | src/routes/player/[player]/index.svelte (renamed from src/routes/player/[player].svelte) | 94 |
11 files changed, 223 insertions, 88 deletions
diff --git a/src/app.html b/src/app.html index b0013f4..e0a73a9 100644 --- a/src/app.html +++ b/src/app.html @@ -9,6 +9,6 @@ %svelte.head% </head> <body> - <div>%svelte.body%</div> + %svelte.body% </body> </html> diff --git a/src/lib/Head.svelte b/src/lib/Head.svelte index d301f14..e8032db 100644 --- a/src/lib/Head.svelte +++ b/src/lib/Head.svelte @@ -1,17 +1,17 @@ <script lang="ts"> - /** The title that is shown at the top of the page and in search engines */ - export let title = 'SkyBlock Stats' - /** The description that is shown in search engines */ + /** The title that is shown at the top of the page and in search engines */ + export let title = 'SkyBlock Stats' + /** The description that is shown in search engines */ export let description = '' - /** The title that is shown in platforms like Discord */ + /** The title that is shown in platforms like Discord */ export let metaTitle = title - /** The description that is shown in platforms like Discord */ - export let metaDescription = description + /** The description that is shown in platforms like Discord */ + export let metaDescription = description </script> <svelte:head> - <title>{title}</title> - <meta name="description" content={description}> - <meta property="og:title" content={metaTitle}> - <meta property="og:description" content={metaDescription}> + <title>{title}</title> + <meta name="description" content={description} /> + <meta property="og:title" content={metaTitle} /> + <meta property="og:description" content={metaDescription} /> </svelte:head> diff --git a/src/lib/Header.svelte b/src/lib/Header.svelte index 27c7d09..a5ec702 100644 --- a/src/lib/Header.svelte +++ b/src/lib/Header.svelte @@ -21,7 +21,7 @@ }} > <input - class="enter-username-button" + class="enter-username-input" type="text" placeholder="Enter username" name="user-search" @@ -34,3 +34,37 @@ /> </form> </header> + +<style> + header { + background-color: var(--theme-background); + box-shadow: 0 0 1em rgba(0, 0, 0, 0.8); + padding: 0.5rem 10%; + } + + .user-form { + display: inline-block; + text-align: center; + font-size: 1.25rem; + /* center the forms */ + margin: 0 auto; + width: max-content; + } + + .enter-username-input { + box-shadow: none; + /* add a slight shadow on the form in the index page */ + max-width: calc(90vw - 8em); + } + + .back-arrow { + float: left; + transition: stroke 200ms; + stroke: var(--theme-darker-text); + margin-top: 0.4em; + margin-right: 1em; + } + .back-arrow:hover { + stroke: var(--theme-main-text); + } +</style> diff --git a/src/lib/Username.svelte b/src/lib/Username.svelte index 764721c..d415511 100644 --- a/src/lib/Username.svelte +++ b/src/lib/Username.svelte @@ -26,9 +26,11 @@ {:else if headType == '2d'} <Head2d {player} isPartOfUsername={true} /> {/if} - <span class="username-rank-prefix"> - {@html formattingCodeToHtml(player.rank.colored)} - </span> + {#if prefix} + <span class="username-rank-prefix"> + {@html formattingCodeToHtml(player.rank.colored)} + </span> + {/if} <span class="username" style="color: {player.rank.color}">{player.username}</span> </ConditionalLink> diff --git a/src/lib/api.ts b/src/lib/api.ts index 3c1d8ec..db6bf81 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,7 +1 @@ -const BASE_URL = 'https://skyblock-api.matdoes.dev/' - -export async function get(path: string) { - const resp = await fetch(BASE_URL + path) - return await resp.json() -} - +export const API_URL = 'https://skyblock-api.matdoes.dev/'
\ No newline at end of file diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 0000000..dc84994 --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,11 @@ +import { API_URL } from '$lib/api' + +export let constants: any = {} + +async function updateConstants() { + constants = await fetch(API_URL + 'constants').then(r => r.json()) + console.log('updated constants') +} + +updateConstants() +setInterval(updateConstants, 60 * 60 * 1000) // update every hour
\ No newline at end of file diff --git a/src/lib/profile.ts b/src/lib/profile.ts new file mode 100644 index 0000000..6388128 --- /dev/null +++ b/src/lib/profile.ts @@ -0,0 +1,57 @@ +import { constants } from './constants' +import { cleanId, millisecondsToTime } from './utils' + +/** + * Convert milliseconds since epoch into a string, but if it was within the + * past week then show the timeago + */ +function prettyTimestamp(ms: number) { + const isWithinPastWeek = Date.now() - ms < 1000 * 60 * 60 * 24 * 7 + const timeAsString = isWithinPastWeek ? (millisecondsToTime(Date.now() - ms) + ' ago') : (new Date(ms)).toUTCString() + return timeAsString +} + +export function generateMetaDescription(data) { + const result: string[] = [] + + result.push(`💾 Last save: ${prettyTimestamp(data.member.last_save * 1000)}`) + + result.push(`🚶 Profile created: ${prettyTimestamp(data.member.first_join * 1000)}`) + + result.push(`✨ Fairy souls: ${data.member.fairy_souls.total}/${constants.max_fairy_souls}`) + + if (data.profile.minion_count >= constants.max_minions) + result.push(`🤖 Minion count: ${data.profile.minion_count}`) + + let mostSignificantKillsStat = null + let mostSignificantDeathsStat = null + + for (const stat of data.member.stats) { + if ( + stat.category === 'kills' + && stat.rawName != 'kills' + && stat.value >= 200_000 + && stat.value > (mostSignificantKillsStat?.value ?? 0) + ) + mostSignificantKillsStat = stat + if ( + stat.category === 'deaths' + && stat.rawName != 'deaths' + && stat.value > 1_000_000 + && stat.value > (mostSignificantDeathsStat?.value ?? 0) + ) + mostSignificantDeathsStat = stat + } + + if (mostSignificantKillsStat) + result.push( + `⚔️ ${mostSignificantKillsStat.value.toLocaleString()} ${mostSignificantKillsStat.unit || cleanId(mostSignificantKillsStat.rawName).toLowerCase()}` + ) + + if (mostSignificantDeathsStat) + result.push( + `☠ ${mostSignificantDeathsStat.value.toLocaleString()} ${mostSignificantDeathsStat.unit || cleanId(mostSignificantDeathsStat.rawName).toLowerCase()}` + ) + + return result.join('\n') +}
\ No newline at end of file diff --git a/src/lib/utils.ts b/src/lib/utils.ts index e6f85ff..5d8ecc8 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -70,12 +70,14 @@ export function formattingCodeToHtml(formatted: string): string { export function removeFormattingCode(formatted: string): string { return formatted.replace(new RegExp(colorCodeCharacter + '.', 'g'), '') } -function moveStringToEnd(word: string, thing: string) { + +function moveToEndOfId(word: string, thing: string) { if (thing.startsWith(`${word}_`)) - thing = thing.substr(`${word}_`.length) + `_${word}` + thing = thing.slice(`${word}_`.length) + `_${word}` return thing } -function millisecondsToTime(totalMilliseconds: number) { + +export function millisecondsToTime(totalMilliseconds: number) { const totalSeconds = totalMilliseconds / 1000 const totalMinutes = totalSeconds / 60 const totalHours = totalMinutes / 60 @@ -98,29 +100,20 @@ function millisecondsToTime(totalMilliseconds: number) { else if (milliseconds == 1) stringUnits.push(`${milliseconds} millisecond`) return stringUnits.slice(0, 2).join(' and ') } -export function cleanNumber(number: number, unit?: string): string { - switch (unit) { - case 'time': - return millisecondsToTime(number) - case 'date': - return (new Date(number * 1000)).toUTCString() - } - return number.toLocaleString() + (unit ? (' ' + unit) : '') -} -export function clean(thing: string | number) { - if (typeof thing === 'number') { - return cleanNumber(thing) - } else { - for (const string of ['deaths', 'kills', 'collection', 'skill']) - thing = moveStringToEnd(string, thing) - return thing - .replace(/^./, thing[0].toUpperCase()) - .replace(/_/g, ' ') - } + +export function cleanId(id: string) { + for (const string of ['deaths', 'kills', 'collection', 'skill']) + id = moveToEndOfId(string, id) + + return id + .replace(/^./, id[0].toUpperCase()) + .replace(/_/g, ' ') } + 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] } + export function shuffle<T>(a: T[]): T[] { for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)) diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index d1fca30..2da6384 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -3,6 +3,6 @@ import '../app.css' </script> -<main> - <slot /> -</main> +<nav /> + +<slot /> diff --git a/src/routes/player/[player]/[profile].svelte b/src/routes/player/[player]/[profile].svelte new file mode 100644 index 0000000..c5276bc --- /dev/null +++ b/src/routes/player/[player]/[profile].svelte @@ -0,0 +1,32 @@ +<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 player: string = params.player + const profile: string = params.profile + const res = await fetch(`${API_URL}player/${player}/${profile}`).then(r => r.json()) + return { + props: { + data: res, + }, + } + } +</script> + +<script lang="ts"> + import Head from '$lib/Head.svelte' + import Header from '$lib/Header.svelte' + import Username from '$lib/Username.svelte' + import { generateMetaDescription } from '$lib/profile' + + export let data +</script> + +<Head + title="{data.member.username}'s SkyBlock profile ({data.member.profileName})" + description={generateMetaDescription(data)} + metaTitle={(data.member.rank.name ? `[${data.member.rank.name}] ` : '') + + `${data.member.username}\'s SkyBlock profile (${data.member.profileName})`} +/> +<Header backArrowHref="/player/{data.member.username}" /> diff --git a/src/routes/player/[player].svelte b/src/routes/player/[player]/index.svelte index 2cce8e7..73dfb0c 100644 --- a/src/routes/player/[player].svelte +++ b/src/routes/player/[player]/index.svelte @@ -1,24 +1,34 @@ <script lang="ts" context="module"> - import { get } from '$lib/api' import type { Load } from '@sveltejs/kit' + import { API_URL } from '$lib/api' + export const load: Load = async ({ params, fetch }) => { const player: string = params.player - // if (browser) alert('doing get') - const res = await fetch(`https://skyblock-api.matdoes.dev/player/${player}`).then(r => r.json()) - // const res = await get(`player/${player}`) + const res = await fetch(`${API_URL}player/${player}?customization=true`).then(r => r.json()) + + console.log('res', res) + + if (!res.player) { + return { fallthrough: true } as unknown + } + + if (res.player.username !== player) { + return { + redirect: `/player/${res.player.username}`, + status: 302, + } + } + return { - props: { - data: res, - }, + props: { data: res }, } } </script> <script lang="ts"> - import Head from '$lib/Head.svelte' - import Header from '$lib/Header.svelte' - import { browser } from '$app/env' import Username from '$lib/Username.svelte' + import Header from '$lib/Header.svelte' + import Head from '$lib/Head.svelte' export let data @@ -34,7 +44,6 @@ } } - // {%- set activeProfileOnline = getTime() - 60 < activeProfileLastSave -%} const isActiveProfileOnline = Date.now() / 1000 - 60 < activeProfileLastSave </script> @@ -60,36 +69,39 @@ {/if} </svelte:head> -<h1><Username player={data.player} headType="3d" />'s profiles</h1> - -<ul class="profile-list"> - {#each data.profiles as profile} - <li - class="profile-list-item" - class:profile-list-item-active={profile.uuid === activeProfile.uuid} - class:profile-list-item-online={profile.uuid === activeProfile.uuid && isActiveProfileOnline} - > - <a class="profile-name" href="/player/{data.player.username}/{profile.name}"> - {profile.name} - </a> - <span class="profile-members"> - {#if profile.members.length > 1} - {#each profile.members as player} - <span class="member"> - <Username - {player} - headType="2d" - hyperlinkToProfile={player.uuid != data.player.uuid} - /> - </span> - {/each} - {:else} - Solo - {/if} - </span> - </li> - {/each} -</ul> +<main> + <h1><Username player={data.player} headType="3d" />'s profiles</h1> + + <ul class="profile-list"> + {#each data.profiles as profile} + <li + class="profile-list-item" + class:profile-list-item-active={profile.uuid === activeProfile.uuid} + class:profile-list-item-online={profile.uuid === activeProfile.uuid && + isActiveProfileOnline} + > + <a class="profile-name" href="/player/{data.player.username}/{profile.name}"> + {profile.name} + </a> + <span class="profile-members"> + {#if profile.members.length > 1} + {#each profile.members as player} + <span class="member"> + <Username + {player} + headType="2d" + hyperlinkToProfile={player.uuid != data.player.uuid} + /> + </span> + {/each} + {:else} + Solo + {/if} + </span> + </li> + {/each} + </ul> +</main> <style> .profile-name { |