(() => { // Have Footer always be just slightly out of view { const footerWrapper = document.querySelector('div.wrapper-footer') if (footerWrapper) { footerWrapper.style.marginTop = Math.max( document.documentElement.clientHeight - (document.body.clientHeight - footerWrapper.clientHeight), 0 ) + 'px' } } // Navigation Bar - Profile // Cache for this is invalidated and updated by another script { interface MinimalProfileResponse { id: number; avatar: string | null; } let loggedIn = true const profileButton = document.querySelector('a#navigation-profile')! const profileCache = sessionStorage.getItem('cache_profile') profileCache ? UpdateProfile(JSON.parse(profileCache)) : FetchProfile() /** Redirect to profile if logged in, otherwise prompt login */ profileButton.addEventListener('click', () => loggedIn ? window.location.assign('/profile') : window.location.assign('/login') ) /** Update Profile Elements */ function UpdateProfile(data: undefined | MinimalProfileResponse) { if (data === undefined) return loggedIn = false profileButton.style.backgroundImage = `url('${ImageURL('avatars', data.id, data.avatar, true, "small")}')` } /** Fetch Profile from API */ function FetchProfile() { CallAPI('GET', '/v1/users/@me', 'basic').then(resp => { if (resp.ok) { sessionStorage.setItem('cache_profile', resp.body) UpdateProfile(resp.json) } else { UpdateProfile(undefined) console.error(`[PROFILE] Fetch Failed`, resp.error) } }) } } // Navigation Bar - Status // Fetches player count and server status from service every 5 minutes // TODO: Add random offset so traffic spike doesn't disintegrate the server lol { const CLASS_RED = 'status-red' const CLASS_YEL = 'status-yellow' const CLASS_GRN = 'status-green' const ELEMENT_DOT = document.querySelector('div#status-dot')! const ELEMENT_TXT = document.querySelector('p#status-text')! FetchStatus() /** Update Status Elements */ function UpdateStatus(status: undefined | { status: "online" | "degraded" | "down" | "none"; counter_players_online?: number; }) { for (const c of [CLASS_RED, CLASS_YEL, CLASS_GRN]) ELEMENT_DOT.classList.remove(c) if (status !== undefined) switch (status.status) { case "online": ELEMENT_DOT.classList.add(CLASS_GRN) ELEMENT_TXT.textContent = `Online • ${status.counter_players_online} players` break case "degraded": ELEMENT_DOT.classList.add(CLASS_YEL) ELEMENT_TXT.textContent = `Service Degraded • ${status.counter_players_online} players` break case "down": ELEMENT_DOT.classList.add(CLASS_RED) ELEMENT_TXT.textContent = 'Service Down' break case "none": ELEMENT_TXT.textContent = "Unknown" break } } /** Fetch Status from API */ function FetchStatus() { fetch(ENV_URLS.status + '/api/widget.json').then(async resp => { const REFRESH_IN = parseFloat(resp.headers.get('X-Refresh')!) * 1000 | 0 if (resp.status === 503) { setTimeout(FetchStatus, REFRESH_IN) return } else if (resp.status === 200) { UpdateStatus(await resp.json()) return } else { console.error(`[STATUS] Request Failed with Status Code ${resp.status}:`, await resp.text()) UpdateStatus({ status: "none" }) } }) } } })()