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

@@ -2882,6 +2882,103 @@
gap: 14px; gap: 14px;
} }
@media (max-width: 900px) {
#tarot-house-view {
padding: 10px;
}
#tarot-house-view .tarot-house-card {
gap: 10px;
}
.tarot-house-card-head {
flex-direction: column;
align-items: stretch;
}
.tarot-house-card-actions {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: stretch;
gap: 8px;
}
.tarot-house-toggle,
.tarot-house-filter-group,
.tarot-house-action-btn {
width: 100%;
box-sizing: border-box;
}
.tarot-house-filter-group {
justify-content: flex-start;
}
.tarot-house-layout {
--tarot-house-card-gap: 2px;
--tarot-house-row-gap: 4px;
--tarot-house-section-gap: 8px;
--tarot-house-card-width: clamp(28px, calc((100vw - 56px) / 11), 42px);
--tarot-house-card-height: calc(var(--tarot-house-card-width) * 1.5);
width: 100%;
max-width: 100%;
}
.tarot-house-trumps {
overflow-x: visible;
}
.tarot-house-trump-row,
.tarot-house-bottom-grid {
width: 100%;
}
.tarot-house-bottom-grid {
justify-content: center;
}
.tarot-house-card-btn.is-selected {
transform: scale(1.08);
}
.tarot-house-card-label {
left: 2px;
right: 2px;
bottom: 2px;
padding: 2px 3px;
font-size: 6.5px;
line-height: 1.1;
}
.tarot-house-card-label-secondary {
margin-top: 1px;
font-size: 6px;
}
.tarot-house-card-text-face {
gap: 3px;
padding: 5px 4px;
}
.tarot-house-card-text-face.is-dense {
gap: 2px;
padding: 4px 3px;
}
.tarot-house-card-text-face.is-top-hebrew .tarot-house-card-text-primary {
font-size: 14px;
}
.tarot-house-card-text-primary {
font-size: 8px;
}
.tarot-house-card-text-secondary,
.tarot-house-card-fallback {
font-size: 6px;
}
}
/* ── Tarot Spread View ─────────────────────────────── */ /* ── Tarot Spread View ─────────────────────────────── */
#tarot-spread-view { #tarot-spread-view {
display: flex; display: flex;

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -293,8 +293,6 @@
tarotHouseBottomInfoMonthEl: document.getElementById("tarot-house-bottom-info-month"), tarotHouseBottomInfoMonthEl: document.getElementById("tarot-house-bottom-info-month"),
tarotHouseBottomInfoRulerEl: document.getElementById("tarot-house-bottom-info-ruler"), tarotHouseBottomInfoRulerEl: document.getElementById("tarot-house-bottom-info-ruler"),
tarotHouseBottomInfoDateEl: document.getElementById("tarot-house-bottom-info-date"), tarotHouseBottomInfoDateEl: document.getElementById("tarot-house-bottom-info-date"),
tarotHouseFocusToggleEl: document.getElementById("tarot-house-focus-toggle"),
tarotHouseExportEl: document.getElementById("tarot-house-export"),
tarotHouseExportWebpEl: document.getElementById("tarot-house-export-webp") tarotHouseExportWebpEl: document.getElementById("tarot-house-export-webp")
}; };
} }
@@ -568,16 +566,6 @@
setHouseBottomInfoCheckboxState(elements?.tarotHouseBottomInfoRulerEl, state.houseBottomInfoModes.ruler); setHouseBottomInfoCheckboxState(elements?.tarotHouseBottomInfoRulerEl, state.houseBottomInfoModes.ruler);
setHouseBottomInfoCheckboxState(elements?.tarotHouseBottomInfoDateEl, state.houseBottomInfoModes.date); setHouseBottomInfoCheckboxState(elements?.tarotHouseBottomInfoDateEl, state.houseBottomInfoModes.date);
if (elements?.tarotHouseFocusToggleEl) {
elements.tarotHouseFocusToggleEl.setAttribute("aria-pressed", state.houseFocusMode ? "true" : "false");
elements.tarotHouseFocusToggleEl.textContent = state.houseFocusMode ? "Show Full Tarot" : "Focus House";
}
if (elements?.tarotHouseExportEl) {
elements.tarotHouseExportEl.disabled = Boolean(state.houseExportInProgress);
elements.tarotHouseExportEl.textContent = state.houseExportInProgress ? "Exporting..." : "Export PNG";
}
if (elements?.tarotHouseExportWebpEl) { if (elements?.tarotHouseExportWebpEl) {
const supportsWebp = tarotHouseUi.isExportFormatSupported?.("webp") === true; const supportsWebp = tarotHouseUi.isExportFormatSupported?.("webp") === true;
elements.tarotHouseExportWebpEl.disabled = Boolean(state.houseExportInProgress) || !supportsWebp; elements.tarotHouseExportWebpEl.disabled = Boolean(state.houseExportInProgress) || !supportsWebp;
@@ -808,6 +796,7 @@
tarotHouseUi.init?.({ tarotHouseUi.init?.({
resolveTarotCardImage, resolveTarotCardImage,
resolveTarotCardThumbnail, resolveTarotCardThumbnail,
getActiveDeck,
getDisplayCardName, getDisplayCardName,
clearChildren, clearChildren,
normalizeTarotCardLookupName, normalizeTarotCardLookupName,
@@ -932,13 +921,6 @@
}); });
} }
if (elements.tarotHouseFocusToggleEl) {
elements.tarotHouseFocusToggleEl.addEventListener("click", () => {
state.houseFocusMode = !state.houseFocusMode;
syncHouseControls(elements);
});
}
if (elements.tarotHouseTopCardsVisibleEl) { if (elements.tarotHouseTopCardsVisibleEl) {
elements.tarotHouseTopCardsVisibleEl.addEventListener("change", () => { elements.tarotHouseTopCardsVisibleEl.addEventListener("change", () => {
state.houseTopCardsVisible = Boolean(elements.tarotHouseTopCardsVisibleEl.checked); state.houseTopCardsVisible = Boolean(elements.tarotHouseTopCardsVisibleEl.checked);
@@ -989,12 +971,6 @@
}); });
}); });
if (elements.tarotHouseExportEl) {
elements.tarotHouseExportEl.addEventListener("click", () => {
exportHouseOfCards(elements, "png");
});
}
if (elements.tarotHouseExportWebpEl) { if (elements.tarotHouseExportWebpEl) {
elements.tarotHouseExportWebpEl.addEventListener("click", () => { elements.tarotHouseExportWebpEl.addEventListener("click", () => {
exportHouseOfCards(elements, "webp"); exportHouseOfCards(elements, "webp");

View File

@@ -16,7 +16,7 @@
<link rel="stylesheet" href="node_modules/@fontsource/amiri/arabic-400.css"> <link rel="stylesheet" href="node_modules/@fontsource/amiri/arabic-400.css">
<link rel="stylesheet" href="node_modules/@fontsource/amiri/arabic-700.css"> <link rel="stylesheet" href="node_modules/@fontsource/amiri/arabic-700.css">
<link rel="stylesheet" href="node_modules/@fontsource/noto-naskh-arabic/arabic-400.css"> <link rel="stylesheet" href="node_modules/@fontsource/noto-naskh-arabic/arabic-400.css">
<link rel="stylesheet" href="app/styles.css?v=20260323-word-meta-01"> <link rel="stylesheet" href="app/styles.css?v=20260328-house-mobile-01">
</head> </head>
<body> <body>
<div class="topbar"> <div class="topbar">
@@ -368,8 +368,6 @@
<span>Date</span> <span>Date</span>
</label> </label>
</fieldset> </fieldset>
<button id="tarot-house-focus-toggle" class="tarot-house-action-btn" type="button" aria-pressed="false">Focus House</button>
<button id="tarot-house-export" class="tarot-house-action-btn" type="button">Export PNG</button>
<button id="tarot-house-export-webp" class="tarot-house-action-btn" type="button">Export WebP</button> <button id="tarot-house-export-webp" class="tarot-house-action-btn" type="button">Export WebP</button>
</div> </div>
</div> </div>
@@ -1039,8 +1037,8 @@
<script src="app/data-service.js?v=20260319-word-dictionary-01"></script> <script src="app/data-service.js?v=20260319-word-dictionary-01"></script>
<script src="app/calendar-events.js"></script> <script src="app/calendar-events.js"></script>
<script src="app/card-images.js?v=20260309-gate"></script> <script src="app/card-images.js?v=20260309-gate"></script>
<script src="app/ui-tarot-lightbox.js?v=20260312-compare-zoom-01"></script> <script src="app/ui-tarot-lightbox.js?v=20260328-mobile-compare-02"></script>
<script src="app/ui-tarot-house.js?v=20260312-house-cube-01"></script> <script src="app/ui-tarot-house.js?v=20260328-house-mobile-01"></script>
<script src="app/ui-tarot-relations.js"></script> <script src="app/ui-tarot-relations.js"></script>
<script src="app/ui-now-helpers.js?v=20260314-now-planets-grid-01"></script> <script src="app/ui-now-helpers.js?v=20260314-now-planets-grid-01"></script>
<script src="app/ui-now.js?v=20260314-now-planets-grid-01"></script> <script src="app/ui-now.js?v=20260314-now-planets-grid-01"></script>
@@ -1059,7 +1057,7 @@
<script src="app/ui-tarot-card-derivations.js?v=20260307b"></script> <script src="app/ui-tarot-card-derivations.js?v=20260307b"></script>
<script src="app/ui-tarot-detail.js?v=20260307b"></script> <script src="app/ui-tarot-detail.js?v=20260307b"></script>
<script src="app/ui-tarot-relation-display.js?v=20260307b"></script> <script src="app/ui-tarot-relation-display.js?v=20260307b"></script>
<script src="app/ui-tarot.js?v=20260312-house-cube-01"></script> <script src="app/ui-tarot.js?v=20260328-house-mobile-01"></script>
<script src="app/ui-planets-references.js"></script> <script src="app/ui-planets-references.js"></script>
<script src="app/ui-planets.js"></script> <script src="app/ui-planets.js"></script>
<script src="app/ui-cycles.js"></script> <script src="app/ui-cycles.js"></script>