Commit 1b3088ab authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat(analysis): timeline scrubber replaces arrow buttons

- Draggable slider bar to scrub through moves like a video
- RTL-aware: drag right = start, drag left = end
- Blue fill + white thumb shows current position
- Touch/pointer events for mobile drag
- Move display text above scrubber shows current move
- Move chips below still clickable as secondary nav
- No more confusing directional arrows
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 8fb5b77a
......@@ -41,23 +41,21 @@ export function mountAnalysis(el, params) {
<div style="color:#64748b;font-size:12px;text-align:center;">جاري التحليل...</div>
</div>
<!-- Move navigator — proper RTL order -->
<div style="display:flex;align-items:center;gap:6px;padding:6px 12px;background:#0a0a18;border-top:1px solid rgba(255,255,255,0.04);">
<button class="nav-btn" id="nav-end" title="النهاية">⟫</button>
<button class="nav-btn" id="nav-next" title="التالي">›</button>
<div id="move-display" style="flex:1;text-align:center;font-family:Inter,monospace;font-size:13px;font-weight:600;color:#f8fafc;">بداية</div>
<button class="nav-btn" id="nav-prev" title="السابق">‹</button>
<button class="nav-btn" id="nav-start" title="البداية">⟪</button>
<!-- Timeline scrubber -->
<div style="padding:8px 12px;background:#0a0a18;border-top:1px solid rgba(255,255,255,0.04);">
<div id="move-display" style="text-align:center;font-family:Inter,monospace;font-size:13px;font-weight:600;color:#f8fafc;margin-bottom:6px;">بداية</div>
<div id="scrubber-track" style="position:relative;height:32px;background:#1a1a2e;border-radius:8px;cursor:pointer;touch-action:none;user-select:none;">
<div id="scrubber-fill" style="position:absolute;top:0;right:0;height:100%;background:linear-gradient(90deg,#2563EB,#3B82F6);border-radius:8px;width:0%;transition:width 0.15s;"></div>
<div id="scrubber-thumb" style="position:absolute;top:50%;transform:translate(50%,-50%);right:0%;width:18px;height:18px;background:#f8fafc;border-radius:50%;box-shadow:0 2px 6px rgba(0,0,0,0.4);transition:right 0.15s;"></div>
<div id="scrubber-marks" style="position:absolute;inset:0;display:flex;align-items:center;justify-content:space-between;padding:0 8px;pointer-events:none;"></div>
</div>
</div>
<!-- Move chips -->
<div id="analysis-moves" style="padding:6px 12px;background:#0a0a18;border-top:1px solid rgba(255,255,255,0.04);max-height:44px;overflow-x:auto;white-space:nowrap;font-family:Inter,monospace;font-size:11px;display:flex;gap:3px;align-items:center;">
<div id="analysis-moves" style="padding:6px 12px;background:#0a0a18;border-top:1px solid rgba(255,255,255,0.04);max-height:40px;overflow-x:auto;white-space:nowrap;font-family:Inter,monospace;font-size:11px;display:flex;gap:3px;align-items:center;">
</div>
</div>
<style>
.nav-btn { width:38px;height:34px;background:#1a1a2e;border:1px solid rgba(255,255,255,0.08);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:18px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:background 0.1s,transform 0.1s; }
.nav-btn:hover { background:#2a2a4a; }
.nav-btn:active { background:#3a3a6a;transform:scale(0.92); }
.move-chip { padding:3px 7px;border-radius:5px;cursor:pointer;color:#94a3b8;font-size:11px;transition:background 0.1s; }
.move-chip:hover { background:rgba(255,255,255,0.08); }
.move-chip.active { background:#2563EB;color:#fff;font-weight:600; }
......@@ -78,10 +76,29 @@ export function mountAnalysis(el, params) {
// Navigation
el.querySelector('#back-btn').addEventListener('click', () => { audio.play('click'); scene.pop(); });
el.querySelector('#nav-start').addEventListener('click', () => goToMove(el, moves, 0));
el.querySelector('#nav-prev').addEventListener('click', () => goToMove(el, moves, Math.max(0, currentMoveIdx - 1)));
el.querySelector('#nav-next').addEventListener('click', () => goToMove(el, moves, Math.min(moves.length, currentMoveIdx + 1)));
el.querySelector('#nav-end').addEventListener('click', () => goToMove(el, moves, moves.length));
// Timeline scrubber
const track = el.querySelector('#scrubber-track');
let isDragging = false;
function scrubToPosition(clientX) {
const rect = track.getBoundingClientRect();
// RTL: right side = start (0), left side = end (moves.length)
const ratio = 1 - Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
const idx = Math.round(ratio * moves.length);
goToMove(el, moves, idx);
}
track.addEventListener('pointerdown', (e) => {
isDragging = true;
track.setPointerCapture(e.pointerId);
scrubToPosition(e.clientX);
});
track.addEventListener('pointermove', (e) => {
if (isDragging) scrubToPosition(e.clientX);
});
track.addEventListener('pointerup', () => { isDragging = false; });
track.addEventListener('pointercancel', () => { isDragging = false; });
// Go to final position
goToMove(el, moves, moves.length);
......@@ -128,6 +145,14 @@ function goToMove(el, moves, idx) {
if (idx === 0) display.textContent = 'بداية';
else display.textContent = `${Math.ceil(idx / 2)}. ${moves[idx - 1]?.san || ''}`;
// Update scrubber position
const totalMoves = moves.length || 1;
const percent = (idx / totalMoves) * 100;
const fill = el.querySelector('#scrubber-fill');
const thumb = el.querySelector('#scrubber-thumb');
if (fill) fill.style.width = percent + '%';
if (thumb) thumb.style.right = percent + '%';
// Update active chip
el.querySelectorAll('.move-chip').forEach(c => c.classList.remove('active'));
const activeChip = el.querySelector(`.move-chip[data-idx="${idx}"]`);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment