Fix Sasquatch panel overflow on mobile: cap height to dvh + safe-area, pin header, scroll body internally

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-08-10 22:23:48 +07:00
parent 6e11aaab7d
commit eed8552e37

View file

@ -1208,17 +1208,24 @@ Instructions:
{shouldShowPanel && !isMinimized && ( {shouldShowPanel && !isMinimized && (
<div <div
className={cn( className={cn(
'fixed z-50 transition-all duration-300 ease-out', 'fixed z-50 flex flex-col transition-all duration-300 ease-out',
// Mobile: left-anchored, max ~65% width — leaves right side free for Quick Snap + filter pills // Mobile: left-anchored, max ~65% width — leaves right side free for Quick Snap + filter pills.
// Height is bounded to the visible viewport (dvh) with safe-area insets so the
// header/close button never slide off the top of the screen behind the status bar.
'bottom-[4.5rem] left-2 w-[min(calc(100vw-5rem),340px)]', 'bottom-[4.5rem] left-2 w-[min(calc(100vw-5rem),340px)]',
// Desktop: compact panel bottom-left // Desktop: compact panel bottom-left
'md:bottom-6 md:left-4 md:w-[340px]', 'md:bottom-6 md:left-4 md:w-[340px]',
isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-3 pointer-events-none' isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-3 pointer-events-none'
)} )}
style={{
// Cap the panel so it can never exceed the space between the safe-area top
// and its own bottom offset (5rem ≈ bottom offset + a little breathing room).
maxHeight: 'calc(100dvh - env(safe-area-inset-top, 0px) - 6rem)',
}}
> >
{/* Jungle/dark card */} {/* Jungle/dark card */}
<div <div
className="rounded-xl border border-[#ccff00]/20 shadow-2xl overflow-hidden" className="flex min-h-0 flex-1 flex-col rounded-xl border border-[#ccff00]/20 shadow-2xl overflow-hidden"
style={{ style={{
background: 'linear-gradient(160deg, #0f1f08 0%, #0a1505 50%, #060d03 100%)', background: 'linear-gradient(160deg, #0f1f08 0%, #0a1505 50%, #060d03 100%)',
boxShadow: '0 0 40px rgba(0,0,0,0.9), 0 0 20px rgba(204,255,0,0.06), inset 0 1px 0 rgba(204,255,0,0.08)', boxShadow: '0 0 40px rgba(0,0,0,0.9), 0 0 20px rgba(204,255,0,0.06), inset 0 1px 0 rgba(204,255,0,0.08)',
@ -1226,12 +1233,12 @@ Instructions:
> >
{/* Jungle texture strip at top */} {/* Jungle texture strip at top */}
<div <div
className="h-1 w-full" className="h-1 w-full flex-shrink-0"
style={{ background: 'linear-gradient(90deg, #1a3d0a, #ccff00, #2d5c10, #ccff00, #1a3d0a)' }} style={{ background: 'linear-gradient(90deg, #1a3d0a, #ccff00, #2d5c10, #ccff00, #1a3d0a)' }}
/> />
{/* Header */} {/* Header */}
<div className="flex items-center gap-2.5 px-3 py-2.5 border-b border-[#ccff00]/10"> <div className="flex flex-shrink-0 items-center gap-2.5 px-3 py-2.5 border-b border-[#ccff00]/10">
<div className="relative flex-shrink-0"> <div className="relative flex-shrink-0">
<img <img
src="/images/sasquatch-guide.webp" src="/images/sasquatch-guide.webp"
@ -1287,8 +1294,8 @@ Instructions:
</div> </div>
</div> </div>
{/* Body */} {/* Body — scrolls internally so the card never outgrows the viewport */}
<div className="p-3"> <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain p-3">
{/* Greeting */} {/* Greeting */}
<p className="text-xs text-gray-300 leading-relaxed mb-3"> <p className="text-xs text-gray-300 leading-relaxed mb-3">
{activeMessage.message} {activeMessage.message}
@ -1452,7 +1459,7 @@ Instructions:
{/* Bottom jungle strip */} {/* Bottom jungle strip */}
<div <div
className="h-0.5 w-full opacity-30" className="h-0.5 w-full flex-shrink-0 opacity-30"
style={{ background: 'linear-gradient(90deg, transparent, #ccff00, transparent)' }} style={{ background: 'linear-gradient(90deg, transparent, #ccff00, transparent)' }}
/> />
</div> </div>