fix(walkthrough): keep sidebar crisp behind modal steps
Neutralize the app modal backdrop's dim/blur while the tour runs so a ringed sidebar/toolbar control behind an open modal (steps 2, 10) stays readable — the overlay's SVG spotlight is now the single source of dimming. Add a walkthrough-running body class toggled by the overlay and a CSS rule stripping [data-slot=dialog-overlay] background/backdrop-filter. Also refine coach-card placement: dialogCardPosition drops the card into the empty bottom-right corner for large modals (inventory, scan history) and beside small modals, so it never covers modal content (steps 3, 4).
This commit is contained in:
@@ -36,6 +36,23 @@ function cardPosition(rect: DOMRect | null, placement: StepPlacement): { left: n
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Position the card relative to an OPEN MODAL (the step's real subject).
|
||||
* Large modals (inventory, scan history at ~90vw) leave no room beside them, so
|
||||
* the card drops into the empty bottom-right corner instead of covering content.
|
||||
* Small modals get the card beside them, on whichever side has room.
|
||||
*/
|
||||
function dialogCardPosition(rect: DOMRect): { left: number; top: number } {
|
||||
const vw = window.innerWidth
|
||||
const vh = window.innerHeight
|
||||
const clampT = (t: number) => Math.max(8, Math.min(t, vh - CARD_H_EST - 8))
|
||||
const isLarge = rect.width > vw * 0.6 || rect.height > vh * 0.7
|
||||
if (isLarge) return { left: vw - CARD_W - 16, top: vh - CARD_H_EST - 16 }
|
||||
if (rect.left >= CARD_W + GAP * 2) return { left: rect.left - GAP - CARD_W, top: clampT(rect.top) }
|
||||
if (vw - rect.right >= CARD_W + GAP * 2) return { left: rect.right + GAP, top: clampT(rect.top) }
|
||||
return { left: Math.max(8, Math.min(rect.left, vw - CARD_W - 8)), top: clampT(rect.bottom + GAP) }
|
||||
}
|
||||
|
||||
export function WalkthroughOverlay() {
|
||||
const { isActive, stepIndex, total, setTotal, next, prev, skip } = useWalkthroughStore()
|
||||
const actions = useWalkthroughActions()
|
||||
@@ -99,12 +116,24 @@ export function WalkthroughOverlay() {
|
||||
return () => window.removeEventListener('keydown', handleKey)
|
||||
}, [isActive, handleKey])
|
||||
|
||||
// Flag the tour so app-modal backdrops drop their own dim/blur (see
|
||||
// walkthrough.css) — the spotlight then dims consistently everywhere.
|
||||
useEffect(() => {
|
||||
if (!isActive) return
|
||||
document.body.classList.add('walkthrough-running')
|
||||
return () => document.body.classList.remove('walkthrough-running')
|
||||
}, [isActive])
|
||||
|
||||
if (!isActive || !step) return null
|
||||
|
||||
const isLast = stepIndex >= total - 1
|
||||
// Ring / card follow the anchor if the step has one, else the open modal.
|
||||
// Ring the step's anchor (sidebar/toolbar button) if it has one, else the modal.
|
||||
const ringRect = anchorRect ?? dialogRect
|
||||
const pos = cardPosition(ringRect, step.placement ?? 'auto')
|
||||
// The card follows the OPEN MODAL when there is one (that's what the user reads),
|
||||
// otherwise the step's anchor. Keeps the card off the modal's content.
|
||||
const pos = dialogRect
|
||||
? dialogCardPosition(dialogRect)
|
||||
: cardPosition(anchorRect, step.placement ?? 'auto')
|
||||
// Cut-outs keep both the ringed control and any open modal lit.
|
||||
const holes = [anchorRect, dialogRect].filter((r): r is DOMRect => r !== null)
|
||||
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
50% { outline: 7px solid rgba(0, 212, 255, 0); }
|
||||
}
|
||||
|
||||
/* While the tour runs, app modals must not add their own dim/blur — the overlay's
|
||||
SVG spotlight is the single source of dimming, so a ringed sidebar/toolbar
|
||||
control behind an open modal stays crisp instead of being double-dimmed and
|
||||
blurred by the modal's own backdrop. */
|
||||
body.walkthrough-running [data-slot="dialog-overlay"] {
|
||||
background: transparent !important;
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.walkthrough-invite-enter,
|
||||
.walkthrough-card-enter,
|
||||
|
||||
Reference in New Issue
Block a user