Files

76 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Desk calendar: a dial clock that turns once per in-game day, the date, term progress, next
// decision dates, the brass speed controls and the way into the menu.
import { t, dateParts } from "../i18n/i18n.js";
import { dateOfDay } from "../engine/index.js";
import { $, dialSvg, setDial } from "./desk.js";
export function createCalendar(root, bal, { onSpeed, onMenu }) {
const speeds = bal.time.speeds;
root.innerHTML = `
<div class="cal__head"><span class="cal__weekday"></span></div>
<div class="cal__body">
<div class="cal__top">
${dialSvg("cal__dial")}
<div class="cal__date">
<div class="cal__day"></div>
<div class="cal__month"></div>
</div>
</div>
<div class="cal__count"></div>
<div class="cal__term"><span></span></div>
<dl class="cal__next">
<dt>${t("cal.briefing")}</dt><dd data-next="briefing"></dd>
<dt>${t("cal.review")}</dt><dd data-next="review"></dd>
</dl>
<div class="cal__controls">
<button class="brass" data-speed="0" title="${t("cal.pause")}" aria-label="${t("cal.pause")}">II</button>
${speeds.map((s) => `<button class="brass" data-speed="${s}" aria-label="${t("cal.speed", { n: s })}">${s}×</button>`).join("")}
</div>
<button class="brass cal__menu" data-menu>${t("cal.menu")}</button>
</div>`;
root.addEventListener("click", (e) => {
const b = e.target.closest("button");
if (!b) return;
if (b.dataset.menu !== undefined) onMenu();
else onSpeed(Number(b.dataset.speed));
});
const until = (day, every) => (every - (day % every)) % every;
const when = (n) => {
if (n === 0) return t("cal.today");
return n === 1 ? t("cal.tomorrow") : t("cal.inDays", { n });
};
const dial = $(root, ".cal__dial");
let lastDay = -1;
function update(state) {
const p = dateParts(dateOfDay(state.startDate, state.day).iso);
$(root, ".cal__weekday").textContent = p.weekday;
const dayEl = $(root, ".cal__day");
dayEl.textContent = p.day;
if (lastDay >= 0 && state.day !== lastDay && state.speed > 0 && state.speed <= 2) {
dayEl.classList.remove("is-flip");
void dayEl.offsetWidth; // restart the animation
dayEl.classList.add("is-flip");
}
lastDay = state.day;
$(root, ".cal__month").textContent = `${p.month} ${p.year}`;
const shown = Math.min(state.day + 1, bal.time.termDays);
$(root, ".cal__count").textContent = t("cal.dayCount", { day: shown, total: bal.time.termDays });
$(root, ".cal__term span").style.width = `${(state.day / bal.time.termDays) * 100}%`;
const over = Boolean(state.over);
$(root, '[data-next="briefing"]').textContent = over ? "–" : when(until(state.day, bal.time.daysPerWeek));
$(root, '[data-next="review"]').textContent = over ? "–" : when(state.pending.review ? 0 : until(state.day, bal.time.daysPerQuarter));
for (const b of root.querySelectorAll("button[data-speed]")) {
b.setAttribute("aria-pressed", String(Number(b.dataset.speed) === state.speed));
}
}
return { update, clockHand: (progress) => setDial(dial, progress) };
}