diff options
| author | mat <github@matdoes.dev> | 2022-03-05 16:04:50 -0600 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-03-05 16:04:50 -0600 |
| commit | f256a52e6a0a9ba478cde22d96c6292842247c01 (patch) | |
| tree | 6b45a452cb6f6de45318b2b9839313599edbfd5c /src/routes | |
| parent | 478b6ea8a50bbf372921990775d3fd480446f350 (diff) | |
| download | skyblock-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.svelte | 273 | ||||
| -rw-r--r-- | src/routes/index.svelte | 8 |
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> |
