aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-02-15 21:58:20 +0000
committermat <github@matdoes.dev>2022-02-15 21:58:20 +0000
commitc060d60ba1d5f3ad9f37b48b50b694a2d19240d1 (patch)
tree23fb02b54c16c878675f47052eb4c2d5e6c7829c /src
parent235fac70c745973f0fe3f18ea900922fa4b199f8 (diff)
downloadskyblock-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.html2
-rw-r--r--src/lib/Head.svelte20
-rw-r--r--src/lib/Header.svelte36
-rw-r--r--src/lib/Username.svelte8
-rw-r--r--src/lib/api.ts8
-rw-r--r--src/lib/constants.ts11
-rw-r--r--src/lib/profile.ts57
-rw-r--r--src/lib/utils.ts37
-rw-r--r--src/routes/__layout.svelte6
-rw-r--r--src/routes/player/[player]/[profile].svelte32
-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 {