updated frame for more mobile friendly usage
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user