diff options
author | mat <27899617+mat-1@users.noreply.github.com> | 2022-12-15 20:19:42 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-15 20:19:42 -0600 |
commit | ed5eedab8f9fc90dadf5c442cf559572d1b35f0c (patch) | |
tree | 01a763fd11810e9970f14f7dae180e95b279de9a /src/lib | |
parent | 89bf3d31e36ad3bdfd45461ee6fb69a4c791f848 (diff) | |
parent | 103689520f51991a1e9a4ca5829fe2f46d1a32c2 (diff) | |
download | skyblock-stats-ed5eedab8f9fc90dadf5c442cf559572d1b35f0c.tar.gz skyblock-stats-ed5eedab8f9fc90dadf5c442cf559572d1b35f0c.tar.bz2 skyblock-stats-ed5eedab8f9fc90dadf5c442cf559572d1b35f0c.zip |
Merge pull request #6 from skyblockstats/sveltekit-v1
Sveltekit v1
Diffstat (limited to 'src/lib')
27 files changed, 26 insertions, 1348 deletions
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 @@ <script lang="ts"> - import { browser } from '$app/env' + import { browser } from '$app/environment' import type { ItemAuctionsSchema, SimpleAuctionSchema } from './APITypes' import type { PreviewedAuctionData } from './utils' diff --git a/src/lib/BackgroundImage.svelte b/src/lib/BackgroundImage.svelte index 0b2f043..17d8705 100644 --- a/src/lib/BackgroundImage.svelte +++ b/src/lib/BackgroundImage.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { onDestroy, onMount } from 'svelte' - import { browser } from '$app/env' + import { browser } from '$app/environment' export let url: string let styleHtml = `<style class="background-image-style">:root{--background:url(${url})}</style>` diff --git a/src/lib/Collapsible.svelte b/src/lib/Collapsible.svelte index a7b6105..68fee79 100644 --- a/src/lib/Collapsible.svelte +++ b/src/lib/Collapsible.svelte @@ -4,7 +4,7 @@ Collapsible content that works without JS but is enhanced by it. --> <script lang="ts"> - import { browser } from '$app/env' + import { browser } from '$app/environment' import { onMount } from 'svelte' import { cleanId } from './utils' diff --git a/src/lib/LoginButton.svelte b/src/lib/LoginButton.svelte index bba078e..7ebf5d7 100644 --- a/src/lib/LoginButton.svelte +++ b/src/lib/LoginButton.svelte @@ -6,7 +6,7 @@ {#if loggedIn} <a href="/profile"><button class="login-button">Edit profile</button></a> {:else} - <a href="/login"> + <a href="/login" rel="external"> <button class="login-button" ><img src="/discord-mark-light.svg" alt="Discord logo" />Log in with Discord</button > diff --git a/src/lib/MayorSkin.svelte b/src/lib/MayorSkin.svelte index ad0a9a8..193a3d5 100644 --- a/src/lib/MayorSkin.svelte +++ b/src/lib/MayorSkin.svelte @@ -16,6 +16,7 @@ // special mayors derpy: 'be0f89466528ad5eca5a6506adddd896ff78c4fd21facaa74a8c4a809c89207', scorpius: '8f26fa0c47536e78e337257d898af8b1ebc87c0894503375234035ff2c7ef8f0', + finnegan: 'e7747fbee9fb39be39b00d3d483eb2f88b4bae82417ab5cb1b1aa930dd7b6689', // unique mayors technoblade: '786c039d969d1839155255e38e7b06a626ea9f8baf9cb55e0a77311efe18a3e', @@ -23,14 +24,21 @@ faith: '64b39d0756b92b8b7599d1f971580088954e21c5f60c673d0d4f63693fb002b5', } - let url: string + let url: string | undefined $: { - if (name.toLowerCase() === 'derpy') url = '/villager.png' - else url = `https://mc-heads.net/body/${skinIds[name.toLowerCase()]}` + if (name.toLowerCase() === 'jerry') url = '/villager.png' + else { + const skinId = skinIds[name.toLowerCase()] + url = skinId ? `https://mc-heads.net/body/${skinId}` : undefined + } } </script> -<img src={url} alt="Mayor {toTitleCase(name)}" /> +{#if url} + <img src={url} alt="Mayor {toTitleCase(name)}" /> +{:else} + <div class="no-skin-found">Unknown mayor</div> +{/if} <style> img { @@ -39,4 +47,12 @@ height: 12em; margin: 0 auto; } + + .no-skin-found { + display: flex; + align-items: center; + justify-content: center; + height: 12em; + margin: 0 auto; + } </style> diff --git a/src/lib/layout/Loader.svelte b/src/lib/layout/Loader.svelte index 3884e55..dd04924 100644 --- a/src/lib/layout/Loader.svelte +++ b/src/lib/layout/Loader.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { browser } from '$app/env' + import { browser } from '$app/environment' import { navigating } from '$app/stores' let progress = 0 diff --git a/src/lib/minecraft/inventory.ts b/src/lib/minecraft/inventory.ts index 227ed0c..5bd79c2 100644 --- a/src/lib/minecraft/inventory.ts +++ b/src/lib/minecraft/inventory.ts @@ -1,6 +1,6 @@ import * as skyblockAssets from 'skyblock-assets' import { vanilla } from '$lib/packs' -import { browser } from '$app/env' +import { browser } from '$app/environment' export interface Item { id?: string diff --git a/src/lib/sections/AccessoryBagUpgrades.svelte b/src/lib/sections/AccessoryBagUpgrades.svelte deleted file mode 100644 index 74530d1..0000000 --- a/src/lib/sections/AccessoryBagUpgrades.svelte +++ /dev/null @@ -1,100 +0,0 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Emoji from '$lib/Emoji.svelte' - import ListItemWithIcon from '$lib/ListItemWithIcon.svelte' - import { cleanId, skyblockTime } from '$lib/utils' - - export let data: CleanMemberProfile - - $: bagData = data.member.accessoryBagUpgrades -</script> - -<span class="accessory-bag-upgrades"> - <h3>Upgrades</h3> - <div class="accessory-bag-info-text"> - <p>Purchased: <b>{bagData.upgrades.purchased}</b></p> - <p>Coins spent: <b>{bagData.upgrades.coinsSpent.toLocaleString()}</b></p> - <p>Extra slots: <b>{bagData.upgrades.extraSlots}</b></p> - </div> - - <h3>Powers</h3> - {#if bagData.powers.selected} - <p class="accessory-bag-info-text"> - Selected: <b>{cleanId(bagData.powers.selected)}</b> - </p> - {/if} - <ul> - {#each bagData.powers.list as power} - <li> - {#if bagData.powers.selected === power} - <b>{cleanId(power)}</b> - {:else} - {cleanId(power)} - {/if} - </li> - {/each} - </ul> - - <div class="tuning-templates"> - {#each bagData.tuningTemplates as template, template_index} - <div class="tuning-template"> - <h3>Template #{template_index + 1}</h3> - <div class="accessory-bag-info-text"> - {#each Object.entries(template) as [statName, statValue]} - <p>{cleanId(statName)}: <b>{statValue}</b></p> - {/each} - </div> - </div> - {/each} - </div> -</span> - -<style> - p, - ul { - margin: 0; - } - ul { - padding-left: 1.5em; - } - h3 { - margin: 0.5em 0 0 0; - } - - .accessory-bag-info-text { - color: var(--theme-darker-text); - } - .accessory-bag-info-text b { - color: var(--theme-main-text); - } - - .tuning-templates { - display: flex; - flex-wrap: wrap; - max-width: 40rem; - column-gap: 0.5rem; - row-gap: 0.5rem; - margin-top: 1rem; - } - .tuning-template { - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.1); - padding: 0.75em; - border-radius: 1em; - } - .tuning-template h3 { - margin: 0; - } - - .accessory-bag-upgrades { - /* width: 5rem; */ - } - @media only screen and (min-width: 1160px) { - .accessory-bag-upgrades { - display: inline-grid; - position: relative; - top: -1.5em; - left: 0.5em; - } - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Tooltip from '$lib/Tooltip.svelte' - export let data: CleanMemberProfile -</script> - -{#if data.member.achievements} - <h3> - Tiered - <span class="achievement-count"> - ({data.member.achievements.tiered.filter(a => a.amount).length}/{data.member.achievements - .tiered.length}) - </span> - </h3> - <ul> - {#each data.member.achievements.tiered as achievement} - <li class="achievement"> - <Tooltip> - <span slot="tooltip"> - {achievement.description} - </span> - - <span class:achievement-locked={achievement.amount === 0}> - {achievement.name}: {#if achievement.next} - <b class="achievement-amount">{achievement.amount}</b>/{achievement.next} - {:else} - <span class="achievement-amount achievement-amount-maxed">{achievement.amount}</span> - {/if} - </span> - </Tooltip> - </li> - {/each} - </ul> - - <h3> - Challenge - <span class="achievement-count"> - ({data.member.achievements.challenge.filter(a => a.unlocked).length}/{data.member.achievements - .challenge.length}) - </span> - </h3> - <ul> - {#each data.member.achievements.challenge as achievement} - <li class="achievement"> - <Tooltip> - <span slot="tooltip"> - {achievement.description} - </span> - - {#if achievement.unlocked} - <span> - {achievement.name} - </span> - {:else} - <span class="achievement-locked"> - {achievement.name} - </span> - {/if} - </Tooltip> - </li> - {/each} - </ul> -{/if} - -<style> - ul { - margin: 0; - padding-left: 1em; - } - - .achievement-locked { - opacity: 0.5; - } - - .achievement-count { - color: var(--theme-darker-text); - font-weight: normal; - } - - .achievement-amount { - opacity: 0.9; - } - .achievement-amount-maxed { - color: #0e0; - opacity: 1; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Inventory from '$lib/minecraft/Inventory.svelte' - import type { MatcherFile } from 'skyblock-assets' - - export let data: CleanMemberProfile - export let pack: MatcherFile -</script> - -{#if data.member.inventories} - <span> - <Inventory items={data.member.inventories.armor} name="armor" groupLimit={1} {pack} /> - </span> -{/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 @@ -<!-- - @component - - A list of the player's past auctions, and their auction stats. ---> -<script lang="ts"> - import { cleanId, millisecondsToTime } from '$lib/utils' - import type { CleanMemberProfile, StatItem } from '$lib/APITypes' - import { fetchApi } from '$lib/api' - import type { MatcherFile } from 'skyblock-assets' - import Auction from '$lib/Auction.svelte' - - export let data: CleanMemberProfile - export let stats: StatItem[] - export let pack: MatcherFile - - let onlyThisProfile = true - - let auctions: any[] = [] - let loading = true - - let page = 0 - let totalPages: number | undefined = undefined - - async function updateAuctions() { - loading = true - const thisPage = page - page += 1 - const auctionsResponse = await fetchApi( - `playerauctions/${data.member.uuid}?page=${thisPage}`, - fetch - ).then(r => r.json()) - loading = false - auctions = [...auctions, ...auctionsResponse.auctions] - totalPages = auctionsResponse.pages - } - - updateAuctions() -</script> - -<div class="auction-stats-and-list-container"> - <ul> - {#each stats.sort((a, b) => b.value - a.value) as stat} - <li> - <span class="stat-name">{cleanId(stat.categorizedName)}:</span> - <span class="stat-value"> - {#if stat.unit === 'time'} - {millisecondsToTime(stat.value)} - {:else} - {stat.value.toLocaleString()} - {/if} - </span> - </li> - {/each} - </ul> - - <div class="player-auctions-list-container"> - {#if loading || auctions.length > 0} - <h3>Auctions sold</h3> - {/if} - {#if auctions.length > 0} - <div class="player-auctions-list"> - {#each auctions as auction} - {#if !onlyThisProfile || auction.sellerProfileUuid == data.profile.uuid} - <Auction {auction} {pack} /> - {/if} - {/each} - </div> - {#if !loading && page != totalPages} - <button on:click={updateAuctions}>Show more</button> - {/if} - {/if} - {#if loading} - Loading... - {/if} - </div> -</div> - -<style> - li { - position: relative; - } - ul { - padding-left: 1em; - margin-top: 0.5em; - width: max-content; - } - .auction-stats-and-list-container { - display: grid; - grid-template-columns: 1fr auto; - } - - @media (max-width: 600px) { - .auction-stats-and-list-container { - grid-template-columns: 1fr; - } - } - - .player-auctions-list { - display: flex; - flex-wrap: wrap; - column-gap: 0.5rem; - row-gap: 0.5rem; - } - .player-auctions-list-container { - margin-top: 0.5em; - margin-left: 0.5em; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Tooltip from '$lib/Tooltip.svelte' - import ConditionalLink from '$lib/ConditionalLink.svelte' - import { - colorCodeCharacter, - formattingCodeToHtml, - millisecondsToTime, - removeFormattingCode, - } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -{#if data.profile.bank} - <div class="bank-main-current-balance"> - <p> - Current bank balance: - <span class="bank-main-current-balance-value"> - <b>{data.profile.bank.balance?.toLocaleString()}</b> coins - </span> - </p> - <p> - Purse: - <span class="bank-main-current-balance-value"> - <b>{data.member.purse.toLocaleString()}</b> coins - </span> - </p> - </div> - {#each data.profile.bank.history as transaction} - <div> - <span class="transaction-player"> - <ConditionalLink - href="/player/{removeFormattingCode(transaction.name)}" - isWrapped={transaction.name.startsWith(colorCodeCharacter)} - > - {@html formattingCodeToHtml(transaction.name)} - </ConditionalLink> - </span> - <Tooltip> - <span slot="tooltip"> - New balance: <b>{transaction.total.toLocaleString()}</b> - </span> - <span - class:difference-positive={transaction.change > 0} - class:difference-negative={transaction.change < 0} - > - {transaction.change > 0 - ? '+' + transaction.change.toLocaleString() - : transaction.change.toLocaleString()} - </span> - </Tooltip> - - <span class="transaction-timeago"> - {millisecondsToTime(Date.now() - transaction.timestamp)} ago - </span> - </div> - {/each} -{/if} - -<style> - .difference-positive { - color: #0f0; - } - .difference-negative { - color: red; - } - - .transaction-timeago { - color: var(--theme-darker-text); - } - - .transaction-player { - font-family: Minecraft, 'Atkinson Hyperlegible', sans-serif; - font-size: 0.8em; - } - - .bank-main-current-balance { - margin: 0.5em 0; - color: var(--theme-darker-text); - } - - .bank-main-current-balance-value { - color: var(--theme-main-text); - } - p { - margin: 0; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import { cleanId, millisecondsToTime, toTitleCase } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -{#if data.member.claimed && data.member.claimed.length > 0} - <ul> - {#each data.member.claimed as claimed} - <li> - <b class="claimed-item-name">{toTitleCase(cleanId(claimed.id))}</b> - <span class="claimed-item-timestamp"> - {millisecondsToTime(Date.now() - claimed.timestamp)} ago - </span> - </li> - {/each} - </ul> -{/if} - -<style> - p { - margin: 0; - } - - ul { - margin: 0.5em 0; - } - - .claimed-item-timestamp { - color: var(--theme-darker-text); - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile, Collection } from '$lib/APITypes' - import { skyblockItemToUrl } from '$lib/minecraft/inventory' - import ListItemWithIcon from '$lib/ListItemWithIcon.svelte' - import type { MatcherFile } from 'skyblock-assets' - import Tooltip from '$lib/Tooltip.svelte' - import { cleanId } from '$lib/utils' - - export let data: CleanMemberProfile - export let pack: MatcherFile - - const categories: Record<string, Collection[]> = {} - if (data.member.collections) - for (const collection of data.member.collections) { - if (!categories[collection.category]) categories[collection.category] = [] - categories[collection.category].push(collection) - } -</script> - -{#if data.member.collections} - {#each Object.keys(categories).sort() as categoryName} - {@const collections = categories[categoryName]} - <h3>{cleanId(categoryName)}</h3> - <ul> - {#each collections as collection} - <ListItemWithIcon - src={skyblockItemToUrl(collection.name, pack)} - alt={cleanId(collection.name)} - > - <Tooltip> - <span slot="tooltip"> - Amount: {collection.amount.toLocaleString()} - </span> - {cleanId(collection.name)} - <span class="coll-level">{collection.level}</span> - </Tooltip> - </ListItemWithIcon> - {/each} - </ul> - {/each} -{/if} - -<style> - ul { - margin: 0; - display: flex; - flex-wrap: wrap; - width: fit-content; - /* this ensures there's at most 2 lines */ - max-width: 30em; - } - - ul > :global(li) { - width: 12em; - height: 1.5em; - text-overflow: ellipsis; - } - - h3 { - margin: 0.5em 0 0.5em 0.5em; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Username from '$lib/minecraft/Username.svelte' - import { millisecondsToTime } from '$lib/utils' - export let data: CleanMemberProfile - - $: isProfileCreator = data.member.coopInvitation?.invitedBy?.uuid == data.member.uuid -</script> - -{#if data.member.coopInvitation} - <div class="info-text primary-info-text"> - {#if isProfileCreator} - <p><b class="info-text-value">Created co-op</b></p> - {:else} - <p> - Invited by {#if data.member.coopInvitation.invitedBy} - <Username player={data.member.coopInvitation.invitedBy} prefix /> - {:else} - <b>Unknown player</b> - {/if} - </p> - {/if} - <p> - {isProfileCreator ? 'Began creation' : 'Invited'}: - <span class="info-text-value coop-invited-timeago"> - <b>{millisecondsToTime(Date.now() - data.member.coopInvitation.invitedTimestamp)}</b> ago - </span> - </p> - {#if data.member.coopInvitation.acceptedTimestamp} - <p> - {isProfileCreator ? 'Finished creation' : 'Accepted invite'}: - <span class="info-text-value coop-accepted-invite-after"> - after <b> - {millisecondsToTime( - data.member.coopInvitation.acceptedTimestamp - - data.member.coopInvitation.invitedTimestamp - )} - </b> - </span> - </p> - {/if} - </div> - <h3>Members</h3> - {#each data.profile.members.filter(m => !m.left) as player} - <span class="member"> - <Username {player} headType="2d" hyperlinkToProfile /> - </span> - {/each} - {#if data.profile.members.filter(m => m.left).length > 0} - <h3 class="former-members-title">Former members</h3> - {#each data.profile.members.filter(m => m.left) as player} - <span class="member"> - <Username {player} headType="2d" hyperlinkToProfile={data.profile.uuid} /> - </span> - {/each} - {/if} -{/if} - -<style> - p { - margin: 0; - } - .primary-info-text { - margin: 0.5em 0; - } - .info-text { - color: var(--theme-darker-text); - } - .info-text .info-text-value { - color: var(--theme-main-text); - } - - .member { - display: block; - } - .former-members-title { - margin-top: 0.5rem; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import { cleanId, toTitleCase } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -{#if data.member.essence.types.length > 0} - <ul> - {#each data.member.essence.types as essenceType} - <li> - {toTitleCase(cleanId(essenceType.id))}: - <b class="essence-type-amount">{essenceType.amount.toLocaleString()}</b> - </li> - {/each} - </ul> -{/if} - -<style> - p { - margin: 0; - } - - ul { - margin: 0.5em 0; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Emoji from '$lib/Emoji.svelte' - import ListItemWithIcon from '$lib/ListItemWithIcon.svelte' - import { skyblockItemToUrl } from '$lib/minecraft/inventory' - import { skyblockTime } from '$lib/utils' - - export let data: CleanMemberProfile - - let cachedItemUrls: Record<string, string> = {} - function cachedSkyblockItemToUrl(item: string) { - if (!cachedItemUrls[item]) cachedItemUrls[item] = skyblockItemToUrl(item) - return cachedItemUrls[item] - } -</script> - -<div class="info-text primary-info-text"> - <p>Talked to Jacob: <Emoji value={data.member.farmingContests.talkedToJacob ? '✅' : '❌'} /></p> -</div> -<div class="farming-contests-list"> - {#each data.member.farmingContests.list as farmingContest} - <div class="farming-contest"> - <p class="farming-contest-date"> - {new Date( - skyblockTime(farmingContest.year, farmingContest.month, farmingContest.day) - ).toUTCString()} - </p> - <ul> - {#each farmingContest.crops as crop} - <ListItemWithIcon src={cachedSkyblockItemToUrl(crop.item)}> - <b>{crop.amount.toLocaleString()}</b> collected - {#if crop.position} - <span class="farming-contest-item-placement"> - (#{crop.position}/{crop.participants}) - </span> - {/if} - </ListItemWithIcon> - {/each} - </ul> - </div> - {/each} -</div> - -<style> - p, - ul { - margin: 0; - } - - .primary-info-text { - margin: 0.5em 0; - } - - .info-text { - color: var(--theme-darker-text); - } - - .farming-contest-item-placement, - .farming-contest-date { - color: var(--theme-darker-text); - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import Emoji from '$lib/Emoji.svelte' - import { cleanId, millisecondsToTime, toTitleCase } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -<div class="info-text primary-info-text"> - <p>Claimed Melody's hair: <Emoji value={data.member.harp.claimedMelodysHair ? '✅' : '❌'} /></p> - {#if data.member.harp.selected} - <p> - Selected song: - <b class="info-text-value">{toTitleCase(cleanId(data.member.harp.selected.id))}</b> - <span class="harp-selection-timeago"> - {millisecondsToTime(Date.now() - data.member.harp.selected.timestamp)} ago - </span> - </p> - {/if} -</div> -<div class="harp-songs-list"> - {#each data.member.harp.songs as song} - <div class="harp-song" class:selected-harp-song={song.id === data.member.harp.selected?.id}> - <h3>{toTitleCase(cleanId(song.id))}</h3> - <div class="info-text"> - {#if song.completions} - <p>Completions: <b class="info-text-value">{song.completions}</b></p> - {/if} - {#if song.perfectCompletions} - <p>Perfect completions: <b class="info-text-value">{song.perfectCompletions}</b></p> - {:else} - <p>Progress: <b class="info-text-value">{Math.floor(song.progress * 100)}%</b></p> - {/if} - </div> - </div> - {/each} -</div> - -<style> - p { - margin: 0; - } - - .primary-info-text { - margin: 0.5em 0; - } - - .info-text { - color: var(--theme-darker-text); - } - .info-text .info-text-value { - color: var(--theme-main-text); - } - - .harp-songs-list { - display: flex; - flex-wrap: wrap; - max-width: 40rem; - column-gap: 0.5rem; - row-gap: 0.5rem; - } - .harp-song { - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.1); - padding: 0.75em; - border-radius: 1em; - width: 12em; - } - .selected-harp-song { - border: 1px solid rgba(255, 255, 255, 0.2); - } -</style> 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 @@ -<script lang="ts"> - import { generateInfobox } from '$lib/profile' - import Username from '$lib/minecraft/Username.svelte' - import Emoji from '$lib/Emoji.svelte' - - export let data -</script> - -<div id="infobox-container"> - <div id="infobox"> - <h2> - <Username player={data.member} prefix /> ({data.member.left - ? 'Removed' - : data.member.profileName}) - </h2> - {#each generateInfobox(data) as item} - <!-- hack so fairy souls is clickable to get to the leaderboards --> - {#if item.includes('Fairy souls')} - <a href="/leaderboards/fairy_souls" class="fairy-souls-leaderboard" - ><p><Emoji value={item} /></p></a - > - {:else} - <p><Emoji value={item} /></p> - {/if} - {/each} - </div> - <div id="infobox-extra"> - <p>Player UUID:</p> - <b><code>{data.member.uuid}</code></b> - <p>Profile UUID:</p> - <b><code>{data.profile.uuid}</code></b> - </div> -</div> - -<style> - #infobox-container { - float: right; - max-width: 95%; - width: 20em; - } - #infobox { - background-color: rgba(20, 20, 20, 0.4); - padding: 1em; - margin-top: 2em; - border-radius: 0.5em; - box-shadow: 0 0 1em #000; - } - #infobox-extra { - opacity: 0.5; - margin-top: 0.5rem; - } - #infobox-extra p { - margin: 0; - } - p { - margin: 0 0 0.25em 0; - } - .fairy-souls-leaderboard { - color: inherit; - text-decoration: none; - } - @media only screen and (max-width: 600px) { - #infobox { - position: relative; - right: -2em; - margin-top: 0; - } - } - @media only screen and (max-width: 550px) { - #infobox { - position: unset; - box-shadow: none; - float: none; - border: 1px solid var(--theme-lighter-background); - } - } - @media only screen and (max-width: 460px) { - #infobox-container { - max-width: 100%; - float: left; - } - } -</style> 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 @@ -<script lang="ts"> - import { inventoryIconMap, skyblockItemToUrl, type Item } from '$lib/minecraft/inventory' - import Inventory from '$lib/minecraft/Inventory.svelte' - import type { MatcherFile } from 'skyblock-assets' - import { cleanId } from '$lib/utils' - import AccessoryBagUpgrades from './AccessoryBagUpgrades.svelte' - import type { CleanMemberProfile } from '$lib/APITypes' - - export let data: CleanMemberProfile - export let pack: MatcherFile - - let displayingInventories: string[] = [] - for (const inventoryName in data.member.inventories) - if (inventoryName !== 'armor') displayingInventories.push(inventoryName) - - let selectedInventoryName: string = displayingInventories[0] -</script> - -{#if displayingInventories.length > 1} - <div id="inventory-tabs"> - {#each displayingInventories as inventoryName} - <button - class="inventory-tab" - class:inventory-tab-active={inventoryName === selectedInventoryName} - on:click={() => (selectedInventoryName = inventoryName)} - > - {#if inventoryName in inventoryIconMap} - <img - class="inventory-tab-icon" - loading="lazy" - src={skyblockItemToUrl(inventoryIconMap[inventoryName], pack, 50)} - alt={cleanId(inventoryName)} - /> - {/if} - <span class="inventory-tab-name">{cleanId(inventoryName)}</span> - </button> - {/each} - </div> -{/if} -{#if data.member.inventories} - {#each displayingInventories as inventoryName} - {#if inventoryName === selectedInventoryName} - <span id={inventoryName} class="inventory-content"> - <Inventory items={data.member.inventories[inventoryName]} {pack} name={inventoryName} /> - </span> - {#if inventoryName == 'accessory_bag'} - <AccessoryBagUpgrades {data} /> - {/if} - {/if} - {/each} -{/if} - -<style> - #inventory-tabs { - margin-bottom: 1em; - overflow: hidden; - border-radius: 1em; - max-width: 40em; - /* box-shadow: 0 0 1em #000; */ - } - .inventory-tab { - /* background-color: var(--theme-lighter-background); */ - background-color: rgba(20, 20, 20, 0.4); - color: var(--theme-main-text); - border: none; - border-radius: 0; - padding: 0 0.5em; - cursor: pointer; - transition-duration: 200ms; - height: 2.5em; - vertical-align: middle; - } - .inventory-tab-icon { - height: 1.5em; - width: 1.5em; - vertical-align: text-bottom; - position: relative; - top: 0.1em; - image-rendering: crisp-edges; - image-rendering: pixelated; - } - .inventory-tab-name { - vertical-align: text-top; - } - .inventory-tab:hover, - .inventory-tab-active { - background-color: rgba(40, 40, 40, 0.9); - } - - .inventory-content { - display: inline-grid; - } - - @media only screen and (max-width: 480px) { - .inventory-content :global(.item) { - /* there's no good way to override the existing 32px size without !important :( */ - font-size: 24px !important; - } - } - @media only screen and (max-width: 350px) { - .inventory-content :global(.item) { - font-size: 16px !important; - } - } -</style> 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 @@ -<script lang="ts"> - import { fetchApi } from '$lib/api' - - import type { CleanMemberProfile } from '$lib/APITypes' - import Emoji from '$lib/Emoji.svelte' - import { cleanId, formatNumberFromUnit } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -{#await fetchApi(`player/${data.member.uuid}/${data.profile.uuid}/leaderboards`, fetch).then( r => r.json() )} - Loading... -{:then leaderboards} - {#if leaderboards.length > 0} - <ul> - {#each leaderboards as leaderboard} - <li class="leaderboard-item"> - <a href="/leaderboard/{leaderboard.name}" class="leaderboard-item-anchor"> - {leaderboard.positionIndex + 1}) <b>{cleanId(leaderboard.name)}</b>: {formatNumberFromUnit( - leaderboard.value, - leaderboard.unit ?? null - )} - </a> - </li> - {/each} - </ul> - {:else} - <p>This player isn't in any leaderboards. <Emoji value="😦" /></p> - {/if} -{/await} - -<style> - .leaderboard-item-anchor { - color: inherit; - } - .leaderboard-item { - list-style-type: none; - } - ul { - padding-left: 0; - margin-top: 0.5em; - } - p { - margin: 0.5rem 0; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import { cleanId, toRomanNumerals } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -<p class="unique-minions-text"> - Unique minions: - <span class="minions-fraction"> - <b>{data.profile.minionCount}</b>/{data.profile.maxUniqueMinions} - </span> -</p> -<table> - {#each data.profile.minions as minion} - <tr> - <th>{cleanId(minion.name)}</th> - {#each minion.levels as unlocked, i} - <td class="minion-table-item" class:unlocked> - {toRomanNumerals(i + 1)} - </td> - {/each} - </tr> - {/each} -</table> - -<style> - .unique-minions-text { - color: var(--theme-darker-text); - } - .minions-fraction { - color: var(--theme-main-text); - } - .minion-table-item:not(.unlocked) { - opacity: 0.2; - } - .minion-table-item.unlocked { - color: #3e3; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import { cleanId, toRomanNumerals, toTitleCase } from '$lib/utils' - - export let data: CleanMemberProfile - - // we convert it to a set to remove duplicates - const petsAcquiredCount = new Set(data.member.pets.list.map(p => p.id)).size - const totalPetsCount = data.member.pets.missingIds.length + petsAcquiredCount -</script> - -{#if data.member.zones} - <p class="zones-visited-text"> - Pets acquired: - <span class="zones-visited-number"> - <b>{petsAcquiredCount}</b>/{totalPetsCount} - </span> - </p> - <div class="pets-list"> - {#each data.member.pets.list as pet} - <div class="individual-pet-data"> - <h3>{cleanId(pet.id.toLowerCase())}</h3> - <p>Level: <b>{pet.level.toLocaleString()}</b></p> - <p>Tier: <b>{toTitleCase(pet.tier)}</b></p> - {#if pet.item} - <p>Item: <b>{pet.item.display.name}</b></p> - {/if} - </div> - {/each} - </div> - {#if data.member.pets.missingIds.length > 0} - <h3 class="missing-pets-title">Missing</h3> - <ul> - {#each data.member.pets.missingIds as petId} - <li class="missing-pet">{toTitleCase(cleanId(petId.toLowerCase()))}</li> - {/each} - </ul> - {/if} -{/if} - -<style> - p { - margin: 0; - } - .zones-visited-text { - color: var(--theme-darker-text); - margin: 0.5em 0; - } - .zones-visited-number { - color: var(--theme-main-text); - } - .missing-pet { - opacity: 0.5; - } - .individual-pet-data { - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.1); - padding: 0.75em; - border-radius: 1em; - width: 9rem; - } - - .pets-list { - display: flex; - flex-wrap: wrap; - max-width: 40rem; - column-gap: 0.5rem; - row-gap: 0.5rem; - } - - .missing-pets-title { - margin-top: 1rem; - } - - ul { - padding-left: 1em; - margin: 0; - } -</style> 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 @@ -<script lang="ts"> - import Emoji from '$lib/Emoji.svelte' - - import Tooltip from '$lib/Tooltip.svelte' - import { cleanId, formatNumber } from '$lib/utils' - - const skillImages = { - runecrafting: '/skill-icons/runecrafting.webp', - alchemy: '/skill-icons/herblore.webp', - combat: '/skill-icons/attack.webp', - enchanting: '/skill-icons/magic.webp', - foraging: '/skill-icons/woodcutting.webp', - mining: '/skill-icons/mining.webp', - taming: '/skill-icons/hunter.webp', - farming: '/skill-icons/farming.webp', - fishing: '/skill-icons/fishing.webp', - carpentry: '/skill-icons/construction.webp', - social: '/skill-icons/agility.webp', - } - - export let data -</script> - -{#if !data.member.skills.apiEnabled} - <p class="skills-api-warning"> - <Emoji value="⚠" /> Skills API is disabled for this profile, so the values shown may be inaccurate. - </p> -{/if} -<ul> - {#each data.member.skills.list as skill} - <li - class="list-item-with-icon" - style="background: url({skillImages[skill.id]}) 0 0/1em no-repeat" - > - <Tooltip> - <span slot="tooltip"> - {#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} - </span> - <span> - {cleanId(skill.id)} - <span class="skill-level" class:skill-maxed={skill.level === skill.maxLevel}> - {skill.level} - </span> - </span> - </Tooltip> - </li> - {/each} -</ul> - -<style> - .skill-level { - opacity: 0.9; - } - .skill-maxed { - color: #0e0; - opacity: 1; - } - .list-item-with-icon { - list-style: none; - padding-left: 1.2em; - position: relative; - right: 1.2em; - image-rendering: crisp-edges; - image-rendering: pixelated; - } - - .skills-api-warning { - margin-top: 0; - } - - ul { - margin-top: 0; - display: flex; - flex-wrap: wrap; - max-width: 30em; - } - ul > li { - width: 10em; - margin: 0.25em 0.25em 0 0; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import { cleanId, toRomanNumerals } from '$lib/utils' - - export let data: CleanMemberProfile -</script> - -{#if data.member.slayers} - <div class="slayer-info-text total-slayer-info-text"> - <p>Xp: <b>{data.member.slayers.xp}</b></p> - <p>Kills: <b>{data.member.slayers.kills}</b></p> - </div> - <div class="slayers-list"> - {#each data.member.slayers.bosses as slayer} - <div class="individual-slayer-data"> - <h3>{slayer.name ? cleanId(slayer.name) : cleanId(slayer.rawName)}</h3> - <div class="slayer-info-text"> - <p>Xp: <b>{slayer.xp.toLocaleString()}</b></p> - <p>Level: <b>{slayer.level}</b></p> - </div> - <table> - <tr> - {#each slayer.tiers as tier} - <th>Tier {toRomanNumerals(tier.tier)}</th> - {/each} - </tr> - <tr> - {#each slayer.tiers as tier} - <td class="slayer-tier-kills"> - {tier.kills.toLocaleString()} - </td> - {/each} - </tr> - </table> - </div> - {/each} - </div> -{/if} - -<style> - p { - margin: 0; - } - - .total-slayer-info-text { - margin: 0.5em 0; - } - - .slayer-tier-kills { - text-align: center; - } - - .slayer-info-text { - color: var(--theme-darker-text); - } - .slayer-info-text b { - color: var(--theme-main-text); - } - - .individual-slayer-data { - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.1); - padding: 0.75em; - border-radius: 1em; - } - - .slayers-list { - display: flex; - flex-wrap: wrap; - max-width: 40rem; - column-gap: 0.5rem; - row-gap: 0.5rem; - } -</style> 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 @@ -<!-- - @component - - A sorted list of a user's stats, with the total sometimes being at the top. ---> -<script lang="ts"> - import { cleanId, millisecondsToTime } from '$lib/utils' - import type { StatItem } from '$lib/APITypes' - - export let stats: StatItem[] -</script> - -<ul> - {#each stats.sort((a, b) => b.value - a.value) as stat} - <li class:total-stat={stat.categorizedName === 'total'}> - <span class="stat-name">{cleanId(stat.categorizedName)}:</span> - <span class="stat-value"> - {#if stat.unit === 'time'} - {millisecondsToTime(stat.value)} - {:else} - {stat.value.toLocaleString()} - {/if} - </span> - </li> - {/each} -</ul> - -<style> - .total-stat .stat-name { - color: var(--theme-darker-text); - } - .total-stat .stat-value { - font-weight: bold; - } - - .total-stat { - list-style-type: none; - padding: 0 0 0.5em 0; - right: 1em; - } - li { - position: relative; - } - ul { - margin-top: 0.5em; - padding-left: 1em; - } -</style> 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 @@ -<script lang="ts"> - import type { CleanMemberProfile } from '$lib/APITypes' - import { cleanId } from '$lib/utils' - - export let data: CleanMemberProfile - - let zonesVisitedCount = data.member.zones ? data.member.zones?.filter(z => z.visited).length : 0 -</script> - -{#if data.member.zones} - <p class="zones-visited-text"> - Zones visited: - <span class="zones-visited-number"> - <b>{zonesVisitedCount}</b>/{data.member.zones.length} - </span> - </p> - <ul> - {#each data.member.zones.filter(z => z.visited) as zone} - <li>{cleanId(zone.name)}</li> - {/each} - {#each data.member.zones.filter(z => !z.visited) as zone} - <li class="unvisited-zone">{cleanId(zone.name)}</li> - {/each} - </ul> -{/if} - -<style> - .zones-visited-text { - color: var(--theme-darker-text); - margin: 0.5em 0; - } - .zones-visited-number { - color: var(--theme-main-text); - } - .unvisited-zone { - opacity: 0.5; - } - ul { - padding-left: 1em; - margin: 0; - } -</style> |