Skip to content

Commit 71c6615

Browse files
committed
add extra js
1 parent cf4514c commit 71c6615

1 file changed

Lines changed: 224 additions & 0 deletions

File tree

assets/js/extra.js

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
function setupFlipCards() {
2+
const preciseInput = window.matchMedia(
3+
"(min-width: 769px) and (any-hover: hover) and (any-pointer: fine)",
4+
);
5+
let keyboardNavigation = false;
6+
7+
document.addEventListener(
8+
"keydown",
9+
(event) => {
10+
if (event.key === "Tab") keyboardNavigation = true;
11+
},
12+
true,
13+
);
14+
document.addEventListener(
15+
"pointerdown",
16+
() => {
17+
keyboardNavigation = false;
18+
},
19+
true,
20+
);
21+
22+
const cards = Array.from(document.querySelectorAll("[data-flip-card]"))
23+
.map((card) => {
24+
const front = card.querySelector(".flip-card-front");
25+
const back = card.querySelector(".flip-card-back");
26+
const openButton = card.querySelector(".flip-card-toggle");
27+
const closeButton = card.querySelector(".flip-card-back-toggle");
28+
if (!front || !back || !openButton || !closeButton) return null;
29+
30+
const cardTitle = card.querySelector(".flip-card-title")?.textContent.trim();
31+
32+
function setFlipped(flipped, moveFocus = false) {
33+
card.classList.toggle("is-flipped", flipped);
34+
openButton.setAttribute("aria-expanded", String(flipped));
35+
front.toggleAttribute("inert", flipped);
36+
back.toggleAttribute("inert", !flipped);
37+
front.setAttribute("aria-hidden", String(flipped));
38+
back.setAttribute("aria-hidden", String(!flipped));
39+
if (moveFocus) (flipped ? closeButton : openButton).focus();
40+
}
41+
42+
function setPreciseMode(enabled) {
43+
card.classList.toggle("precise-interaction", enabled);
44+
if (enabled) {
45+
openButton.setAttribute("tabindex", "-1");
46+
openButton.setAttribute("aria-hidden", "true");
47+
} else {
48+
openButton.removeAttribute("tabindex");
49+
openButton.removeAttribute("aria-hidden");
50+
}
51+
closeButton.disabled = enabled;
52+
closeButton.hidden = enabled;
53+
closeButton.setAttribute("aria-hidden", String(enabled));
54+
}
55+
56+
function configureKeyboardAccess() {
57+
if (preciseInput.matches) {
58+
card.tabIndex = 0;
59+
card.setAttribute("role", "group");
60+
card.setAttribute("aria-label", `${cardTitle || "Join option"} details`);
61+
card.setAttribute("aria-controls", back.id);
62+
} else {
63+
card.removeAttribute("tabindex");
64+
card.removeAttribute("role");
65+
card.removeAttribute("aria-label");
66+
card.removeAttribute("aria-controls");
67+
}
68+
setPreciseMode(preciseInput.matches);
69+
setFlipped(false);
70+
}
71+
72+
openButton.addEventListener("click", () => setFlipped(true, true));
73+
closeButton.addEventListener("click", () => setFlipped(false, true));
74+
75+
card.addEventListener("pointerenter", (event) => {
76+
if (event.pointerType === "mouse") {
77+
setPreciseMode(true);
78+
setFlipped(true);
79+
}
80+
});
81+
82+
card.addEventListener("pointerdown", (event) => {
83+
if (event.pointerType !== "mouse") setPreciseMode(false);
84+
});
85+
86+
card.addEventListener("pointerleave", (event) => {
87+
if (event.pointerType === "mouse" && !card.contains(document.activeElement)) {
88+
setFlipped(false);
89+
setPreciseMode(preciseInput.matches);
90+
}
91+
});
92+
93+
card.addEventListener("focusin", () => {
94+
if (keyboardNavigation && preciseInput.matches) {
95+
setPreciseMode(true);
96+
setFlipped(true);
97+
}
98+
});
99+
100+
card.addEventListener("focusout", () => {
101+
window.requestAnimationFrame(() => {
102+
if (!card.contains(document.activeElement)) {
103+
setFlipped(false);
104+
setPreciseMode(preciseInput.matches);
105+
}
106+
});
107+
});
108+
109+
card.addEventListener("keydown", (event) => {
110+
if (card.classList.contains("precise-interaction") && event.key === "Escape") {
111+
event.preventDefault();
112+
setFlipped(false);
113+
}
114+
});
115+
116+
return { configureKeyboardAccess };
117+
})
118+
.filter(Boolean);
119+
120+
function configureCards() {
121+
cards.forEach(({ configureKeyboardAccess }) => configureKeyboardAccess());
122+
}
123+
124+
preciseInput.addEventListener("change", configureCards);
125+
configureCards();
126+
}
127+
128+
function setupArticleSorting() {
129+
const select = document.getElementById("sort-select");
130+
const grid = document.getElementById("articleGrid");
131+
if (!select || !grid) return;
132+
133+
const comparators = {
134+
"date-desc": (a, b) => b.dataset.date.localeCompare(a.dataset.date),
135+
"date-asc": (a, b) => a.dataset.date.localeCompare(b.dataset.date),
136+
type: (a, b) => a.dataset.type.localeCompare(b.dataset.type),
137+
title: (a, b) => a.dataset.title.localeCompare(b.dataset.title),
138+
};
139+
140+
function sortArticles() {
141+
const cards = Array.from(grid.querySelectorAll(".article-card"));
142+
cards.sort(comparators[select.value] || comparators["date-desc"]);
143+
cards.forEach((card) => grid.appendChild(card));
144+
}
145+
146+
select.addEventListener("change", sortArticles);
147+
sortArticles();
148+
}
149+
150+
function setupDebris() {
151+
const debrisElements = document.querySelectorAll("[data-debris]");
152+
if (!debrisElements.length) return;
153+
154+
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
155+
const startY = 20;
156+
const travelDistance = 140;
157+
158+
function updateDebris() {
159+
debrisElements.forEach((debris) => {
160+
const scaleValue = Number.parseFloat(debris.dataset.scale);
161+
const scale = Number.isFinite(scaleValue) && scaleValue > 0 ? scaleValue : 1;
162+
163+
if (reduceMotion.matches) {
164+
debris.style.transform = `scale(${scale})`;
165+
return;
166+
}
167+
168+
const card = debris.closest(".games-content-part");
169+
if (!card) return;
170+
171+
const rect = card.getBoundingClientRect();
172+
const progress = Math.min(
173+
1,
174+
Math.max(0, (window.innerHeight - rect.top) / (window.innerHeight + rect.height)),
175+
);
176+
const translateY = startY - travelDistance * progress;
177+
178+
debris.style.transform = `translateY(${translateY}%) scale(${scale})`;
179+
});
180+
}
181+
182+
let ticking = false;
183+
function onScroll() {
184+
if (reduceMotion.matches || ticking) return;
185+
186+
window.requestAnimationFrame(() => {
187+
updateDebris();
188+
ticking = false;
189+
});
190+
ticking = true;
191+
}
192+
193+
window.addEventListener("scroll", onScroll);
194+
window.addEventListener("resize", updateDebris);
195+
window.addEventListener("load", updateDebris);
196+
reduceMotion.addEventListener("change", updateDebris);
197+
updateDebris();
198+
}
199+
200+
function setupReadMore() {
201+
const grid = document.getElementById("readMoreGrid");
202+
const button = document.getElementById("readMoreBtn");
203+
if (!grid || !button) return;
204+
205+
const step = Number.parseInt(button.dataset.step, 10) || 16;
206+
207+
function revealNext() {
208+
const hidden = Array.from(grid.querySelectorAll(".read-more-item.is-hidden"));
209+
hidden.slice(0, step).forEach((item) => item.classList.remove("is-hidden"));
210+
211+
if (!grid.querySelector(".read-more-item.is-hidden")) {
212+
button.hidden = true;
213+
}
214+
}
215+
216+
button.addEventListener("click", revealNext);
217+
}
218+
219+
document.addEventListener("DOMContentLoaded", () => {
220+
setupFlipCards();
221+
setupArticleSorting();
222+
setupReadMore();
223+
setupDebris();
224+
});

0 commit comments

Comments
 (0)