Repository navigation
Expand file tree
/
Copy pathscript.js
More file actions
117 lines (107 loc) · 3.92 KB
/
Copy pathscript.js
File metadata and controls
117 lines (107 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
function setupFlipCard(card) {
if (!card) return;
card.addEventListener("click", () => {
const flipped = card.classList.toggle("is-flipped");
card.setAttribute("aria-pressed", String(flipped));
card.setAttribute("aria-label", flipped ? "Turn the talisman to return to the face marked one" : "Turn the talisman to reveal the face marked zero");
const front = card.querySelector(".card-face--one");
const reverse = card.querySelector(".card-face--zero");
if (front) front.setAttribute("aria-hidden", String(flipped));
if (reverse) reverse.setAttribute("aria-hidden", String(!flipped));
});
}
setupFlipCard(document.querySelector("#hero-card"));
setupFlipCard(document.querySelector("#card-stage"));
const reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window && !window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target);
}
});
}, { threshold: 0.14 });
reveals.forEach((element) => observer.observe(element));
} else {
reveals.forEach((element) => element.classList.add("is-visible"));
}
const babelReader = document.querySelector("#babel-reader");
const babelCatalog = document.querySelector("#babel-catalog");
const babelLines = document.querySelector("#babel-lines");
const babelSource = document.querySelector("#babel-source");
const nextRoomButton = document.querySelector("#next-room");
const readerClockFill = document.querySelector("#reader-clock-fill");
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
let libraryPages = [];
let currentPageIndex = -1;
let roomTimer;
let roomTransitionTimer;
let isRoomTransitioning = false;
function restartReaderClock() {
if (!readerClockFill) return;
readerClockFill.classList.remove("is-running");
void readerClockFill.offsetWidth;
readerClockFill.classList.add("is-running");
}
function selectNextPage() {
if (libraryPages.length < 2) return 0;
let nextIndex = currentPageIndex;
while (nextIndex === currentPageIndex) {
nextIndex = Math.floor(Math.random() * libraryPages.length);
}
return nextIndex;
}
function renderLibraryPage(pageIndex) {
const page = libraryPages[pageIndex];
if (!page || !babelCatalog || !babelLines || !babelSource) return;
currentPageIndex = pageIndex;
babelCatalog.textContent = page.catalog;
babelSource.href = page.reference;
babelLines.replaceChildren(...page.lines.map((line) => {
const item = document.createElement("li");
item.textContent = line;
return item;
}));
restartReaderClock();
}
function scheduleNextRoom() {
window.clearTimeout(roomTimer);
roomTimer = window.setTimeout(transitionToNextRoom, 30000);
}
function transitionToNextRoom() {
if (!babelReader || libraryPages.length === 0 || isRoomTransitioning) return;
const nextIndex = selectNextPage();
if (reducedMotion) {
renderLibraryPage(nextIndex);
scheduleNextRoom();
return;
}
isRoomTransitioning = true;
babelReader.classList.add("is-departing");
window.clearTimeout(roomTransitionTimer);
roomTransitionTimer = window.setTimeout(() => {
renderLibraryPage(nextIndex);
babelReader.classList.remove("is-departing");
isRoomTransitioning = false;
}, 700);
scheduleNextRoom();
}
if (babelReader) {
fetch("library-pages.json")
.then((response) => {
if (!response.ok) throw new Error("The shelf could not be opened");
return response.json();
})
.then((pages) => {
libraryPages = pages;
renderLibraryPage(Math.floor(Math.random() * libraryPages.length));
scheduleNextRoom();
})
.catch(() => {
if (babelCatalog) babelCatalog.textContent = "The catalogue is momentarily out of reach.";
});
}
nextRoomButton?.addEventListener("click", () => {
transitionToNextRoom();
});