dominoclock/src/index.ts

131 lines
3.5 KiB
TypeScript

type Times = number[];
type Cats = [string, Times]
const MATRIX: Cats[] = [["o0", [1, 5, 8, 9, 11]],
["o1", [2, 5, 6, 10, 11]],
["o2", [3, 6, 7, 9, 11]],
["o3", [4, 7, 8, 10, 11]]];
const TEMPLATE = `
<style>
.dominoclock {
display: flex;
flex-direction: var(--dominoclock-direction, row);
}
.face {
position: relative;
width: var(--dominoclock-size, 5rem);
height: var(--dominoclock-size, 5rem);
background-color: var(--dominoclock-background, #daaf20);
border: 1px solid #282828;
border-radius: var(--domino-clock-borderradius, 0.5rem);
}
.face:not(:last-child) {
margin-right: 0.25rem;
}
.dot {
position: absolute;
width: var(--dominoclock-dot-size, 1rem);
height: var(--dominoclock-dot-size, 1rem);
background-color: var(--dominoclock-dot-color, #2f4f4f);
transition: opacity 0.3s ease;
border-radius: calc(var(--dominoclock-dot-size, 1rem) / 2);
opacity: 0;
}
.o0 {
top: var(--dominoclock-dot-size, 1rem);
left: var(--dominoclock-dot-size, 1rem);
}
.o1 {
top: var(--dominoclock-dot-size, 1rem);
left: calc(3 * var(--dominoclock-dot-size, 1rem));
}
.o2 {
top: calc(3 * var(--dominoclock-dot-size, 1rem));
left: calc(3 * var(--dominoclock-dot-size, 1rem));
}
.o3 {
top: calc(3 * var(--dominoclock-dot-size, 1rem));
left: var(--dominoclock-dot-size, 1rem);
}
</style>
<div class="dominoclock">
<div class="face" id="hours">
<div class="dot o0" ></div>
<div class="dot o1" ></div>
<div class="dot o2" ></div>
<div class="dot o3" ></div>
</div>
<div class="face" id="minutes">
<div class="dot o0" ></div>
<div class="dot o1" ></div>
<div class="dot o2" ></div>
<div class="dot o3" ></div>
</div>
<div class="face" id="seconds">
<div class="dot o0" ></div>
<div class="dot o1" ></div>
<div class="dot o2" ></div>
<div class="dot o3" ></div>
</div>
</div>
`;
type Face = "hours" | "minutes" | "seconds"
const isFace = (v: unknown): v is Face => {
if (typeof v === "string" && ["hours", "minutes", "seconds"].includes(v)) { return true; }
throw new Error(`Expected a Face, got ${v}`);
}
class DominoClock extends HTMLElement {
elements: { [K in Face]: HTMLDivElement };
timer: number;
constructor() {
super()
this.timer = 0;
this.innerHTML = TEMPLATE;
this.elements = Object.fromEntries(
Array.from(this.getElementsByTagName('div'))
.filter((element) => element.className === "face")
.map((element) => [isFace(element.id) && element.id, element]));
this.paint = this.paint.bind(this);
}
connectedCallback() {
this.timer = window.setTimeout(this.paint, 250)
}
tock(board: Face, time: number) {
const dots = Array.from(this.elements[board].getElementsByTagName('div'));
dots.forEach((element) => element.style.opacity = "0");
dots.forEach((element) => {
const row = MATRIX.find((i) => Array.from(element.classList).includes(i[0]));
if (!row) { console.log(`Didn't find a row for ${element.className}?`); return; }
if (row[1].includes(time)) {
element.style.opacity = "1"
}
});
}
paint() {
const now = new Date();
const rawHours = now.getHours();
const hours = rawHours > 12 ? rawHours - 12 : rawHours;
this.tock("hours", hours);
this.tock("minutes", Math.floor(now.getUTCMinutes() / 5));
this.tock("seconds", Math.floor(now.getUTCSeconds() / 5));
window.clearTimeout(this.timer);
this.timer = window.setTimeout(this.paint, 250);
}
}
customElements.define('domino-clock', DominoClock);