aboutsummaryrefslogtreecommitdiff
path: root/src/routes
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-03-05 16:04:50 -0600
committermat <github@matdoes.dev>2022-03-05 16:04:50 -0600
commitf256a52e6a0a9ba478cde22d96c6292842247c01 (patch)
tree6b45a452cb6f6de45318b2b9839313599edbfd5c /src/routes
parent478b6ea8a50bbf372921990775d3fd480446f350 (diff)
downloadskyblock-stats-f256a52e6a0a9ba478cde22d96c6292842247c01.tar.gz
skyblock-stats-f256a52e6a0a9ba478cde22d96c6292842247c01.tar.bz2
skyblock-stats-f256a52e6a0a9ba478cde22d96c6292842247c01.zip
mayors
Diffstat (limited to 'src/routes')
-rw-r--r--src/routes/election.svelte273
-rw-r--r--src/routes/index.svelte8
2 files changed, 279 insertions, 2 deletions
diff --git a/src/routes/election.svelte b/src/routes/election.svelte
new file mode 100644
index 0000000..69f4812
--- /dev/null
+++ b/src/routes/election.svelte
@@ -0,0 +1,273 @@
+<script lang="ts" context="module">
+ import type { Load } from '@sveltejs/kit'
+ import { API_URL } from '$lib/api'
+
+ export const load: Load = async ({ params, fetch }) => {
+ const data = await fetch(`${API_URL}election`).then(r => r.json())
+
+ return {
+ props: {
+ data,
+ },
+ }
+ }
+</script>
+
+<script lang="ts">
+ import Header from '$lib/Header.svelte'
+ import Head from '$lib/Head.svelte'
+ import {
+ cleanId,
+ 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 { invalidate } from '$app/navigation'
+ import { browser } from '$app/env'
+
+ export let data: ElectionData
+
+ let destroyed = false
+
+ let currentTime = Date.now()
+ // update currentTime every animation frame
+ function updateTime() {
+ currentTime = Date.now()
+ if (!destroyed) requestAnimationFrame(updateTime)
+ }
+
+ $: nextSpecialMayorYear = Math.ceil(((data.current?.year || data.previous.year) + 1) / 8) * 8
+ const specialMayors = ['Scorpius', 'Derpy', 'Jerry']
+
+ // invalidate at the end of every minute
+ async function autoInvalidate(first: boolean) {
+ if (browser && !destroyed) {
+ // don't invalidate the first time the function is called
+ if (!first) await invalidate('')
+
+ const lastUpdatedAgo = Date.now() - data.last_updated * 1000
+ setTimeout(() => autoInvalidate(false), lastUpdatedAgo + 10 * 60 * 1000)
+ }
+ }
+
+ autoInvalidate(true)
+
+ onMount(() => {
+ destroyed = false
+ updateTime()
+ })
+
+ onDestroy(() => {
+ destroyed = true
+ })
+</script>
+
+<Head title="SkyBlock Mayor Election Status" />
+<Header />
+
+<main>
+ <div class="next-mayor-update">
+ <p>
+ <b>Last API update:</b>
+ {millisecondsToTime(currentTime - data.last_updated * 1000)}
+ </p>
+ <p>
+ <b>Next API update:</b>
+ {millisecondsToTime(currentTime - data.last_updated * 1000 + 10 * 60 * 1000)}
+ </p>
+ </div>
+ <h1>SkyBlock Mayor Election Status</h1>
+ <p>
+ <b>Next election:</b>
+ {millisecondsToTime(skyblockTime(data.previous.year + 1, 6, 27) - currentTime, { parts: 3 })}
+ </p>
+
+ {#if data.current}
+ <h2>Ongoing election <span class="candidate-year">(Year {data.current.year})</span></h2>
+ <p class="election-ends-in-text">
+ <b>Ends in:</b>
+ {millisecondsToTime(skyblockTime(data.previous.year + 1, 3, 27) - Date.now())}
+ </p>
+ <div class="mayor-candidates">
+ {#each data.current.candidates.sort((a, b) => a.votes - b.votes) as candidate}
+ {@const color = candidate.color ? colorCodes[candidate.color] : null}
+ <div class="mayor">
+ <div>
+ <h3 style={color ? `color: ${color}` : undefined}>{candidate.name}</h3>
+ <p class="mayor-vote-count">
+ <span class="mayor-vote-count-number" style={color ? `color: ${color}` : undefined}>
+ {candidate.votes.toLocaleString()}
+ </span> votes
+ </p>
+ <MayorSkin name={candidate.name} />
+ </div>
+ <ul class="mayor-perks">
+ {#each candidate.perks as perk}
+ <div class="mayor-perk">
+ <h4 style={color ? `color: ${color}` : undefined}>{perk.name}</h4>
+ <p>{@html formattingCodeToHtml(perk.description)}</p>
+ </div>
+ {/each}
+ </ul>
+ </div>
+ {/each}
+ </div>
+ {/if}
+
+ <!--
+<h2>Previous election <span class="candidate-year">({{ skyblockYear(data.previous.year) }})</span></h2>
+<div class="mayor-candidates">
+ {% for candidate in data.previous.candidates|sort(true, false, 'votes') %}
+ <div class="mayor">
+ {% set color = colorCodes[candidate.color] if candidate.color else null %}
+ <div>
+ <h3{% if color %} style="color: {{color}}"{% endif %}>{{candidate.name}}</h3>
+ <p class="mayor-vote-count"><span class="mayor-vote-count-number"{% if color %} style="color: {{color}}"{% endif %}>{{candidate.votes.toLocaleString()}}</span> votes</p>
+ {% if candidate.name == data.previous.winner %}
+ <p class="mayor-winner">Winner</p>
+ {% endif %}
+ {{ renderMayor(candidate.name) }}
+ </div>
+ <ul class="mayor-perks">
+ {% for perk in candidate.perks %}
+ <div class="mayor-perk">
+ <h4{% if color %} style="color: {{ color }}"{% endif %}>{{ perk.name }}</h4>
+ <p>{{ perk.description|formattingCodeToHtml|safe }}</p>
+ </div>
+ {% endfor %}
+ </ul>
+ </div>
+ {% endfor %}
+</div> -->
+
+ <h2>
+ Previous election <span class="candidate-year">(Year {data.previous.year})</span>
+ </h2>
+ <div class="mayor-candidates">
+ {#each data.previous.candidates.sort((a, b) => b.votes - a.votes) as candidate}
+ {@const color = candidate.color ? colorCodes[candidate.color] : null}
+ <div class="mayor">
+ <div>
+ <h3 style={color ? `color: ${color}` : undefined}>{candidate.name}</h3>
+ <p class="mayor-vote-count">
+ <span class="mayor-vote-count-number" style={color ? `color: ${color}` : undefined}>
+ {candidate.votes.toLocaleString()}
+ </span> votes
+ </p>
+ {#if candidate.name == data.previous.winner}
+ <p class="mayor-winner">Winner</p>
+ {/if}
+ <MayorSkin name={candidate.name} />
+ </div>
+ <ul class="mayor-perks">
+ {#each candidate.perks as perk}
+ <div class="mayor-perk">
+ <h4 style={color ? `color: ${color}` : undefined}>{perk.name}</h4>
+ <p>{@html formattingCodeToHtml(perk.description)}</p>
+ </div>
+ {/each}
+ </ul>
+ </div>
+ {/each}
+ </div>
+
+ <!-- {%- set nextSpecialMayorYear = (((data.current.year or data.previous.year) + 1) / 8)|round(0, 'ceil') * 8 -%}
+ {%- set specialMayors = ['Scorpius', 'Derpy', 'Jerry'] -%}
+ <h2>Upcoming special mayors</h2>
+ <ul>
+ {%- for i in range(3) -%}
+ <li><b>{{ specialMayors[((nextSpecialMayorYear / 8) + i) % 3] }}</b> <span class="next-special-mayor-time">({{ skyblockYear(nextSpecialMayorYear + 8 * i, 6, 27) }})</span></li>
+ {%- endfor -%}
+ </ul> -->
+
+ <h2>Upcoming special mayors</h2>
+ <ul>
+ <!-- for i in range(3) -->
+ {#each Array(3) as _, i}
+ <li>
+ <b>{specialMayors[(nextSpecialMayorYear / 8 + i) % 3]}</b>
+ <span class="next-special-mayor-time">
+ ({millisecondsToTime(skyblockTime(nextSpecialMayorYear + 8 * i + 1, 3, 27) - Date.now())})
+ </span>
+ </li>
+ {/each}
+ </ul>
+</main>
+
+<style>
+ .mayor-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-column-gap: 1em;
+ grid-row-gap: 1em;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ }
+ .mayor {
+ display: inline-block;
+ width: 12em;
+ margin-right: 1em;
+ vertical-align: top;
+ }
+ .mayor h3 {
+ filter: brightness(1.5);
+ text-align: center;
+ }
+ .mayor img {
+ display: block;
+ width: 5em;
+ margin: 0 auto;
+ }
+ .mayor-vote-count-number {
+ filter: brightness(1.2);
+ }
+ .mayor-vote-count {
+ text-align: center;
+ width: 100%;
+ margin: 0 0 0.5em 0;
+ }
+ .mayor-perk h4 {
+ margin-bottom: 0;
+ }
+ .mayor-perk p {
+ margin: 0;
+ }
+ .mayor-candidates {
+ /* display: ; */
+ /* everything next to each other */
+ /* grid-template-columns: repeat(5, 1fr); */
+ max-width: fit-content;
+ }
+ .mayor-perks {
+ list-style-type: none;
+ padding: 0;
+ }
+ .candidate-year {
+ font-weight: normal;
+ color: var(--theme-darker-text);
+ }
+ .mayor-winner {
+ color: var(--theme-yellow);
+ font-weight: bold;
+ margin: 0;
+ text-align: center;
+ font-size: 1em;
+ }
+ .next-special-mayor-time {
+ color: var(--theme-darker-text);
+ }
+ .election-ends-in-text {
+ margin-top: 0;
+ }
+ .next-mayor-update {
+ float: right;
+ color: var(--theme-darker-text);
+ }
+ .next-mayor-update p {
+ margin: 0;
+ }
+</style>
diff --git a/src/routes/index.svelte b/src/routes/index.svelte
index 086c7fb..6f6bae1 100644
--- a/src/routes/index.svelte
+++ b/src/routes/index.svelte
@@ -30,8 +30,8 @@
<hr style="margin: 25vh 0 2em 0" />
<section>
- <h3>Other SkyBlock tools</h3>
- <ul>
+ <h2>Other SkyBlock tools</h2>
+ <ul id="other-tools-list">
<li><a>Auction prices (coming soon)</a></li>
<li><a href="/leaderboards">Leaderboards</a></li>
<li><a>Bazaar (coming soon)</a></li>
@@ -88,4 +88,8 @@
#donators p {
margin: 0;
}
+
+ li {
+ padding: 0.2em 0;
+ }
</style>