diff --git a/package.json b/package.json index c8c36d5..67cea13 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "siteforge", "private": true, - "version": "1.2.1", + "version": "1.2.2", "type": "module", "scripts": { "dev": "vite", diff --git a/src/App.css b/src/App.css index 6031da4..8a862ef 100644 --- a/src/App.css +++ b/src/App.css @@ -8865,10 +8865,8 @@ } .scripture-popup { - position: absolute; - bottom: calc(100% + 8px); - left: 0; - z-index: 200; + position: fixed; + z-index: 1000; display: flex; flex-direction: column; gap: 0.5rem; diff --git a/src/components/QASection.tsx b/src/components/QASection.tsx index 797dd94..9d6fa92 100644 --- a/src/components/QASection.tsx +++ b/src/components/QASection.tsx @@ -218,7 +218,9 @@ function ScriptureTooltip({ refText, bookId, chapter, verseStart, verseEnd }: { const [verses, setVerses] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState(false) + const [pos, setPos] = useState<{ top: number; left: number } | null>(null) const wrapRef = useRef(null) + const btnRef = useRef(null) useEffect(() => { if (!open) return @@ -251,20 +253,35 @@ function ScriptureTooltip({ refText, bookId, chapter, verseStart, verseEnd }: { }) }, [open, bookId, chapter, verseStart, verseEnd, verses.length]) + // Compute fixed position from the trigger button so the popup escapes overflow:hidden parents + useEffect(() => { + if (!open || !btnRef.current) { setPos(null); return } + const rect = btnRef.current.getBoundingClientRect() + const POPUP_W = 360 + const left = Math.max(8, Math.min(rect.left, window.innerWidth - POPUP_W - 12)) + setPos({ top: rect.bottom + 8, left }) + }, [open]) + useEffect(() => { if (!open) return function handleClickOutside(e: MouseEvent) { - if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) { - setOpen(false) - } + if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) setOpen(false) } + function handleDismiss() { setOpen(false) } document.addEventListener('mousedown', handleClickOutside) - return () => document.removeEventListener('mousedown', handleClickOutside) + window.addEventListener('scroll', handleDismiss, { passive: true, capture: true }) + window.addEventListener('resize', handleDismiss) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + window.removeEventListener('scroll', handleDismiss, { capture: true }) + window.removeEventListener('resize', handleDismiss) + } }, [open]) return ( - {open && ( - + {open && pos && ( + {refText}