Sasquatch: fix desktop discoverability + repetitive greeting
- Move bubble & panel to bottom-RIGHT on desktop (was bottom-left, colliding with / hiding behind the desktop footer). Mobile stays bottom-left. - Raise bubble/panel z-index to z-60 so it always sits above the footer. - Re-clamp a stale saved drag position on mount: a bubble dragged off-screen on one device no longer disappears on another. - Stop showing the long welcome greeting + action button on every open once a conversation has started (chatMessages > 0), so it no longer "says the same thing all over again". Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
d12af9e56d
commit
e996d96fa0
1 changed files with 34 additions and 12 deletions
|
|
@ -635,11 +635,26 @@ export function SasquatchGuide({ message, onDismiss }: SasquatchGuideProps) {
|
|||
|
||||
const bubbleStyle = useMemo(() => {
|
||||
if (dragPos) {
|
||||
return { position: 'fixed' as const, left: dragPos.x, top: dragPos.y, bottom: 'auto', right: 'auto', zIndex: 50 };
|
||||
return { position: 'fixed' as const, left: dragPos.x, top: dragPos.y, bottom: 'auto', right: 'auto', zIndex: 60 };
|
||||
}
|
||||
return undefined;
|
||||
}, [dragPos]);
|
||||
|
||||
// Safety: a bubble position saved on one device/viewport (e.g. a phone) can
|
||||
// land off-screen or hidden on another (e.g. desktop). On mount, if a saved
|
||||
// drag position is outside the current viewport, clear it so the bubble
|
||||
// returns to its default, always-visible corner.
|
||||
useEffect(() => {
|
||||
if (!dragPos) return;
|
||||
const maxX = window.innerWidth - 56;
|
||||
const maxY = window.innerHeight - 56;
|
||||
if (dragPos.x < 0 || dragPos.y < 0 || dragPos.x > maxX || dragPos.y > maxY) {
|
||||
setDragPos(null);
|
||||
}
|
||||
// Only run on mount — we don't want to fight the user mid-drag.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Only auto-open the panel when the context message explicitly opts in via
|
||||
// `autoShow`. On the map (`/`) and The Lab (`/lab`) the guide stays minimized
|
||||
// until the user taps the bubble — the message content is still used to
|
||||
|
|
@ -1181,8 +1196,11 @@ Instructions:
|
|||
<div
|
||||
ref={dragRef}
|
||||
className={cn(
|
||||
'z-50 touch-none select-none',
|
||||
dragPos ? '' : 'fixed bottom-[9.5rem] left-4 md:bottom-6 md:left-4',
|
||||
'z-[60] touch-none select-none',
|
||||
// Mobile: bottom-left, clear of the bottom nav. Desktop: bottom-RIGHT
|
||||
// so the bubble is easy to spot and never hides behind the footer
|
||||
// (which is bottom-left on desktop).
|
||||
dragPos ? '' : 'fixed bottom-[9.5rem] left-4 md:bottom-6 md:left-auto md:right-6',
|
||||
)}
|
||||
style={bubbleStyle}
|
||||
onPointerDown={onPointerDown}
|
||||
|
|
@ -1217,13 +1235,13 @@ Instructions:
|
|||
{shouldShowPanel && !isMinimized && (
|
||||
<div
|
||||
className={cn(
|
||||
'fixed z-50 flex flex-col transition-all duration-300 ease-out',
|
||||
'fixed z-[60] flex flex-col transition-all duration-300 ease-out',
|
||||
// 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)]',
|
||||
// Desktop: compact panel bottom-left
|
||||
'md:bottom-6 md:left-4 md:w-[340px]',
|
||||
// Desktop: compact panel bottom-RIGHT (matches the bubble, clears the footer)
|
||||
'md:bottom-6 md:left-auto md:right-6 md:w-[360px]',
|
||||
isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-3 pointer-events-none'
|
||||
)}
|
||||
style={{
|
||||
|
|
@ -1305,13 +1323,17 @@ Instructions:
|
|||
|
||||
{/* Body — scrolls internally so the card never outgrows the viewport */}
|
||||
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain p-3">
|
||||
{/* Greeting */}
|
||||
<p className="text-xs text-gray-300 leading-relaxed mb-3">
|
||||
{activeMessage.message}
|
||||
</p>
|
||||
{/* Greeting — only shown before the user starts chatting, so the
|
||||
same wall of welcome text doesn't reappear on every open once
|
||||
a conversation is underway. */}
|
||||
{chatMessages.length === 0 && (
|
||||
<p className="text-xs text-gray-300 leading-relaxed mb-3">
|
||||
{activeMessage.message}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Action button */}
|
||||
{activeMessage.action && (
|
||||
{/* Action button — also only before chatting */}
|
||||
{chatMessages.length === 0 && activeMessage.action && (
|
||||
<button
|
||||
onClick={activeMessage.action.onClick}
|
||||
className="w-full py-2 px-3 rounded-lg text-xs font-bold text-black bg-[#ccff00] hover:bg-[#d4ff1a] transition-colors mb-3"
|
||||
|
|
|
|||
Loading…
Reference in a new issue