131 lines
3.5 KiB
TypeScript
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);
|
|
|