made tarot section more mobile friendly

This commit is contained in:
2026-03-28 17:31:45 -07:00
parent 60887b68a6
commit d47e63df6d
5 changed files with 918 additions and 65 deletions

View File

@@ -46,6 +46,7 @@
const config = {
resolveTarotCardImage: null,
resolveTarotCardThumbnail: null,
getActiveDeck: () => "",
getDisplayCardName: (card) => card?.name || "",
clearChildren: () => {},
normalizeTarotCardLookupName: (value) => String(value || "").trim().toLowerCase(),
@@ -610,6 +611,34 @@
houseImageObserver = null;
}
function isCompactHouseLayout() {
if (typeof window === "undefined") {
return false;
}
if (typeof window.matchMedia === "function") {
return window.matchMedia("(max-width: 900px)").matches;
}
return Number(window.innerWidth) <= 900;
}
function buildHouseCardDeckOptions(card) {
const deckId = String(config.getActiveDeck?.() || "").trim();
const trumpNumber = card?.arcana === "Major" && Number.isFinite(Number(card?.number))
? Number(card.number)
: undefined;
if (!deckId && !Number.isFinite(trumpNumber)) {
return null;
}
return {
...(deckId ? { deckId } : {}),
...(Number.isFinite(trumpNumber) ? { trumpNumber } : {})
};
}
function hydrateHouseCardImage(image) {
if (!(image instanceof HTMLImageElement)) {
return;
@@ -626,7 +655,7 @@
}
function getHouseImageObserver(elements) {
const root = elements?.tarotHouseOfCardsEl?.closest(".tarot-section-house-top") || null;
const root = elements?.tarotHouseViewEl || elements?.tarotHouseOfCardsEl?.closest(".tarot-section-house-top") || null;
if (!root || typeof IntersectionObserver !== "function") {
return null;
}
@@ -659,6 +688,11 @@
return;
}
if (isCompactHouseLayout()) {
hydrateHouseCardImage(image);
return;
}
const observer = getHouseImageObserver(elements);
if (!observer) {
hydrateHouseCardImage(image);
@@ -685,6 +719,7 @@
const cardDisplayName = config.getDisplayCardName(card);
const label = buildHouseCardLabel(card);
const showImage = isHouseCardImageVisible(card);
const deckOptions = buildHouseCardDeckOptions(card);
const labelText = label?.secondary
? `${label.primary} - ${label.secondary}`
: label?.primary || "";
@@ -692,8 +727,11 @@
button.setAttribute("aria-label", labelText ? `${cardDisplayName || card.name}, ${labelText}` : (cardDisplayName || card.name));
button.dataset.houseCardId = card.id;
const imageUrl = typeof config.resolveTarotCardThumbnail === "function"
? config.resolveTarotCardThumbnail(card.name)
: (typeof config.resolveTarotCardImage === "function" ? config.resolveTarotCardImage(card.name) : null);
? config.resolveTarotCardThumbnail(card.name, deckOptions || undefined)
: (typeof config.resolveTarotCardImage === "function" ? config.resolveTarotCardImage(card.name, deckOptions || undefined) : null);
const fullImageUrl = typeof config.resolveTarotCardImage === "function"
? config.resolveTarotCardImage(card.name, deckOptions || undefined)
: imageUrl;
if (showImage && imageUrl) {
const image = document.createElement("img");
@@ -704,11 +742,19 @@
image.decoding = "async";
image.fetchPriority = config.isHouseFocusMode?.() === true ? "auto" : "low";
image.dataset.src = imageUrl;
image.dataset.fullSrc = fullImageUrl || imageUrl;
image.addEventListener("load", () => {
image.classList.remove("is-loading");
image.classList.add("is-loaded");
}, { once: true });
image.addEventListener("error", () => {
const fallbackSrc = String(image.dataset.fullSrc || "").trim();
if (fallbackSrc && fallbackSrc !== image.currentSrc && image.dataset.fullImageTried !== "true") {
image.dataset.fullImageTried = "true";
image.dataset.imageHydrated = "true";
image.src = fallbackSrc;
return;
}
image.classList.remove("is-loading");
image.classList.remove("is-loaded");
image.dataset.imageHydrated = "false";