From 18fb4fbd63b2b6cf0a5c2e2a78631365970ec611 Mon Sep 17 00:00:00 2001 From: ghassan Date: Tue, 28 Jul 2026 22:35:04 +0300 Subject: [PATCH] Match highlights: mobile bottom sheet (Option A) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On mobile (<=991px) the Points/Coach-review pane no longer stacks below the comments. Tapping "Highlights" now slides it up as a bottom sheet over the lower ~62vh, and scrolls the player back to the top so the user can watch and read at once. Includes a drag handle, a light tap-to-dismiss scrim, and internal scrolling. Desktop keeps its side pane exactly as before — all new CSS is inside the max-width:991px media query. - Sheet only restores its open state on desktop; on mobile it stays closed on load so it never pops open unexpectedly. - Scrim sits above the fixed bottom nav (z-index 1400 > 1000). - Honors prefers-reduced-motion. Co-Authored-By: Claude Opus 4.8 --- resources/views/videos/types/match.blade.php | 96 +++++++++++++++++--- 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/resources/views/videos/types/match.blade.php b/resources/views/videos/types/match.blade.php index dc5d347..7fd8b9f 100644 --- a/resources/views/videos/types/match.blade.php +++ b/resources/views/videos/types/match.blade.php @@ -1882,6 +1882,57 @@ font-size: 0.75rem; } } + + /* ============================================================ + MATCH HIGHLIGHTS — mobile bottom sheet (Option A) + Desktop keeps its side pane untouched. Below 991px the pane + becomes a bottom sheet so the player stays visible up top + while points / coach reviews scroll in the lower half. + ============================================================ */ + .hl-sheet-backdrop { display: none; } + .hl-sheet-grab { display: none; } + + @media (max-width: 991px) { + .events-sidebar { + display: flex !important; /* override desktop display:none so it can slide */ + position: fixed; + left: 0; right: 0; bottom: 0; top: auto; + width: 100% !important; + height: 62vh; max-height: 62vh; + margin: 0 !important; + border-radius: 18px 18px 0 0; + box-shadow: 0 -14px 44px rgba(0, 0, 0, 0.55); + transform: translateY(100%); + transition: transform 0.34s cubic-bezier(0.32, 0.72, 0, 1); + pointer-events: none; + z-index: 1400; /* above the fixed bottom nav (z-index 1000) */ + } + .events-sidebar.show { + display: flex !important; + transform: translateY(0); + pointer-events: auto; + } + /* Drag affordance at the top of the sheet */ + .hl-sheet-grab { + display: block; flex-shrink: 0; + width: 40px; height: 4px; border-radius: 3px; + background: rgba(255, 255, 255, 0.3); + margin: 10px auto 4px; cursor: pointer; + } + /* Light tap-to-dismiss scrim — faint so the video stays watchable */ + .hl-sheet-backdrop { + display: block; + position: fixed; inset: 0; + background: rgba(0, 0, 0, 0.32); + opacity: 0; visibility: hidden; + transition: opacity 0.28s ease, visibility 0.28s; + z-index: 1399; + } + .hl-sheet-backdrop.show { opacity: 1; visibility: visible; } + } + @media (max-width: 991px) and (prefers-reduced-motion: reduce) { + .events-sidebar { transition: none; } + } @endsection @@ -2222,25 +2273,38 @@ const videoId = @json(isset($video) ? $video->getRouteKey() : ''); if (toggleBtn && sidebar) { - // Load saved state on page load - const savedState = localStorage.getItem(`highlights_${videoId}`); - if (savedState === 'open') { - sidebar.classList.add('show'); - toggleBtn.classList.add('expanded'); - toggleBtn.textContent = 'Highlights'; - } + const backdrop = document.getElementById('hlSheetBackdrop'); + const grab = sidebar.querySelector('.hl-sheet-grab'); + const mainScroll = document.getElementById('main'); + const isMobile = () => window.matchMedia('(max-width: 991px)').matches; - toggleBtn.addEventListener('click', function() { - const isOpen = sidebar.classList.toggle('show'); - toggleBtn.classList.toggle('expanded'); - - // Save state to localStorage - if (isOpen) { + const setOpen = (open) => { + sidebar.classList.toggle('show', open); + toggleBtn.classList.toggle('expanded', open); + if (backdrop) backdrop.classList.toggle('show', open && isMobile()); + if (open) { localStorage.setItem(`highlights_${videoId}`, 'open'); - toggleBtn.textContent = 'Highlights'; + // Mobile: the pane is a bottom sheet — bring the player back + // to the top so the user can watch while reading highlights. + if (isMobile() && mainScroll) mainScroll.scrollTo({ top: 0, behavior: 'smooth' }); } else { localStorage.removeItem(`highlights_${videoId}`); } + }; + + // Restore last state on DESKTOP only — a sheet auto-popping open on + // every mobile page load would be jarring. + if (localStorage.getItem(`highlights_${videoId}`) === 'open' && !isMobile()) { + setOpen(true); + } + + toggleBtn.addEventListener('click', () => setOpen(!sidebar.classList.contains('show'))); + if (backdrop) backdrop.addEventListener('click', () => setOpen(false)); + if (grab) grab.addEventListener('click', () => setOpen(false)); + + // Keep the scrim honest if the viewport crosses the mobile boundary. + window.addEventListener('resize', () => { + if (backdrop) backdrop.classList.toggle('show', sidebar.classList.contains('show') && isMobile()); }); } }); @@ -2253,7 +2317,11 @@
+ {{-- Mobile-only scrim behind the bottom sheet (tap to dismiss) --}} +