updated frame for more mobile friendly usage

This commit is contained in:
2026-04-04 12:15:52 -07:00
parent aa4572668e
commit b7747794da
3 changed files with 81 additions and 3 deletions

View File

@@ -1260,6 +1260,8 @@
--frame-cell-height: calc(var(--frame-cell-width) * 1.5); --frame-cell-height: calc(var(--frame-cell-width) * 1.5);
--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));
--frame-pan-cushion-inline: calc(clamp(14px, 1.8vw, 26px) * var(--frame-grid-zoom-scale));
--frame-pan-cushion-block: calc(clamp(18px, 2.4vw, 34px) * var(--frame-grid-zoom-scale));
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr);
gap: 12px; gap: 12px;
@@ -1431,8 +1433,14 @@
.tarot-frame-grid-track { .tarot-frame-grid-track {
width: max-content; width: max-content;
min-width: max-content; min-width: max-content;
padding:
var(--frame-pan-cushion-block)
var(--frame-pan-cushion-inline)
calc(var(--frame-pan-cushion-block) * 1.45)
var(--frame-pan-cushion-inline);
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
box-sizing: border-box;
} }
.tarot-frame-legend { .tarot-frame-legend {

View File

@@ -59,6 +59,7 @@
const HOUSE_BOTTOM_INFO_MODE_IDS = ["zodiac", "decan", "month", "ruler", "date"]; const HOUSE_BOTTOM_INFO_MODE_IDS = ["zodiac", "decan", "month", "ruler", "date"];
const FRAME_LONG_PRESS_DELAY_MS = 460; const FRAME_LONG_PRESS_DELAY_MS = 460;
const FRAME_LONG_PRESS_MOVE_TOLERANCE = 10; const FRAME_LONG_PRESS_MOVE_TOLERANCE = 10;
const FRAME_TOUCH_DRAG_ACTIVATION_DELAY_MS = 140;
const EXPORT_SLOT_WIDTH = 120; const EXPORT_SLOT_WIDTH = 120;
const EXPORT_SLOT_HEIGHT = Math.round((EXPORT_SLOT_WIDTH * TAROT_CARD_HEIGHT_RATIO) / TAROT_CARD_WIDTH_RATIO); const EXPORT_SLOT_HEIGHT = Math.round((EXPORT_SLOT_WIDTH * TAROT_CARD_HEIGHT_RATIO) / TAROT_CARD_WIDTH_RATIO);
const EXPORT_CARD_INSET = 0; const EXPORT_CARD_INSET = 0;
@@ -836,6 +837,23 @@
return viewportEl instanceof HTMLElement ? viewportEl : null; return viewportEl instanceof HTMLElement ? viewportEl : null;
} }
function isLayoutNoteTextarea(element) {
return element instanceof HTMLTextAreaElement && element.id === "tarot-frame-layout-note";
}
function blurLayoutNoteForBoardInteraction(target) {
const activeElement = document.activeElement;
if (!isLayoutNoteTextarea(activeElement)) {
return;
}
if (target instanceof Node && target === activeElement) {
return;
}
activeElement.blur();
}
function updateViewportInteractionState() { function updateViewportInteractionState() {
const viewportEl = getGridViewportElement(); const viewportEl = getGridViewportElement();
if (!(viewportEl instanceof HTMLElement)) { if (!(viewportEl instanceof HTMLElement)) {
@@ -1369,6 +1387,7 @@
return; return;
} }
removeOrphanedDragGhosts();
startPanGesture(null, { startPanGesture(null, {
source: "touch", source: "touch",
startX: anchor.x, startX: anchor.x,
@@ -1386,6 +1405,7 @@
return; return;
} }
removeOrphanedDragGhosts();
clearLongPressGesture(); clearLongPressGesture();
if (state.drag) { if (state.drag) {
cleanupDrag(); cleanupDrag();
@@ -1457,6 +1477,8 @@
} }
function handleBoardTouchStart(event) { function handleBoardTouchStart(event) {
blurLayoutNoteForBoardInteraction(event.target);
if (event.touches.length >= 3) { if (event.touches.length >= 3) {
startTouchPanGesture(event); startTouchPanGesture(event);
return; return;
@@ -3123,6 +3145,15 @@
setHoverSlot(nextSlotId && nextSlotId !== sourceSlotId ? nextSlotId : ""); setHoverSlot(nextSlotId && nextSlotId !== sourceSlotId ? nextSlotId : "");
} }
function removeOrphanedDragGhosts() {
document.querySelectorAll(".tarot-frame-drag-ghost").forEach((ghostEl) => {
if (ghostEl instanceof HTMLElement) {
ghostEl.remove();
}
});
document.body.classList.remove("is-tarot-frame-dragging");
}
function detachPointerListeners() { function detachPointerListeners() {
document.removeEventListener("pointermove", handlePointerMove); document.removeEventListener("pointermove", handlePointerMove);
document.removeEventListener("pointerup", handlePointerUp); document.removeEventListener("pointerup", handlePointerUp);
@@ -3131,6 +3162,7 @@
function cleanupDrag() { function cleanupDrag() {
if (!state.drag) { if (!state.drag) {
removeOrphanedDragGhosts();
return; return;
} }
@@ -3151,10 +3183,25 @@
} }
state.drag = null; state.drag = null;
document.body.classList.remove("is-tarot-frame-dragging"); removeOrphanedDragGhosts();
detachPointerListeners(); detachPointerListeners();
} }
function handleDocumentTouchStart(event) {
if (Number(event.touches?.length || 0) < 2) {
return;
}
clearLongPressGesture();
if (state.drag?.pointerType === "touch") {
cleanupDrag();
state.suppressClick = true;
return;
}
removeOrphanedDragGhosts();
}
function swapOrMoveSlots(sourceSlotId, targetSlotId) { function swapOrMoveSlots(sourceSlotId, targetSlotId) {
const sourceCardId = String(state.slotAssignments.get(sourceSlotId) || ""); const sourceCardId = String(state.slotAssignments.get(sourceSlotId) || "");
const targetCardId = String(state.slotAssignments.get(targetSlotId) || ""); const targetCardId = String(state.slotAssignments.get(targetSlotId) || "");
@@ -3211,6 +3258,8 @@
return; return;
} }
blurLayoutNoteForBoardInteraction(target);
if (event.button === 1) { if (event.button === 1) {
startPanGesture(event, { source: "pointer" }); startPanGesture(event, { source: "pointer" });
return; return;
@@ -3237,10 +3286,14 @@
state.drag = { state.drag = {
pointerId: event.pointerId, pointerId: event.pointerId,
pointerType: String(event.pointerType || "").toLowerCase(),
sourceSlotId: String(cardButton.dataset.slotId || ""), sourceSlotId: String(cardButton.dataset.slotId || ""),
cardId: String(cardButton.dataset.cardId || ""), cardId: String(cardButton.dataset.cardId || ""),
startX: event.clientX, startX: event.clientX,
startY: event.clientY, startY: event.clientY,
touchEligibleAt: String(event.pointerType || "").toLowerCase() === "touch"
? (Number(event.timeStamp) || window.performance.now()) + FRAME_TOUCH_DRAG_ACTIVATION_DELAY_MS
: 0,
started: false, started: false,
hoverSlotId: "", hoverSlotId: "",
ghostEl: null, ghostEl: null,
@@ -3271,6 +3324,18 @@
return; return;
} }
if (state.drag.pointerType === "touch" && (state.pinchGesture || (state.panGesture && state.panGesture.source === "touch"))) {
cleanupDrag();
state.suppressClick = true;
return;
}
if (!state.drag.started
&& state.drag.pointerType === "touch"
&& (Number(event.timeStamp) || window.performance.now()) < Number(state.drag.touchEligibleAt || 0)) {
return;
}
const movedEnough = Math.hypot(event.clientX - state.drag.startX, event.clientY - state.drag.startY) >= 6; const movedEnough = Math.hypot(event.clientX - state.drag.startX, event.clientY - state.drag.startY) >= 6;
if (!state.drag.started && movedEnough) { if (!state.drag.started && movedEnough) {
const card = getCardMap(getCards()).get(state.drag.cardId) || null; const card = getCardMap(getCards()).get(state.drag.cardId) || null;
@@ -3813,6 +3878,11 @@
tarotFrameBoardEl.addEventListener("touchstart", handleBoardTouchStart, { passive: false }); tarotFrameBoardEl.addEventListener("touchstart", handleBoardTouchStart, { passive: false });
} }
document.addEventListener("touchstart", handleDocumentTouchStart, {
capture: true,
passive: true
});
if (tarotFrameOverviewEl) { if (tarotFrameOverviewEl) {
tarotFrameOverviewEl.addEventListener("input", (event) => { tarotFrameOverviewEl.addEventListener("input", (event) => {
const target = event.target; const target = event.target;

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=20260404-frame-gesture-lock-01"> <link rel="stylesheet" href="app/styles.css?v=20260404-frame-pan-cushion-01">
</head> </head>
<body> <body>
<div class="topbar"> <div class="topbar">
@@ -1189,7 +1189,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=20260404-frame-gesture-lock-01"></script> <script src="app/ui-tarot-frame.js?v=20260404-frame-notes-blur-01"></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>