updated frame for mobile

This commit is contained in:
2026-04-02 01:10:50 -07:00
parent 6c3100b5c9
commit e5d041101f
3 changed files with 85 additions and 11 deletions

View File

@@ -1135,6 +1135,7 @@
--frame-base-gap: clamp(2px, 0.3vw, 6px); --frame-base-gap: clamp(2px, 0.3vw, 6px);
--frame-gap: calc(var(--frame-base-gap) * var(--frame-grid-zoom-scale)); --frame-gap: calc(var(--frame-base-gap) * var(--frame-grid-zoom-scale));
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 14px; gap: 14px;
padding: 18px; padding: 18px;
border: 1px solid #27272a; border: 1px solid #27272a;
@@ -1152,7 +1153,8 @@
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 12px; gap: 12px;
min-width: max-content; min-width: 0;
flex-wrap: wrap;
} }
.tarot-frame-panel-title { .tarot-frame-panel-title {
@@ -1183,8 +1185,10 @@
} }
.tarot-frame-grid-viewport { .tarot-frame-grid-viewport {
width: 100%; width: min(100%, calc(100vw - 52px));
max-width: 100%; max-width: calc(100vw - 52px);
margin-left: auto;
margin-right: auto;
overflow: auto; overflow: auto;
overscroll-behavior: contain; overscroll-behavior: contain;
min-width: 0; min-width: 0;
@@ -1481,7 +1485,8 @@
} }
.tarot-frame-panel { .tarot-frame-panel {
--frame-base-cell-width: 26px; --frame-base-gap: 2px;
--frame-base-cell-width: min(26px, calc((100vw - 78px) / 14));
} }
.tarot-frame-card-badge { .tarot-frame-card-badge {

View File

@@ -991,7 +991,46 @@
return getCardOverlayDate(card) || formatMonthDay(getRelation(card, "decan")?.data?.dateStart) || getDisplayCardName(card); return getCardOverlayDate(card) || formatMonthDay(getRelation(card, "decan")?.data?.dateStart) || getDisplayCardName(card);
} }
function centerGridViewport() { function getOccupiedGridBounds(gridTrackEl) {
if (!(gridTrackEl instanceof HTMLElement)) {
return null;
}
const filledSlots = Array.from(gridTrackEl.querySelectorAll(".tarot-frame-slot:not(.is-empty-slot)"));
if (!filledSlots.length) {
return null;
}
const trackRect = gridTrackEl.getBoundingClientRect();
return filledSlots.reduce((bounds, slotEl) => {
if (!(slotEl instanceof HTMLElement)) {
return bounds;
}
const slotRect = slotEl.getBoundingClientRect();
const left = slotRect.left - trackRect.left;
const right = slotRect.right - trackRect.left;
if (!bounds) {
return { left, right };
}
return {
left: Math.min(bounds.left, left),
right: Math.max(bounds.right, right)
};
}, null);
}
function resetFrameSectionScroll() {
const sectionEl = document.getElementById("tarot-frame-section");
if (!(sectionEl instanceof HTMLElement)) {
return;
}
sectionEl.scrollTop = 0;
}
function centerGridViewport(attempt = 0) {
const { tarotFrameBoardEl } = getElements(); const { tarotFrameBoardEl } = getElements();
const gridViewportEl = tarotFrameBoardEl?.querySelector(".tarot-frame-grid-viewport"); const gridViewportEl = tarotFrameBoardEl?.querySelector(".tarot-frame-grid-viewport");
const gridTrackEl = tarotFrameBoardEl?.querySelector(".tarot-frame-grid-track"); const gridTrackEl = tarotFrameBoardEl?.querySelector(".tarot-frame-grid-track");
@@ -1004,16 +1043,44 @@
return; return;
} }
const overflowX = Math.max(0, gridTrackEl.offsetWidth - gridViewportEl.clientWidth); const contentWidth = gridTrackEl.scrollWidth || gridTrackEl.offsetWidth;
gridViewportEl.scrollLeft = overflowX > 0 ? overflowX / 2 : 0; const viewportWidth = gridViewportEl.clientWidth;
if (!contentWidth || !viewportWidth) {
if (attempt < 6) {
centerGridViewport(attempt + 1);
}
return;
}
const occupiedBounds = getOccupiedGridBounds(gridTrackEl);
const targetCenter = occupiedBounds
? (occupiedBounds.left + occupiedBounds.right) / 2
: contentWidth / 2;
const maxScrollLeft = Math.max(0, contentWidth - viewportWidth);
const targetScrollLeft = Math.min(Math.max(targetCenter - (viewportWidth / 2), 0), maxScrollLeft);
gridViewportEl.scrollLeft = targetScrollLeft;
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (!(gridViewportEl instanceof HTMLElement) || !(gridTrackEl instanceof HTMLElement)) { if (!(gridViewportEl instanceof HTMLElement) || !(gridTrackEl instanceof HTMLElement)) {
return; return;
} }
const nextOverflowX = Math.max(0, gridTrackEl.offsetWidth - gridViewportEl.clientWidth); const nextContentWidth = gridTrackEl.scrollWidth || gridTrackEl.offsetWidth;
gridViewportEl.scrollLeft = nextOverflowX > 0 ? nextOverflowX / 2 : 0; const nextViewportWidth = gridViewportEl.clientWidth;
if (!nextContentWidth || !nextViewportWidth) {
if (attempt < 6) {
centerGridViewport(attempt + 1);
}
return;
}
const nextOccupiedBounds = getOccupiedGridBounds(gridTrackEl);
const nextTargetCenter = nextOccupiedBounds
? (nextOccupiedBounds.left + nextOccupiedBounds.right) / 2
: nextContentWidth / 2;
const nextMaxScrollLeft = Math.max(0, nextContentWidth - nextViewportWidth);
const nextTargetScrollLeft = Math.min(Math.max(nextTargetCenter - (nextViewportWidth / 2), 0), nextMaxScrollLeft);
gridViewportEl.scrollLeft = nextTargetScrollLeft;
}); });
}); });
} }
@@ -2061,6 +2128,8 @@
await config.ensureTarotSection(referenceData, magickDataset); await config.ensureTarotSection(referenceData, magickDataset);
} }
resetFrameSectionScroll();
const cards = getCards(); const cards = getCards();
if (!cards.length) { if (!cards.length) {
setStatus("Tarot cards are still loading..."); setStatus("Tarot cards are still loading...");

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=20260402-frame-center-05"> <link rel="stylesheet" href="app/styles.css?v=20260402-frame-center-07">
</head> </head>
<body> <body>
<div class="topbar"> <div class="topbar">
@@ -1178,7 +1178,7 @@
<script src="app/ui-numbers-detail.js"></script> <script src="app/ui-numbers-detail.js"></script>
<script src="app/ui-numbers.js"></script> <script src="app/ui-numbers.js"></script>
<script src="app/ui-tarot-spread.js"></script> <script src="app/ui-tarot-spread.js"></script>
<script src="app/ui-tarot-frame.js?v=20260402-frame-center-05"></script> <script src="app/ui-tarot-frame.js?v=20260402-frame-mobile-center-06"></script>
<script src="app/ui-settings.js?v=20260309-gate"></script> <script src="app/ui-settings.js?v=20260309-gate"></script>
<script src="app/ui-chrome.js?v=20260328-topbar-settings-01"></script> <script src="app/ui-chrome.js?v=20260328-topbar-settings-01"></script>
<script src="app/ui-navigation.js?v=20260401-tarot-frame-01"></script> <script src="app/ui-navigation.js?v=20260401-tarot-frame-01"></script>