Polish player chrome: left back, right menu, swipe-down dismiss.
build-and-deploy / deploy (push) Successful in 4m32s
build-and-deploy / deploy (push) Successful in 4m32s
Unify square icon buttons and close the expanded sheet with a real downward drag instead of a chevron control. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -290,11 +290,25 @@ button, input { font: inherit; }
|
||||
display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem;
|
||||
}
|
||||
.title-author { font-weight: 500; color: var(--muted); font-size: 0.92em; }
|
||||
.back-btn {
|
||||
flex-shrink: 0; width: 52px; height: 52px; border-radius: 14px;
|
||||
border: 1px solid var(--line); background: #fff; cursor: pointer;
|
||||
font-size: 1.6rem; line-height: 1; color: var(--brand-deep);
|
||||
.back-btn,
|
||||
.sheet-icon-btn,
|
||||
.icon-chip,
|
||||
.sheet-action-icon {
|
||||
flex-shrink: 0;
|
||||
width: 44px; height: 44px; border-radius: 12px;
|
||||
border: 1px solid rgba(28, 43, 36, 0.14);
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 8px rgba(28, 43, 36, 0.08);
|
||||
cursor: pointer;
|
||||
color: var(--brand-deep);
|
||||
display: grid; place-items: center;
|
||||
font-size: 1.35rem; line-height: 1;
|
||||
}
|
||||
.back-btn { width: 52px; height: 52px; border-radius: 14px; font-size: 1.6rem; }
|
||||
.icon-chip.on,
|
||||
.sheet-action.on .sheet-action-icon {
|
||||
background: var(--brand); color: #fff; border-color: var(--brand);
|
||||
box-shadow: 0 2px 10px rgba(31, 107, 74, 0.28);
|
||||
}
|
||||
.ayah-page-title {
|
||||
margin: 0 0 0.85rem; font-size: 1.1rem; font-weight: 700; color: var(--brand-deep);
|
||||
@@ -341,13 +355,6 @@ button, input { font: inherit; }
|
||||
font-weight: 700; font-size: 1.05rem; color: var(--ink); text-align: right;
|
||||
}
|
||||
.dock-actions { display: flex; gap: 0.45rem; flex-shrink: 0; }
|
||||
.icon-chip {
|
||||
width: 44px; height: 44px; border-radius: 12px;
|
||||
border: 1px solid rgba(28, 43, 36, 0.22); background: #f3f6f4; cursor: pointer;
|
||||
color: #1c2b24; font-size: 1.35rem;
|
||||
display: grid; place-items: center;
|
||||
}
|
||||
.icon-chip.on { background: var(--brand); color: #fff; border-color: var(--brand); }
|
||||
.ltr-controls {
|
||||
display: grid; grid-template-columns: auto 1fr auto; gap: 0.7rem; align-items: center;
|
||||
direction: ltr;
|
||||
@@ -396,19 +403,16 @@ button, input { font: inherit; }
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.85rem;
|
||||
direction: ltr; /* spacer left, menu right */
|
||||
}
|
||||
.sheet-header-spacer { width: 44px; height: 44px; }
|
||||
.sheet-header-title {
|
||||
direction: rtl;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
color: var(--ink);
|
||||
}
|
||||
.sheet-icon-btn {
|
||||
width: 44px; height: 44px; border-radius: 12px;
|
||||
border: 1px solid var(--line); background: #fff;
|
||||
cursor: pointer; font-size: 1.35rem; color: var(--brand-deep);
|
||||
display: grid; place-items: center;
|
||||
}
|
||||
.player-hero {
|
||||
width: min(100%, 360px);
|
||||
aspect-ratio: 1;
|
||||
@@ -453,14 +457,7 @@ button, input { font: inherit; }
|
||||
color: var(--ink); font-size: 0.85rem; padding: 0.35rem;
|
||||
}
|
||||
.sheet-action.on { color: var(--brand); font-weight: 700; }
|
||||
.sheet-action-icon {
|
||||
width: 44px; height: 44px; border-radius: 12px;
|
||||
border: 1px solid rgba(28, 43, 36, 0.18); background: #fff;
|
||||
display: grid; place-items: center; font-size: 1.25rem;
|
||||
}
|
||||
.sheet-action.on .sheet-action-icon {
|
||||
background: var(--brand); color: #fff; border-color: var(--brand);
|
||||
}
|
||||
.sheet-action-icon { font-size: 1.25rem; }
|
||||
.sheet-seek-block { margin-top: auto; padding-top: 0.5rem; }
|
||||
.sheet-seek { width: 100%; accent-color: var(--brand); }
|
||||
.sheet-times {
|
||||
@@ -485,7 +482,8 @@ button, input { font: inherit; }
|
||||
}
|
||||
.skip-btn {
|
||||
width: 52px; height: 52px; border-radius: 50%;
|
||||
border: 1px solid rgba(28, 43, 36, 0.22); background: #fff;
|
||||
border: 1px solid rgba(28, 43, 36, 0.14); background: #fff;
|
||||
box-shadow: 0 2px 8px rgba(28, 43, 36, 0.08);
|
||||
cursor: pointer; font-weight: 700; color: var(--brand-deep);
|
||||
}
|
||||
|
||||
@@ -498,12 +496,18 @@ button, input { font: inherit; }
|
||||
overflow: hidden;
|
||||
}
|
||||
.toc-header {
|
||||
display: flex; align-items: center; gap: 0.65rem;
|
||||
display: grid;
|
||||
grid-template-columns: 44px 1fr;
|
||||
align-items: center;
|
||||
gap: 0.65rem;
|
||||
padding: 0 1rem 0.85rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
direction: ltr; /* back button physical left */
|
||||
}
|
||||
.toc-header-text {
|
||||
display: grid; gap: 0.15rem;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
.toc-header-text strong { font-size: 1.15rem; color: var(--ink); }
|
||||
.toc-skeleton { padding: 1rem; }
|
||||
|
||||
@@ -80,3 +80,105 @@ window.tqAudio = {
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
window.tqSheet = {
|
||||
_handlers: new WeakMap(),
|
||||
|
||||
_ignored: (target) => {
|
||||
if (!target || !target.closest) return false;
|
||||
return !!target.closest('.seek, input, .player-main-controls, .sheet-actions, .sheet-icon-btn, button, a');
|
||||
},
|
||||
|
||||
bindDismiss: (el, dotnet, methodName) => {
|
||||
if (!el || !dotnet) return;
|
||||
window.tqSheet.unbindDismiss(el);
|
||||
|
||||
const state = { startY: 0, startX: 0, active: false, dragging: false };
|
||||
const threshold = 80;
|
||||
const method = methodName || 'OnSwipeDismiss';
|
||||
|
||||
const resetTransform = () => {
|
||||
el.style.transition = 'transform 0.22s ease, opacity 0.22s ease';
|
||||
el.style.transform = '';
|
||||
el.style.opacity = '';
|
||||
window.setTimeout(() => { el.style.transition = ''; }, 240);
|
||||
};
|
||||
|
||||
const onStart = (e) => {
|
||||
if (window.tqSheet._ignored(e.target)) return;
|
||||
const point = e.touches ? e.touches[0] : e;
|
||||
if (!point) return;
|
||||
state.startY = point.clientY;
|
||||
state.startX = point.clientX;
|
||||
state.active = true;
|
||||
state.dragging = false;
|
||||
el.style.transition = 'none';
|
||||
};
|
||||
|
||||
const onMove = (e) => {
|
||||
if (!state.active) return;
|
||||
const point = e.touches ? e.touches[0] : e;
|
||||
if (!point) return;
|
||||
const dy = point.clientY - state.startY;
|
||||
const dx = point.clientX - state.startX;
|
||||
if (!state.dragging) {
|
||||
if (Math.abs(dy) < 8 && Math.abs(dx) < 8) return;
|
||||
if (Math.abs(dx) > Math.abs(dy) || dy < 0) {
|
||||
state.active = false;
|
||||
return;
|
||||
}
|
||||
state.dragging = true;
|
||||
}
|
||||
if (e.cancelable) e.preventDefault();
|
||||
const y = Math.max(0, dy);
|
||||
el.style.transform = `translateY(${y}px)`;
|
||||
el.style.opacity = String(Math.max(0.45, 1 - y / 420));
|
||||
};
|
||||
|
||||
const onEnd = (e) => {
|
||||
if (!state.active && !state.dragging) return;
|
||||
const point = (e.changedTouches && e.changedTouches[0]) || e;
|
||||
const dy = point ? (point.clientY - state.startY) : 0;
|
||||
const dx = point ? (point.clientX - state.startX) : 0;
|
||||
const shouldDismiss = state.dragging && dy >= threshold && Math.abs(dx) < dy;
|
||||
state.active = false;
|
||||
state.dragging = false;
|
||||
if (shouldDismiss) {
|
||||
el.style.transition = 'transform 0.2s ease, opacity 0.2s ease';
|
||||
el.style.transform = 'translateY(100%)';
|
||||
el.style.opacity = '0';
|
||||
dotnet.invokeMethodAsync(method);
|
||||
} else {
|
||||
resetTransform();
|
||||
}
|
||||
};
|
||||
|
||||
el.addEventListener('touchstart', onStart, { passive: true });
|
||||
el.addEventListener('touchmove', onMove, { passive: false });
|
||||
el.addEventListener('touchend', onEnd, { passive: true });
|
||||
el.addEventListener('touchcancel', onEnd, { passive: true });
|
||||
el.addEventListener('pointerdown', onStart);
|
||||
el.addEventListener('pointermove', onMove);
|
||||
el.addEventListener('pointerup', onEnd);
|
||||
el.addEventListener('pointercancel', onEnd);
|
||||
|
||||
window.tqSheet._handlers.set(el, { onStart, onMove, onEnd });
|
||||
},
|
||||
|
||||
unbindDismiss: (el) => {
|
||||
const h = window.tqSheet._handlers.get(el);
|
||||
if (!h || !el) return;
|
||||
el.removeEventListener('touchstart', h.onStart);
|
||||
el.removeEventListener('touchmove', h.onMove);
|
||||
el.removeEventListener('touchend', h.onEnd);
|
||||
el.removeEventListener('touchcancel', h.onEnd);
|
||||
el.removeEventListener('pointerdown', h.onStart);
|
||||
el.removeEventListener('pointermove', h.onMove);
|
||||
el.removeEventListener('pointerup', h.onEnd);
|
||||
el.removeEventListener('pointercancel', h.onEnd);
|
||||
el.style.transform = '';
|
||||
el.style.opacity = '';
|
||||
el.style.transition = '';
|
||||
window.tqSheet._handlers.delete(el);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user