import { LitElement, ReactiveController, ReactiveControllerHost, css, html, render } from "lit"; const terranMonthIntervals = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; const pendorMonthIntervals = [0, 1, 25, 49, 73, 97, 121, 145, 146, 147, 171, 195, 211, 243, 267, 291, 292]; const pendorMonthNames = [ "Yestar", "Narrin", "Nenim", "Sulim", "Virta", "Lothess", "Narnya", "Attendes", "Loende", "Cerim", "Urim", "Yavar", "Narquel", "Hiss", "Ring", "Mettare", ]; const pendorWeekdayNames = ["Seren", "Anar", "Noren", "Aldea", "Erwer", "Elenya"]; const prefix = (n: number) => `${n < 10 ? "0" : ""}${n.toFixed(0)}`; export class ClockController implements ReactiveController { host: ReactiveControllerHost; value = new Date(); timeout: number; // Node and the DOM do not agree on the type. Grrr. // eslint-disable-next-line @typescript-eslint/no-explicit-any private _timerID?: any; constructor(host: ReactiveControllerHost, timeout = 1000) { (this.host = host).addController(this); this.timeout = timeout; } hostConnected() { this._timerID = setInterval(() => { this.value = new Date(); this.host.requestUpdate(); }, this.timeout); } hostDisconnected() { clearInterval(this._timerID); this._timerID = undefined; } } const styles = css` *, *::before, *::after { all: unset; display: revert; box-sizing: border-box; } :host { padding-top: 0; letter-spacing: 1px; --default-font-size: calc(clamp(0.63rem, calc(0.5rem + 0.63vw), 0.9rem)); font-family: Bitwise, Audiowide, Tahoma, Arial, Helvetica, sans-serif; flex: 0 1 auto; text-align: left; } div#clock { padding: 0.175rem 0.375rem 0.175rem 0.375rem; background-color: var(--pendorclock-background-color, #000030); color: var(--pendorclock-color, #ffffff); font-size: var(--pendorclock-font-size, --default-font-size); line-height: var(--pendorclock-line-height, 1.35); font-weight: var(--pendorclock-font-weight, 700); min-width: 20ch; max-width: 35ch; text-align: center; } `; const fontStyle = css` @font-face { font-family: "Audiowide"; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/audiowide/v20/l7gdbjpo0cum0ckerWCdlg_O.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } `; export class PendorClock extends LitElement { static get styles() { return styles; } clock: ClockController; constructor() { super(); this.clock = new ClockController(this, 250); } connectedCallback() { super.connectedCallback(); if (document.getElementById("pendor-font-block")) { return; } const head = document.head || document.getElementsByTagName("head")[0]; const style = html``; render(style, head); } tick(now: Date) { let hours = terranMonthIntervals[now.getMonth()] + now.getDate(); if (now.getMonth() > 2 && now.getFullYear() % 4 == 0) { hours++; } // DST Calculation, and wildly wrong, but WTF hours = hours * 24 + now.getHours() - 16; const year = now.getFullYear() + 16; const dayOfYear = hours / 30; hours = hours % 30; let seconds = (now.getSeconds() + now.getMinutes() * 60) / 2.25; const minutes = seconds / 40; seconds = seconds % 40; const timePart = `${hours.toFixed(0)}:${prefix(minutes)}:${prefix(seconds)}`; const nextMonth = pendorMonthIntervals.findIndex(i => i >= dayOfYear); if (nextMonth === undefined || pendorMonthIntervals[nextMonth - 1] === undefined) { return undefined; } const dayOfMonth = dayOfYear - pendorMonthIntervals[nextMonth - 1]; const dayOfWeek = (Math.ceil(dayOfMonth) - 1) % 6; return `${pendorWeekdayNames[dayOfWeek]}, ${pendorMonthNames[nextMonth - 1]} ${dayOfMonth.toFixed( 0 )}, 00${year.toFixed(0)}, ${timePart}`; } render() { return html`
${this.tick(this.clock.value)}
`; } }