From f256a52e6a0a9ba478cde22d96c6292842247c01 Mon Sep 17 00:00:00 2001
From: mat
Date: Sat, 5 Mar 2022 16:04:50 -0600
Subject: mayors
---
src/lib/APITypes.d.ts | 25 +++++
src/lib/MayorSkin.svelte | 41 +++++++
src/lib/utils.ts | 46 ++++++--
src/routes/election.svelte | 273 +++++++++++++++++++++++++++++++++++++++++++++
src/routes/index.svelte | 8 +-
5 files changed, 379 insertions(+), 14 deletions(-)
create mode 100644 src/lib/MayorSkin.svelte
create mode 100644 src/routes/election.svelte
(limited to 'src')
diff --git a/src/lib/APITypes.d.ts b/src/lib/APITypes.d.ts
index 119e5b6..3a54cea 100644
--- a/src/lib/APITypes.d.ts
+++ b/src/lib/APITypes.d.ts
@@ -138,3 +138,28 @@ export interface Collection {
level: number
category: CollectionCategory
}
+
+export interface MayorPerk {
+ name: string
+ description: string
+}
+
+export interface Candidate {
+ name: string
+ perks: MayorPerk[]
+ votes: number
+ color: string | null
+}
+
+export interface ElectionData {
+ last_updated: number
+ previous: {
+ year: number
+ winner: string
+ candidates: Candidate[]
+ }
+ current: {
+ year: number
+ candidates: Candidate[]
+ } | null
+}
\ No newline at end of file
diff --git a/src/lib/MayorSkin.svelte b/src/lib/MayorSkin.svelte
new file mode 100644
index 0000000..c3a90ec
--- /dev/null
+++ b/src/lib/MayorSkin.svelte
@@ -0,0 +1,41 @@
+
+
+
+
+
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index aabd981..d6e8e13 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -81,28 +81,40 @@ function moveToEndOfId(word: string, thing: string) {
return thing
}
-export function millisecondsToTime(totalMilliseconds: number) {
+interface MillisecondsToTimeOpts {
+ parts: number
+}
+
+export function millisecondsToTime(totalMilliseconds: number, opts: MillisecondsToTimeOpts = { parts: 2 }) {
const totalSeconds = totalMilliseconds / 1000
const totalMinutes = totalSeconds / 60
const totalHours = totalMinutes / 60
const totalDays = totalHours / 24
const milliseconds = Math.floor(totalMilliseconds) % 1000
+
const seconds = Math.floor(totalSeconds) % 60
const minutes = Math.floor(totalMinutes) % 60
const hours = Math.floor(totalHours) % 24
const days = Math.floor(totalDays)
+
const stringUnits: string[] = []
- if (days > 1) stringUnits.push(`${days} days`)
- else if (days == 1) stringUnits.push(`${days} day`)
- if (hours > 1) stringUnits.push(`${hours} hours`)
- else if (hours == 1) stringUnits.push(`${hours} hour`)
- if (minutes > 1) stringUnits.push(`${minutes} minutes`)
- else if (minutes == 1) stringUnits.push(`${minutes} minute`)
- if (seconds > 1) stringUnits.push(`${seconds} seconds`)
- else if (seconds == 1) stringUnits.push(`${seconds} second`)
- if (milliseconds > 1) stringUnits.push(`${milliseconds} milliseconds`)
- else if (milliseconds == 1) stringUnits.push(`${milliseconds} millisecond`)
- return stringUnits.slice(0, 2).join(' and ')
+
+ if (totalDays > 1) stringUnits.push(`${days} days`)
+ else if (totalDays == 1) stringUnits.push(`${days} day`)
+ if (totalHours > 1) stringUnits.push(`${hours} hours`)
+ else if (totalHours == 1) stringUnits.push(`${hours} hour`)
+ if (totalMinutes > 1) stringUnits.push(`${minutes} minutes`)
+ else if (totalMinutes == 1) stringUnits.push(`${minutes} minute`)
+ if (totalSeconds > 1) stringUnits.push(`${seconds} seconds`)
+ else if (totalSeconds == 1) stringUnits.push(`${seconds} second`)
+ if (totalMilliseconds > 1) stringUnits.push(`${milliseconds} milliseconds`)
+ else if (totalMilliseconds == 1) stringUnits.push(`${milliseconds} millisecond`)
+ // comma separated, "and" before last
+
+ let partsCount = opts.parts
+ if (stringUnits.length < opts.parts) partsCount = stringUnits.length
+ if (partsCount === 1) return stringUnits[0]
+ return stringUnits.slice(0, partsCount - 1).join(', ') + ' and ' + stringUnits[partsCount - 1]
}
export function cleanId(id: string) {
@@ -171,4 +183,14 @@ export function formatNumberFromUnit(n: number, unit: null | 'date' | 'time' | s
default:
return `${n.toLocaleString()} ${unit}`
}
+}
+
+/** Get the milliseconds since epoch for a given SkyBlock date. The year, month, and day are 1 indexed. */
+export function skyblockTime(year: number, month = 1, day = 1) {
+ const sbEpoch = 1560275700000
+ let time = sbEpoch
+ if (year) time += 446400000 * (year)
+ if (month) time += 37200000 * (month - 1)
+ if (day) time += 1200000 * (day - 1)
+ return time
}
\ No newline at end of file
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 @@
+
+
+
+
+
+
+
+
+
+
+ Last API update:
+ {millisecondsToTime(currentTime - data.last_updated * 1000)}
+
+
+ Next API update:
+ {millisecondsToTime(currentTime - data.last_updated * 1000 + 10 * 60 * 1000)}
+
+
+ SkyBlock Mayor Election Status
+
+ Next election:
+ {millisecondsToTime(skyblockTime(data.previous.year + 1, 6, 27) - currentTime, { parts: 3 })}
+
+
+ {#if data.current}
+ Ongoing election (Year {data.current.year})
+
+ Ends in:
+ {millisecondsToTime(skyblockTime(data.previous.year + 1, 3, 27) - Date.now())}
+
+
+ {#each data.current.candidates.sort((a, b) => a.votes - b.votes) as candidate}
+ {@const color = candidate.color ? colorCodes[candidate.color] : null}
+
+
+
{candidate.name}
+
+
+ {candidate.votes.toLocaleString()}
+ votes
+
+
+
+
+
+ {/each}
+
+ {/if}
+
+
+
+
+ Previous election (Year {data.previous.year})
+
+
+ {#each data.previous.candidates.sort((a, b) => b.votes - a.votes) as candidate}
+ {@const color = candidate.color ? colorCodes[candidate.color] : null}
+
+
+
{candidate.name}
+
+
+ {candidate.votes.toLocaleString()}
+ votes
+
+ {#if candidate.name == data.previous.winner}
+
Winner
+ {/if}
+
+
+
+
+ {/each}
+
+
+
+
+ Upcoming special mayors
+
+
+ {#each Array(3) as _, i}
+ -
+ {specialMayors[(nextSpecialMayorYear / 8 + i) % 3]}
+
+ ({millisecondsToTime(skyblockTime(nextSpecialMayorYear + 8 * i + 1, 3, 27) - Date.now())})
+
+
+ {/each}
+
+
+
+
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 @@