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 +- .../fonts/atkinson-hyperlegible/latin-bold.woff2 | Bin 0 -> 16836 bytes .../atkinson-hyperlegible/latin-ext-bold.woff2 | Bin 0 -> 8548 bytes .../latin-ext-italic-bold.woff2 | Bin 0 -> 8976 bytes .../atkinson-hyperlegible/latin-ext-italic.woff2 | Bin 0 -> 8796 bytes static/fonts/atkinson-hyperlegible/latin-ext.woff2 | Bin 0 -> 8424 bytes .../atkinson-hyperlegible/latin-italic-bold.woff2 | Bin 0 -> 17808 bytes .../fonts/atkinson-hyperlegible/latin-italic.woff2 | Bin 0 -> 17544 bytes static/fonts/atkinson-hyperlegible/latin.woff2 | Bin 0 -> 16464 bytes 13 files changed, 379 insertions(+), 14 deletions(-) create mode 100644 src/lib/MayorSkin.svelte create mode 100644 src/routes/election.svelte create mode 100644 static/fonts/atkinson-hyperlegible/latin-bold.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin-ext-bold.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin-ext-italic-bold.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin-ext-italic.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin-ext.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin-italic-bold.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin-italic.woff2 create mode 100644 static/fonts/atkinson-hyperlegible/latin.woff2 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 @@ + + +Mayor {toTitleCase(name)} + + 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 candidate.perks as perk} +
    +

    {perk.name}

    +

    {@html formattingCodeToHtml(perk.description)}

    +
    + {/each} +
+
+ {/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 candidate.perks as perk} +
    +

    {perk.name}

    +

    {@html formattingCodeToHtml(perk.description)}

    +
    + {/each} +
+
+ {/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 @@
-

Other SkyBlock tools

-
    +

    Other SkyBlock tools

    +
    • Auction prices (coming soon)
    • Leaderboards
    • Bazaar (coming soon)
    • @@ -88,4 +88,8 @@ #donators p { margin: 0; } + + li { + padding: 0.2em 0; + } diff --git a/static/fonts/atkinson-hyperlegible/latin-bold.woff2 b/static/fonts/atkinson-hyperlegible/latin-bold.woff2 new file mode 100644 index 0000000..6d8457a Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-bold.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin-ext-bold.woff2 b/static/fonts/atkinson-hyperlegible/latin-ext-bold.woff2 new file mode 100644 index 0000000..b139a5a Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-ext-bold.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin-ext-italic-bold.woff2 b/static/fonts/atkinson-hyperlegible/latin-ext-italic-bold.woff2 new file mode 100644 index 0000000..7490f67 Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-ext-italic-bold.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin-ext-italic.woff2 b/static/fonts/atkinson-hyperlegible/latin-ext-italic.woff2 new file mode 100644 index 0000000..e579847 Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-ext-italic.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin-ext.woff2 b/static/fonts/atkinson-hyperlegible/latin-ext.woff2 new file mode 100644 index 0000000..95cc0cf Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-ext.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin-italic-bold.woff2 b/static/fonts/atkinson-hyperlegible/latin-italic-bold.woff2 new file mode 100644 index 0000000..1ac3456 Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-italic-bold.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin-italic.woff2 b/static/fonts/atkinson-hyperlegible/latin-italic.woff2 new file mode 100644 index 0000000..f5f51ea Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin-italic.woff2 differ diff --git a/static/fonts/atkinson-hyperlegible/latin.woff2 b/static/fonts/atkinson-hyperlegible/latin.woff2 new file mode 100644 index 0000000..3f1bcc8 Binary files /dev/null and b/static/fonts/atkinson-hyperlegible/latin.woff2 differ -- cgit