From 6e723aadf6de45a79b4ef64d288ea275628232c5 Mon Sep 17 00:00:00 2001 From: mat Date: Thu, 15 Dec 2022 14:59:56 -0600 Subject: start updating to sveltekit v1 --- src/lib/AuctionPriceScatterplot.svelte | 2 +- src/lib/BackgroundImage.svelte | 2 +- src/lib/Collapsible.svelte | 2 +- src/lib/layout/Loader.svelte | 2 +- src/lib/minecraft/inventory.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/lib') diff --git a/src/lib/AuctionPriceScatterplot.svelte b/src/lib/AuctionPriceScatterplot.svelte index da1aed2..17a09f1 100644 --- a/src/lib/AuctionPriceScatterplot.svelte +++ b/src/lib/AuctionPriceScatterplot.svelte @@ -1,5 +1,5 @@ -Mayor {toTitleCase(name)} +{#if url} + Mayor {toTitleCase(name)} +{:else} +
Unknown mayor
+{/if} diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts new file mode 100644 index 0000000..4596c1b --- /dev/null +++ b/src/routes/+page.server.ts @@ -0,0 +1,7 @@ +import type { ServerLoad } from '@sveltejs/kit' + +export const load = (({ locals }) => { + return { + loggedIn: locals.sid !== undefined, + } +}) satisfies ServerLoad diff --git a/src/routes/+page.ts b/src/routes/+page.ts deleted file mode 100644 index cd45f69..0000000 --- a/src/routes/+page.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { PageData } from './$types' - -export const load = (({ session }) => { - return { - loggedIn: session.sid !== undefined, - } -}) satisfies PageData diff --git a/src/routes/[player=username]/+page.ts b/src/routes/[player=username]/+page.ts index c846929..289cd48 100644 --- a/src/routes/[player=username]/+page.ts +++ b/src/routes/[player=username]/+page.ts @@ -1,11 +1,6 @@ +import { redirect } from '@sveltejs/kit' import type { PageLoad } from './$types' - -export const get = (({ params }) => { - return { - status: 303, - headers: { - location: `/player/${params.player}` - } - } +export const load = (({ params }) => { + throw redirect(303, `/player/${params.player}`) }) satisfies PageLoad \ No newline at end of file diff --git a/src/routes/auctionprices/+page.ts b/src/routes/auctionprices/+page.ts index 8166a3c..31af8e3 100644 --- a/src/routes/auctionprices/+page.ts +++ b/src/routes/auctionprices/+page.ts @@ -1,4 +1,4 @@ -import type { PageData } from './$types' +import type { PageLoad } from './$types' import { fetchApi } from '$lib/api' export const load = (async ({ fetch }) => { @@ -10,4 +10,4 @@ export const load = (async ({ fetch }) => { prices, items, } -}) satisfies PageData +}) satisfies PageLoad diff --git a/src/routes/election/+page.svelte b/src/routes/election/+page.svelte index 1754655..dc4719e 100644 --- a/src/routes/election/+page.svelte +++ b/src/routes/election/+page.svelte @@ -1,20 +1,3 @@ - - - + + +
+ +
+ {#if session && session._id} + + {/if} +

Customize Profile

+ + +

+ {#if error} + {error} + {:else if loading} + Loading... + {/if} +

+ + View profile +

+ + +

+

+ + +

+ {#if isDonator} + + + + +

Windows: win+.

+

Mobile: Emoji keyboard

+
+ +
+ {/if} +

Background

+
+ {#each backgroundNames as thisBackgroundName} + (backgroundName = thisBackgroundName)} + on:keypress={e => { + if (e.key === 'Enter') { + backgroundName = thisBackgroundName + } + }} + /> + {/each} +
+
+ + diff --git a/src/routes/profile/+page.ts b/src/routes/profile/+page.ts new file mode 100644 index 0000000..cdd2a93 --- /dev/null +++ b/src/routes/profile/+page.ts @@ -0,0 +1,44 @@ +import { fetchApi } from '$lib/api' +import type { AccountSchema, SessionSchema } from '$lib/APITypes' +import donators from '../../_donators.json' +import admins from '../../_admins.json' +import type { PageLoad } from './$types' +import { redirect } from '@sveltejs/kit' + +export const load = (async ({ fetch, data }) => { + const sessionResponse: { session: SessionSchema | null; account: AccountSchema | null } | null = + await fetchApi(`accounts/session`, fetch, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + uuid: data.sid, + }), + }).then(r => r.json()) + + const playerResponse = sessionResponse?.account + ? await fetchApi(`player/${sessionResponse.account.minecraftUuid}`, fetch).then(r => r.json()) + : null + + // redirect to /login if the user is not logged in + if ( + !sessionResponse || + !sessionResponse.account || + !sessionResponse.session || + !playerResponse.player + ) { + throw redirect(303, '/login') + } + + const isDonator = + donators.find(d => d?.uuid === sessionResponse.account?.minecraftUuid) !== undefined + const isAdmin = admins.find(a => a === sessionResponse.account?.minecraftUuid) !== undefined + + return { + session: sessionResponse.session, + account: sessionResponse.account, + player: playerResponse, + isDonator: isDonator || isAdmin, + } +}) as PageLoad diff --git a/src/routes/profile/index.svelte b/src/routes/profile/index.svelte deleted file mode 100644 index 0d5ad04..0000000 --- a/src/routes/profile/index.svelte +++ /dev/null @@ -1,219 +0,0 @@ - - - - - -
- -
- {#if session && session._id} - - {/if} -

Customize Profile

- - -

- {#if error} - {error} - {:else if loading} - Loading... - {/if} -

- - View profile -

- - -

-

- - -

- {#if isDonator} - - - - -

Windows: win+.

-

Mobile: Emoji keyboard

-
- -
- {/if} -

Background

-
- {#each backgroundNames as thisBackgroundName} - (backgroundName = thisBackgroundName)} - /> - {/each} -
-
- - diff --git a/src/routes/profile/update.ts b/src/routes/profile/update.ts deleted file mode 100644 index 168cba8..0000000 --- a/src/routes/profile/update.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { fetchApi } from '$lib/api' -import type { AccountSchema, SessionSchema } from '$lib/APITypes' -import type { RequestHandler } from '@sveltejs/kit' -import backgroundFileNames from '../../_backgrounds.json' -import donators from '../../_donators.json' -import admins from '../../_admins.json' -import type { JSONValue } from '@sveltejs/kit/types/internal' -import env from '$lib/env' - -const emojiRegex = /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])$/ - -function isValidEmoji(emoji: string) { - const match = emojiRegex.exec(emoji) - return match && match[0] === emoji && match.index === 0 -} - - -export const patch: RequestHandler = async ({ request, locals, platform }) => { - if (locals.sid === undefined) { - return { - body: { ok: false, error: 'You are not logged in.' }, - status: 401, - } - } - const key = env(platform).SKYBLOCK_STATS_API_KEY - if (!key) { - return { - body: { ok: false, error: 'The SKYBLOCK_STATS_API_KEY environment variable is not set.' }, - status: 500, - } - } - const data = await request.json() - - const sessionResponse: { session: SessionSchema | null, account: AccountSchema | null } = await fetchApi(`accounts/session`, fetch, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - uuid: locals.sid, - }), - }).then(r => r.json()) - if (!sessionResponse.session || !sessionResponse.account?.minecraftUuid) - return { - body: { ok: false, error: 'Invalid session.' }, - status: 401, - } - - const backgroundName = data.backgroundName - const pack = data.pack - const blurBackground = data.blurBackground - const emoji = data.emoji - - const isDonator = donators.find(d => d.uuid === sessionResponse.account?.minecraftUuid) !== undefined - const isAdmin = admins.includes(sessionResponse.account?.minecraftUuid) - - if (typeof backgroundName !== 'undefined' && typeof backgroundName !== 'string') { - return { - body: { ok: false, error: 'Invalid background.' }, - status: 400, - } - } - if (typeof pack !== 'string') { - return { - body: { ok: false, error: 'Invalid pack.' }, - status: 400, - } - } - if (typeof blurBackground !== 'boolean') { - return { - body: { ok: false, error: 'Invalid blurBackground.' }, - status: 400, - } - } - if (typeof emoji !== 'undefined' && typeof emoji !== 'string') { - return { - body: { ok: false, error: 'Invalid emoji.' }, - status: 400, - } - } - - // prevent people from putting non-existent backgrounds - if (backgroundName && !backgroundFileNames.includes(backgroundName)) - return { - body: { ok: false, error: 'Invalid background.' }, - status: 400, - } - const backgroundUrl = backgroundName ? `/backgrounds/${backgroundName}` : undefined - - if (emoji) { - if (!isDonator && !isAdmin) - return { - body: { ok: false, error: 'You are not allowed to use emojis.' }, - status: 401, - } - if (!isValidEmoji(emoji)) - return { - body: { ok: false, error: 'Invalid emoji.' }, - status: 400, - } - } - - const updatedAccount: AccountSchema = { - discordId: sessionResponse.account.discordId, - customization: { - backgroundUrl, - pack, - blurBackground, - emoji, - }, - } - - const response = await fetchApi(`accounts/update`, fetch, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - key: key - }, - body: JSON.stringify(updatedAccount), - }).then(r => r.json()) - - - return { - body: { ok: true } as JSONValue, - } -} \ No newline at end of file diff --git a/src/routes/profile/update/+server.ts b/src/routes/profile/update/+server.ts new file mode 100644 index 0000000..7190fb8 --- /dev/null +++ b/src/routes/profile/update/+server.ts @@ -0,0 +1,95 @@ +import { fetchApi } from '$lib/api' +import type { AccountSchema, SessionSchema } from '$lib/APITypes' +import backgroundFileNames from '../../../_backgrounds.json' +import donators from '../../../_donators.json' +import admins from '../../../_admins.json' +import env from '$lib/env' +import type { PageServerLoad } from '../$types' +import { error, json } from '@sveltejs/kit' + +const emojiRegex = /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])$/ + +function isValidEmoji(emoji: string) { + const match = emojiRegex.exec(emoji) + return match && match[0] === emoji && match.index === 0 +} + + +export const PATCH = (async ({ request, locals, platform }) => { + if (locals.sid === undefined) { + throw error(401, 'You are not logged in.') + } + const key = env(platform).SKYBLOCK_STATS_API_KEY + if (!key) { + throw error(500, 'The SKYBLOCK_STATS_API_KEY environment variable is not set.') + } + const data = await request.json() + + const sessionResponse: { session: SessionSchema | null, account: AccountSchema | null } = await fetchApi(`accounts/session`, fetch, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + uuid: locals.sid, + }), + }).then(r => r.json()) + if (!sessionResponse.session || !sessionResponse.account?.minecraftUuid) + throw error(401, 'Invalid session.') + + const backgroundName = data.backgroundName + const pack = data.pack + const blurBackground = data.blurBackground + const emoji = data.emoji + + const isDonator = donators.find(d => d.uuid === sessionResponse.account?.minecraftUuid) !== undefined + const isAdmin = admins.includes(sessionResponse.account?.minecraftUuid) + + if (typeof backgroundName !== 'undefined' && typeof backgroundName !== 'string') { + throw error(400, 'Invalid background.') + } + if (typeof pack !== 'string') { + throw error(400, 'Invalid pack.') + } + if (typeof blurBackground !== 'boolean') { + throw error(400, 'Invalid blurBackground.') + } + if (typeof emoji !== 'undefined' && typeof emoji !== 'string') { + throw error(400, 'Invalid emoji.') + } + + // prevent people from putting non-existent backgrounds + if (backgroundName && !backgroundFileNames.includes(backgroundName)) + throw error(400, 'Invalid background.') + const backgroundUrl = backgroundName ? `/backgrounds/${backgroundName}` : undefined + + if (emoji) { + if (!isDonator && !isAdmin) + throw error(401, 'You are not allowed to use emojis.') + if (!isValidEmoji(emoji)) + throw error(400, 'Invalid emoji.') + } + + const updatedAccount: AccountSchema = { + discordId: sessionResponse.account.discordId, + customization: { + backgroundUrl, + pack, + blurBackground, + emoji, + }, + } + + const response = await fetchApi(`accounts/update`, fetch, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + key: key + }, + body: JSON.stringify(updatedAccount), + }).then(r => r.json()) + console.log(response) + + + return json({ ok: true }) +}) satisfies PageServerLoad \ No newline at end of file diff --git a/src/routes/verify/+page.server.ts b/src/routes/verify/+page.server.ts index 3321164..bd3ea7f 100644 --- a/src/routes/verify/+page.server.ts +++ b/src/routes/verify/+page.server.ts @@ -1,75 +1,75 @@ import { fetchApi } from '$lib/api' import type { AccountSchema, CleanUser, SessionSchema } from '$lib/APITypes' -import type { RequestHandler } from '@sveltejs/kit' +import { redirect, type RequestHandler, type ServerLoad } from '@sveltejs/kit' import env from '$lib/env' +import type { Actions } from './$types' -function redirect(status: number, location: string) { - return { - status, - headers: { - location, - }, - } -} +export const actions: Actions = { + default: async ({ platform, locals, request }) => { + const key = env(platform).SKYBLOCK_STATS_API_KEY + if (!key) { + throw redirect(303, `/verify?error=NO_KEY`) + } + if (locals.sid === undefined) { + throw redirect(303, '/login') + } -export const post: RequestHandler = async ({ request, locals, platform }) => { - const key = env(platform).SKYBLOCK_STATS_API_KEY - if (!key) { - return redirect(303, `/verify?error=NO_KEY`) - } - if (locals.sid === undefined) { - return redirect(303, '/login') - } + const form = await request.formData() - const form = await request.formData() + // username or uuid + const playerIdentifier = form.get('ign') + if (!playerIdentifier) { + throw redirect(303, `/verify?error=NO_IGN`) + } - // username or uuid - const playerIdentifier = form.get('ign') - if (!playerIdentifier) { - return redirect(303, `/verify?error=NO_IGN`) - } + const playerResponse: CleanUser = await fetchApi(`player/${playerIdentifier}`, fetch).then(res => res.json()) + const sessionResponse: { session: SessionSchema | null, account: AccountSchema | null } = await fetchApi(`accounts/session`, fetch, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + uuid: locals.sid, + }), + }).then(r => r.json()) - const playerResponse: CleanUser = await fetchApi(`player/${playerIdentifier}`, fetch).then(res => res.json()) - const sessionResponse: { session: SessionSchema | null, account: AccountSchema | null } = await fetchApi(`accounts/session`, fetch, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - uuid: locals.sid, - }), - }).then(r => r.json()) + if (!sessionResponse.session) + throw redirect(303, '/login') - if (!sessionResponse.session) - return redirect(303, '/login') + const hypixelDiscordName = playerResponse.player?.socials.discord - const hypixelDiscordName = playerResponse.player?.socials.discord + if (!hypixelDiscordName) + throw redirect(303, `/verify?error=NOT_LINKED`) - if (!hypixelDiscordName) - return redirect(303, `/verify?error=NOT_LINKED`) + const discordUser = sessionResponse.session.discord_user + const actualDiscordName = discordUser.name + // some people link themselves as # instead of # + const actualDiscordIdDiscrim = `${discordUser.id}#${discordUser.name.split('#')[1]}` - const discordUser = sessionResponse.session.discord_user - const actualDiscordName = discordUser.name - // some people link themselves as # instead of # - const actualDiscordIdDiscrim = `${discordUser.id}#${discordUser.name.split('#')[1]}` + if (!(hypixelDiscordName === actualDiscordName || hypixelDiscordName === actualDiscordIdDiscrim)) + throw redirect(303, `/verify?error=WRONG_NAME¤t=${encodeURIComponent(hypixelDiscordName)}&correct=${encodeURIComponent(actualDiscordName)}`) - if (!(hypixelDiscordName === actualDiscordName || hypixelDiscordName === actualDiscordIdDiscrim)) - return redirect(303, `/verify?error=WRONG_NAME¤t=${encodeURIComponent(hypixelDiscordName)}&correct=${encodeURIComponent(actualDiscordName)}`) + const updatedAccount: AccountSchema = { + discordId: sessionResponse.session.discord_user.id, + minecraftUuid: playerResponse.player?.uuid + } - const updatedAccount: AccountSchema = { - discordId: sessionResponse.session.discord_user.id, - minecraftUuid: playerResponse.player?.uuid - } + await fetchApi(`accounts/update`, fetch, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + key: key + }, + body: JSON.stringify(updatedAccount), + }).then(r => r.json()) - await fetchApi(`accounts/update`, fetch, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - key: key - }, - body: JSON.stringify(updatedAccount), - }).then(r => r.json()) + throw redirect(303, '/profile') + } +} - return redirect(303, '/profile') -} \ No newline at end of file +export const load = (({ locals }) => { + return { + sid: locals.sid + } +}) satisfies ServerLoad diff --git a/src/routes/verify/+page.svelte b/src/routes/verify/+page.svelte index 20de403..4edc50d 100644 --- a/src/routes/verify/+page.svelte +++ b/src/routes/verify/+page.svelte @@ -1,27 +1,14 @@ - - - - -

Upgrades

-
-

Purchased: {bagData.upgrades.purchased}

-

Coins spent: {bagData.upgrades.coinsSpent.toLocaleString()}

-

Extra slots: {bagData.upgrades.extraSlots}

-
- -

Powers

- {#if bagData.powers.selected} -

- Selected: {cleanId(bagData.powers.selected)} -

- {/if} -
    - {#each bagData.powers.list as power} -
  • - {#if bagData.powers.selected === power} - {cleanId(power)} - {:else} - {cleanId(power)} - {/if} -
  • - {/each} -
- -
- {#each bagData.tuningTemplates as template, template_index} -
-

Template #{template_index + 1}

-
- {#each Object.entries(template) as [statName, statValue]} -

{cleanId(statName)}: {statValue}

- {/each} -
-
- {/each} -
-
- - diff --git a/src/lib/sections/Achievements.svelte b/src/lib/sections/Achievements.svelte deleted file mode 100644 index 92ba468..0000000 --- a/src/lib/sections/Achievements.svelte +++ /dev/null @@ -1,87 +0,0 @@ - - -{#if data.member.achievements} -

- Tiered - - ({data.member.achievements.tiered.filter(a => a.amount).length}/{data.member.achievements - .tiered.length}) - -

-
    - {#each data.member.achievements.tiered as achievement} -
  • - - - {achievement.description} - - - - {achievement.name}: {#if achievement.next} - {achievement.amount}/{achievement.next} - {:else} - {achievement.amount} - {/if} - - -
  • - {/each} -
- -

- Challenge - - ({data.member.achievements.challenge.filter(a => a.unlocked).length}/{data.member.achievements - .challenge.length}) - -

-
    - {#each data.member.achievements.challenge as achievement} -
  • - - - {achievement.description} - - - {#if achievement.unlocked} - - {achievement.name} - - {:else} - - {achievement.name} - - {/if} - -
  • - {/each} -
-{/if} - - diff --git a/src/lib/sections/Armor.svelte b/src/lib/sections/Armor.svelte deleted file mode 100644 index 285a898..0000000 --- a/src/lib/sections/Armor.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -{#if data.member.inventories} - - - -{/if} diff --git a/src/lib/sections/Auctions.svelte b/src/lib/sections/Auctions.svelte deleted file mode 100644 index 50d47b6..0000000 --- a/src/lib/sections/Auctions.svelte +++ /dev/null @@ -1,109 +0,0 @@ - - - -
-
    - {#each stats.sort((a, b) => b.value - a.value) as stat} -
  • - {cleanId(stat.categorizedName)}: - - {#if stat.unit === 'time'} - {millisecondsToTime(stat.value)} - {:else} - {stat.value.toLocaleString()} - {/if} - -
  • - {/each} -
- -
- {#if loading || auctions.length > 0} -

Auctions sold

- {/if} - {#if auctions.length > 0} -
- {#each auctions as auction} - {#if !onlyThisProfile || auction.sellerProfileUuid == data.profile.uuid} - - {/if} - {/each} -
- {#if !loading && page != totalPages} - - {/if} - {/if} - {#if loading} - Loading... - {/if} -
-
- - diff --git a/src/lib/sections/Bank.svelte b/src/lib/sections/Bank.svelte deleted file mode 100644 index 9bd2b8f..0000000 --- a/src/lib/sections/Bank.svelte +++ /dev/null @@ -1,89 +0,0 @@ - - -{#if data.profile.bank} -
-

- Current bank balance: - - {data.profile.bank.balance?.toLocaleString()} coins - -

-

- Purse: - - {data.member.purse.toLocaleString()} coins - -

-
- {#each data.profile.bank.history as transaction} -
- - - {@html formattingCodeToHtml(transaction.name)} - - - - - New balance: {transaction.total.toLocaleString()} - - 0} - class:difference-negative={transaction.change < 0} - > - {transaction.change > 0 - ? '+' + transaction.change.toLocaleString() - : transaction.change.toLocaleString()} - - - - - {millisecondsToTime(Date.now() - transaction.timestamp)} ago - -
- {/each} -{/if} - - diff --git a/src/lib/sections/Claimed.svelte b/src/lib/sections/Claimed.svelte deleted file mode 100644 index 8f44796..0000000 --- a/src/lib/sections/Claimed.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - -{#if data.member.claimed && data.member.claimed.length > 0} -
    - {#each data.member.claimed as claimed} -
  • - {toTitleCase(cleanId(claimed.id))} - - {millisecondsToTime(Date.now() - claimed.timestamp)} ago - -
  • - {/each} -
-{/if} - - diff --git a/src/lib/sections/Collections.svelte b/src/lib/sections/Collections.svelte deleted file mode 100644 index 4baa660..0000000 --- a/src/lib/sections/Collections.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - -{#if data.member.collections} - {#each Object.keys(categories).sort() as categoryName} - {@const collections = categories[categoryName]} -

{cleanId(categoryName)}

-
    - {#each collections as collection} - - - - Amount: {collection.amount.toLocaleString()} - - {cleanId(collection.name)} - {collection.level} - - - {/each} -
- {/each} -{/if} - - diff --git a/src/lib/sections/Coop.svelte b/src/lib/sections/Coop.svelte deleted file mode 100644 index ff858f1..0000000 --- a/src/lib/sections/Coop.svelte +++ /dev/null @@ -1,79 +0,0 @@ - - -{#if data.member.coopInvitation} -
- {#if isProfileCreator} -

Created co-op

- {:else} -

- Invited by {#if data.member.coopInvitation.invitedBy} - - {:else} - Unknown player - {/if} -

- {/if} -

- {isProfileCreator ? 'Began creation' : 'Invited'}: - - {millisecondsToTime(Date.now() - data.member.coopInvitation.invitedTimestamp)} ago - -

- {#if data.member.coopInvitation.acceptedTimestamp} -

- {isProfileCreator ? 'Finished creation' : 'Accepted invite'}: - - after - {millisecondsToTime( - data.member.coopInvitation.acceptedTimestamp - - data.member.coopInvitation.invitedTimestamp - )} - - -

- {/if} -
-

Members

- {#each data.profile.members.filter(m => !m.left) as player} - - - - {/each} - {#if data.profile.members.filter(m => m.left).length > 0} -

Former members

- {#each data.profile.members.filter(m => m.left) as player} - - - - {/each} - {/if} -{/if} - - diff --git a/src/lib/sections/Essence.svelte b/src/lib/sections/Essence.svelte deleted file mode 100644 index 244dbcd..0000000 --- a/src/lib/sections/Essence.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -{#if data.member.essence.types.length > 0} -
    - {#each data.member.essence.types as essenceType} -
  • - {toTitleCase(cleanId(essenceType.id))}: - {essenceType.amount.toLocaleString()} -
  • - {/each} -
-{/if} - - diff --git a/src/lib/sections/FarmingContests.svelte b/src/lib/sections/FarmingContests.svelte deleted file mode 100644 index 8eef53d..0000000 --- a/src/lib/sections/FarmingContests.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - -
-

Talked to Jacob:

-
-
- {#each data.member.farmingContests.list as farmingContest} -
-

- {new Date( - skyblockTime(farmingContest.year, farmingContest.month, farmingContest.day) - ).toUTCString()} -

-
    - {#each farmingContest.crops as crop} - - {crop.amount.toLocaleString()} collected - {#if crop.position} - - (#{crop.position}/{crop.participants}) - - {/if} - - {/each} -
-
- {/each} -
- - diff --git a/src/lib/sections/Harp.svelte b/src/lib/sections/Harp.svelte deleted file mode 100644 index 6a5c9cc..0000000 --- a/src/lib/sections/Harp.svelte +++ /dev/null @@ -1,72 +0,0 @@ - - -
-

Claimed Melody's hair:

- {#if data.member.harp.selected} -

- Selected song: - {toTitleCase(cleanId(data.member.harp.selected.id))} - - {millisecondsToTime(Date.now() - data.member.harp.selected.timestamp)} ago - -

- {/if} -
-
- {#each data.member.harp.songs as song} -
-

{toTitleCase(cleanId(song.id))}

-
- {#if song.completions} -

Completions: {song.completions}

- {/if} - {#if song.perfectCompletions} -

Perfect completions: {song.perfectCompletions}

- {:else} -

Progress: {Math.floor(song.progress * 100)}%

- {/if} -
-
- {/each} -
- - diff --git a/src/lib/sections/Infobox.svelte b/src/lib/sections/Infobox.svelte deleted file mode 100644 index f8d2889..0000000 --- a/src/lib/sections/Infobox.svelte +++ /dev/null @@ -1,83 +0,0 @@ - - -
-
-

- ({data.member.left - ? 'Removed' - : data.member.profileName}) -

- {#each generateInfobox(data) as item} - - {#if item.includes('Fairy souls')} -

- {:else} -

- {/if} - {/each} -
-
-

Player UUID:

- {data.member.uuid} -

Profile UUID:

- {data.profile.uuid} -
-
- - diff --git a/src/lib/sections/Inventories.svelte b/src/lib/sections/Inventories.svelte deleted file mode 100644 index 1dd7d28..0000000 --- a/src/lib/sections/Inventories.svelte +++ /dev/null @@ -1,105 +0,0 @@ - - -{#if displayingInventories.length > 1} -
- {#each displayingInventories as inventoryName} - - {/each} -
-{/if} -{#if data.member.inventories} - {#each displayingInventories as inventoryName} - {#if inventoryName === selectedInventoryName} - - - - {#if inventoryName == 'accessory_bag'} - - {/if} - {/if} - {/each} -{/if} - - diff --git a/src/lib/sections/Leaderboards.svelte b/src/lib/sections/Leaderboards.svelte deleted file mode 100644 index 817f59a..0000000 --- a/src/lib/sections/Leaderboards.svelte +++ /dev/null @@ -1,46 +0,0 @@ - - -{#await fetchApi(`player/${data.member.uuid}/${data.profile.uuid}/leaderboards`, fetch).then( r => r.json() )} - Loading... -{:then leaderboards} - {#if leaderboards.length > 0} - - {:else} -

This player isn't in any leaderboards.

- {/if} -{/await} - - diff --git a/src/lib/sections/Minions.svelte b/src/lib/sections/Minions.svelte deleted file mode 100644 index 856d8f0..0000000 --- a/src/lib/sections/Minions.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - -

- Unique minions: - - {data.profile.minionCount}/{data.profile.maxUniqueMinions} - -

- - {#each data.profile.minions as minion} - - - {#each minion.levels as unlocked, i} - - {/each} - - {/each} -
{cleanId(minion.name)} - {toRomanNumerals(i + 1)} -
- - diff --git a/src/lib/sections/Pets.svelte b/src/lib/sections/Pets.svelte deleted file mode 100644 index 7f660c4..0000000 --- a/src/lib/sections/Pets.svelte +++ /dev/null @@ -1,79 +0,0 @@ - - -{#if data.member.zones} -

- Pets acquired: - - {petsAcquiredCount}/{totalPetsCount} - -

-
- {#each data.member.pets.list as pet} -
-

{cleanId(pet.id.toLowerCase())}

-

Level: {pet.level.toLocaleString()}

-

Tier: {toTitleCase(pet.tier)}

- {#if pet.item} -

Item: {pet.item.display.name}

- {/if} -
- {/each} -
- {#if data.member.pets.missingIds.length > 0} -

Missing

-
    - {#each data.member.pets.missingIds as petId} -
  • {toTitleCase(cleanId(petId.toLowerCase()))}
  • - {/each} -
- {/if} -{/if} - - diff --git a/src/lib/sections/Skills.svelte b/src/lib/sections/Skills.svelte deleted file mode 100644 index 8fc5aaf..0000000 --- a/src/lib/sections/Skills.svelte +++ /dev/null @@ -1,87 +0,0 @@ - - -{#if !data.member.skills.apiEnabled} -

- Skills API is disabled for this profile, so the values shown may be inaccurate. -

-{/if} -
    - {#each data.member.skills.list as skill} -
  • - - - {#if skill.levelXpRequired !== null} - {Math.round((skill.levelXp / skill.levelXpRequired) * 100)}% to next level, {Math.round( - skill.levelXp - ).toLocaleString()}/{formatNumber(skill.levelXpRequired, 3)} xp - {:else} - {Math.round(skill.levelXp).toLocaleString()} extra xp - {/if} - - - {cleanId(skill.id)} - - {skill.level} - - - -
  • - {/each} -
- - diff --git a/src/lib/sections/Slayers.svelte b/src/lib/sections/Slayers.svelte deleted file mode 100644 index 40fa67d..0000000 --- a/src/lib/sections/Slayers.svelte +++ /dev/null @@ -1,74 +0,0 @@ - - -{#if data.member.slayers} -
-

Xp: {data.member.slayers.xp}

-

Kills: {data.member.slayers.kills}

-
-
- {#each data.member.slayers.bosses as slayer} -
-

{slayer.name ? cleanId(slayer.name) : cleanId(slayer.rawName)}

-
-

Xp: {slayer.xp.toLocaleString()}

-

Level: {slayer.level}

-
- - - {#each slayer.tiers as tier} - - {/each} - - - {#each slayer.tiers as tier} - - {/each} - -
Tier {toRomanNumerals(tier.tier)}
- {tier.kills.toLocaleString()} -
-
- {/each} -
-{/if} - - diff --git a/src/lib/sections/StatList.svelte b/src/lib/sections/StatList.svelte deleted file mode 100644 index 38604d7..0000000 --- a/src/lib/sections/StatList.svelte +++ /dev/null @@ -1,48 +0,0 @@ - - - -
    - {#each stats.sort((a, b) => b.value - a.value) as stat} -
  • - {cleanId(stat.categorizedName)}: - - {#if stat.unit === 'time'} - {millisecondsToTime(stat.value)} - {:else} - {stat.value.toLocaleString()} - {/if} - -
  • - {/each} -
- - diff --git a/src/lib/sections/Zones.svelte b/src/lib/sections/Zones.svelte deleted file mode 100644 index f7e993b..0000000 --- a/src/lib/sections/Zones.svelte +++ /dev/null @@ -1,42 +0,0 @@ - - -{#if data.member.zones} -

- Zones visited: - - {zonesVisitedCount}/{data.member.zones.length} - -

-
    - {#each data.member.zones.filter(z => z.visited) as zone} -
  • {cleanId(zone.name)}
  • - {/each} - {#each data.member.zones.filter(z => !z.visited) as zone} -
  • {cleanId(zone.name)}
  • - {/each} -
-{/if} - - diff --git a/src/routes/election/+page.svelte b/src/routes/election/+page.svelte index dc4719e..54ac668 100644 --- a/src/routes/election/+page.svelte +++ b/src/routes/election/+page.svelte @@ -4,7 +4,7 @@ import { colorCodes, formattingCodeToHtml, millisecondsToTime, skyblockTime } from '$lib/utils' import type { ElectionData } from '$lib/APITypes' import { onDestroy, onMount } from 'svelte' - import MayorSkin from '$lib/MayorSkin.svelte' + import MayorSkin from '../../lib/MayorSkin.svelte' import { invalidate } from '$app/navigation' import { browser } from '$app/environment' diff --git a/src/routes/player/[player]/[profile]/+page.svelte b/src/routes/player/[player]/[profile]/+page.svelte index 247619d..8a3adbb 100644 --- a/src/routes/player/[player]/[profile]/+page.svelte +++ b/src/routes/player/[player]/[profile]/+page.svelte @@ -1,31 +1,31 @@ + + +

Upgrades

+
+

Purchased: {bagData.upgrades.purchased}

+

Coins spent: {bagData.upgrades.coinsSpent.toLocaleString()}

+

Extra slots: {bagData.upgrades.extraSlots}

+
+ +

Powers

+ {#if bagData.powers.selected} +

+ Selected: {cleanId(bagData.powers.selected)} +

+ {/if} +
    + {#each bagData.powers.list as power} +
  • + {#if bagData.powers.selected === power} + {cleanId(power)} + {:else} + {cleanId(power)} + {/if} +
  • + {/each} +
+ +
+ {#each bagData.tuningTemplates as template, template_index} +
+

Template #{template_index + 1}

+
+ {#each Object.entries(template) as [statName, statValue]} +

{cleanId(statName)}: {statValue}

+ {/each} +
+
+ {/each} +
+
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Achievements.svelte b/src/routes/player/[player]/[profile]/sections/Achievements.svelte new file mode 100644 index 0000000..92ba468 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Achievements.svelte @@ -0,0 +1,87 @@ + + +{#if data.member.achievements} +

+ Tiered + + ({data.member.achievements.tiered.filter(a => a.amount).length}/{data.member.achievements + .tiered.length}) + +

+
    + {#each data.member.achievements.tiered as achievement} +
  • + + + {achievement.description} + + + + {achievement.name}: {#if achievement.next} + {achievement.amount}/{achievement.next} + {:else} + {achievement.amount} + {/if} + + +
  • + {/each} +
+ +

+ Challenge + + ({data.member.achievements.challenge.filter(a => a.unlocked).length}/{data.member.achievements + .challenge.length}) + +

+
    + {#each data.member.achievements.challenge as achievement} +
  • + + + {achievement.description} + + + {#if achievement.unlocked} + + {achievement.name} + + {:else} + + {achievement.name} + + {/if} + +
  • + {/each} +
+{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Armor.svelte b/src/routes/player/[player]/[profile]/sections/Armor.svelte new file mode 100644 index 0000000..285a898 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Armor.svelte @@ -0,0 +1,14 @@ + + +{#if data.member.inventories} + + + +{/if} diff --git a/src/routes/player/[player]/[profile]/sections/Auctions.svelte b/src/routes/player/[player]/[profile]/sections/Auctions.svelte new file mode 100644 index 0000000..50d47b6 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Auctions.svelte @@ -0,0 +1,109 @@ + + + +
+
    + {#each stats.sort((a, b) => b.value - a.value) as stat} +
  • + {cleanId(stat.categorizedName)}: + + {#if stat.unit === 'time'} + {millisecondsToTime(stat.value)} + {:else} + {stat.value.toLocaleString()} + {/if} + +
  • + {/each} +
+ +
+ {#if loading || auctions.length > 0} +

Auctions sold

+ {/if} + {#if auctions.length > 0} +
+ {#each auctions as auction} + {#if !onlyThisProfile || auction.sellerProfileUuid == data.profile.uuid} + + {/if} + {/each} +
+ {#if !loading && page != totalPages} + + {/if} + {/if} + {#if loading} + Loading... + {/if} +
+
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Bank.svelte b/src/routes/player/[player]/[profile]/sections/Bank.svelte new file mode 100644 index 0000000..9bd2b8f --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Bank.svelte @@ -0,0 +1,89 @@ + + +{#if data.profile.bank} +
+

+ Current bank balance: + + {data.profile.bank.balance?.toLocaleString()} coins + +

+

+ Purse: + + {data.member.purse.toLocaleString()} coins + +

+
+ {#each data.profile.bank.history as transaction} +
+ + + {@html formattingCodeToHtml(transaction.name)} + + + + + New balance: {transaction.total.toLocaleString()} + + 0} + class:difference-negative={transaction.change < 0} + > + {transaction.change > 0 + ? '+' + transaction.change.toLocaleString() + : transaction.change.toLocaleString()} + + + + + {millisecondsToTime(Date.now() - transaction.timestamp)} ago + +
+ {/each} +{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Claimed.svelte b/src/routes/player/[player]/[profile]/sections/Claimed.svelte new file mode 100644 index 0000000..8f44796 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Claimed.svelte @@ -0,0 +1,33 @@ + + +{#if data.member.claimed && data.member.claimed.length > 0} +
    + {#each data.member.claimed as claimed} +
  • + {toTitleCase(cleanId(claimed.id))} + + {millisecondsToTime(Date.now() - claimed.timestamp)} ago + +
  • + {/each} +
+{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Collections.svelte b/src/routes/player/[player]/[profile]/sections/Collections.svelte new file mode 100644 index 0000000..4baa660 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Collections.svelte @@ -0,0 +1,62 @@ + + +{#if data.member.collections} + {#each Object.keys(categories).sort() as categoryName} + {@const collections = categories[categoryName]} +

{cleanId(categoryName)}

+
    + {#each collections as collection} + + + + Amount: {collection.amount.toLocaleString()} + + {cleanId(collection.name)} + {collection.level} + + + {/each} +
+ {/each} +{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Coop.svelte b/src/routes/player/[player]/[profile]/sections/Coop.svelte new file mode 100644 index 0000000..ff858f1 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Coop.svelte @@ -0,0 +1,79 @@ + + +{#if data.member.coopInvitation} +
+ {#if isProfileCreator} +

Created co-op

+ {:else} +

+ Invited by {#if data.member.coopInvitation.invitedBy} + + {:else} + Unknown player + {/if} +

+ {/if} +

+ {isProfileCreator ? 'Began creation' : 'Invited'}: + + {millisecondsToTime(Date.now() - data.member.coopInvitation.invitedTimestamp)} ago + +

+ {#if data.member.coopInvitation.acceptedTimestamp} +

+ {isProfileCreator ? 'Finished creation' : 'Accepted invite'}: + + after + {millisecondsToTime( + data.member.coopInvitation.acceptedTimestamp - + data.member.coopInvitation.invitedTimestamp + )} + + +

+ {/if} +
+

Members

+ {#each data.profile.members.filter(m => !m.left) as player} + + + + {/each} + {#if data.profile.members.filter(m => m.left).length > 0} +

Former members

+ {#each data.profile.members.filter(m => m.left) as player} + + + + {/each} + {/if} +{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Essence.svelte b/src/routes/player/[player]/[profile]/sections/Essence.svelte new file mode 100644 index 0000000..244dbcd --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Essence.svelte @@ -0,0 +1,27 @@ + + +{#if data.member.essence.types.length > 0} +
    + {#each data.member.essence.types as essenceType} +
  • + {toTitleCase(cleanId(essenceType.id))}: + {essenceType.amount.toLocaleString()} +
  • + {/each} +
+{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/FarmingContests.svelte b/src/routes/player/[player]/[profile]/sections/FarmingContests.svelte new file mode 100644 index 0000000..8eef53d --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/FarmingContests.svelte @@ -0,0 +1,62 @@ + + +
+

Talked to Jacob:

+
+
+ {#each data.member.farmingContests.list as farmingContest} +
+

+ {new Date( + skyblockTime(farmingContest.year, farmingContest.month, farmingContest.day) + ).toUTCString()} +

+
    + {#each farmingContest.crops as crop} + + {crop.amount.toLocaleString()} collected + {#if crop.position} + + (#{crop.position}/{crop.participants}) + + {/if} + + {/each} +
+
+ {/each} +
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Harp.svelte b/src/routes/player/[player]/[profile]/sections/Harp.svelte new file mode 100644 index 0000000..6a5c9cc --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Harp.svelte @@ -0,0 +1,72 @@ + + +
+

Claimed Melody's hair:

+ {#if data.member.harp.selected} +

+ Selected song: + {toTitleCase(cleanId(data.member.harp.selected.id))} + + {millisecondsToTime(Date.now() - data.member.harp.selected.timestamp)} ago + +

+ {/if} +
+
+ {#each data.member.harp.songs as song} +
+

{toTitleCase(cleanId(song.id))}

+
+ {#if song.completions} +

Completions: {song.completions}

+ {/if} + {#if song.perfectCompletions} +

Perfect completions: {song.perfectCompletions}

+ {:else} +

Progress: {Math.floor(song.progress * 100)}%

+ {/if} +
+
+ {/each} +
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Infobox.svelte b/src/routes/player/[player]/[profile]/sections/Infobox.svelte new file mode 100644 index 0000000..f8d2889 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Infobox.svelte @@ -0,0 +1,83 @@ + + +
+
+

+ ({data.member.left + ? 'Removed' + : data.member.profileName}) +

+ {#each generateInfobox(data) as item} + + {#if item.includes('Fairy souls')} +

+ {:else} +

+ {/if} + {/each} +
+
+

Player UUID:

+ {data.member.uuid} +

Profile UUID:

+ {data.profile.uuid} +
+
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Inventories.svelte b/src/routes/player/[player]/[profile]/sections/Inventories.svelte new file mode 100644 index 0000000..1dd7d28 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Inventories.svelte @@ -0,0 +1,105 @@ + + +{#if displayingInventories.length > 1} +
+ {#each displayingInventories as inventoryName} + + {/each} +
+{/if} +{#if data.member.inventories} + {#each displayingInventories as inventoryName} + {#if inventoryName === selectedInventoryName} + + + + {#if inventoryName == 'accessory_bag'} + + {/if} + {/if} + {/each} +{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Leaderboards.svelte b/src/routes/player/[player]/[profile]/sections/Leaderboards.svelte new file mode 100644 index 0000000..817f59a --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Leaderboards.svelte @@ -0,0 +1,46 @@ + + +{#await fetchApi(`player/${data.member.uuid}/${data.profile.uuid}/leaderboards`, fetch).then( r => r.json() )} + Loading... +{:then leaderboards} + {#if leaderboards.length > 0} + + {:else} +

This player isn't in any leaderboards.

+ {/if} +{/await} + + diff --git a/src/routes/player/[player]/[profile]/sections/Minions.svelte b/src/routes/player/[player]/[profile]/sections/Minions.svelte new file mode 100644 index 0000000..856d8f0 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Minions.svelte @@ -0,0 +1,40 @@ + + +

+ Unique minions: + + {data.profile.minionCount}/{data.profile.maxUniqueMinions} + +

+ + {#each data.profile.minions as minion} + + + {#each minion.levels as unlocked, i} + + {/each} + + {/each} +
{cleanId(minion.name)} + {toRomanNumerals(i + 1)} +
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Pets.svelte b/src/routes/player/[player]/[profile]/sections/Pets.svelte new file mode 100644 index 0000000..7f660c4 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Pets.svelte @@ -0,0 +1,79 @@ + + +{#if data.member.zones} +

+ Pets acquired: + + {petsAcquiredCount}/{totalPetsCount} + +

+
+ {#each data.member.pets.list as pet} +
+

{cleanId(pet.id.toLowerCase())}

+

Level: {pet.level.toLocaleString()}

+

Tier: {toTitleCase(pet.tier)}

+ {#if pet.item} +

Item: {pet.item.display.name}

+ {/if} +
+ {/each} +
+ {#if data.member.pets.missingIds.length > 0} +

Missing

+
    + {#each data.member.pets.missingIds as petId} +
  • {toTitleCase(cleanId(petId.toLowerCase()))}
  • + {/each} +
+ {/if} +{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/Skills.svelte b/src/routes/player/[player]/[profile]/sections/Skills.svelte new file mode 100644 index 0000000..8fc5aaf --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Skills.svelte @@ -0,0 +1,87 @@ + + +{#if !data.member.skills.apiEnabled} +

+ Skills API is disabled for this profile, so the values shown may be inaccurate. +

+{/if} +
    + {#each data.member.skills.list as skill} +
  • + + + {#if skill.levelXpRequired !== null} + {Math.round((skill.levelXp / skill.levelXpRequired) * 100)}% to next level, {Math.round( + skill.levelXp + ).toLocaleString()}/{formatNumber(skill.levelXpRequired, 3)} xp + {:else} + {Math.round(skill.levelXp).toLocaleString()} extra xp + {/if} + + + {cleanId(skill.id)} + + {skill.level} + + + +
  • + {/each} +
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Slayers.svelte b/src/routes/player/[player]/[profile]/sections/Slayers.svelte new file mode 100644 index 0000000..40fa67d --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Slayers.svelte @@ -0,0 +1,74 @@ + + +{#if data.member.slayers} +
+

Xp: {data.member.slayers.xp}

+

Kills: {data.member.slayers.kills}

+
+
+ {#each data.member.slayers.bosses as slayer} +
+

{slayer.name ? cleanId(slayer.name) : cleanId(slayer.rawName)}

+
+

Xp: {slayer.xp.toLocaleString()}

+

Level: {slayer.level}

+
+ + + {#each slayer.tiers as tier} + + {/each} + + + {#each slayer.tiers as tier} + + {/each} + +
Tier {toRomanNumerals(tier.tier)}
+ {tier.kills.toLocaleString()} +
+
+ {/each} +
+{/if} + + diff --git a/src/routes/player/[player]/[profile]/sections/StatList.svelte b/src/routes/player/[player]/[profile]/sections/StatList.svelte new file mode 100644 index 0000000..38604d7 --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/StatList.svelte @@ -0,0 +1,48 @@ + + + +
    + {#each stats.sort((a, b) => b.value - a.value) as stat} +
  • + {cleanId(stat.categorizedName)}: + + {#if stat.unit === 'time'} + {millisecondsToTime(stat.value)} + {:else} + {stat.value.toLocaleString()} + {/if} + +
  • + {/each} +
+ + diff --git a/src/routes/player/[player]/[profile]/sections/Zones.svelte b/src/routes/player/[player]/[profile]/sections/Zones.svelte new file mode 100644 index 0000000..f7e993b --- /dev/null +++ b/src/routes/player/[player]/[profile]/sections/Zones.svelte @@ -0,0 +1,42 @@ + + +{#if data.member.zones} +

+ Zones visited: + + {zonesVisitedCount}/{data.member.zones.length} + +

+
    + {#each data.member.zones.filter(z => z.visited) as zone} +
  • {cleanId(zone.name)}
  • + {/each} + {#each data.member.zones.filter(z => !z.visited) as zone} +
  • {cleanId(zone.name)}
  • + {/each} +
+{/if} + + -- cgit