diff --git a/app/[locale]/bible/reader.tsx b/app/[locale]/bible/reader.tsx index d9f65f2..4b8b409 100644 --- a/app/[locale]/bible/reader.tsx +++ b/app/[locale]/bible/reader.tsx @@ -147,6 +147,7 @@ export default function BibleReaderNew() { const [preferences, setPreferences] = useState(defaultPreferences) const [highlightedVerse, setHighlightedVerse] = useState(null) const [showScrollTop, setShowScrollTop] = useState(false) + const [previousVerses, setPreviousVerses] = useState([]) // Keep previous content during loading // Bookmark state const [isChapterBookmarked, setIsChapterBookmarked] = useState(false) @@ -387,11 +388,35 @@ export default function BibleReaderNew() { useEffect(() => { if (selectedBook && selectedChapter) { setLoading(true) + + // Store scroll position to prevent jumping + const scrollPosition = window.pageYOffset + fetch(`/api/bible/verses?bookId=${selectedBook}&chapter=${selectedChapter}`) .then(res => res.json()) .then(data => { - setVerses(data.verses || []) - setLoading(false) + const newVerses = data.verses || [] + + // Store previous verses before updating + setPreviousVerses(verses) + + // Use requestAnimationFrame to ensure smooth transition + requestAnimationFrame(() => { + setVerses(newVerses) + + // Small delay to allow content to render before removing loading state + setTimeout(() => { + setLoading(false) + setPreviousVerses([]) // Clear previous content after transition + + // Restore scroll position if we're not navigating to a specific verse + const urlVerse = new URLSearchParams(window.location.search).get('verse') + if (!urlVerse) { + // Maintain scroll position for better UX + window.scrollTo({ top: Math.min(scrollPosition, document.body.scrollHeight), behavior: 'auto' }) + } + }, 50) // Small delay for smoother transition + }) }) .catch(err => { console.error('Error fetching verses:', err) @@ -808,7 +833,11 @@ export default function BibleReaderNew() { p: preferences.readingMode ? 1 : 2, ...getThemeStyles(), border: preferences.readingMode ? 'none' : `1px solid ${getThemeStyles().borderColor}`, - backgroundColor: preferences.readingMode ? 'transparent' : getThemeStyles().backgroundColor + backgroundColor: preferences.readingMode ? 'transparent' : getThemeStyles().backgroundColor, + position: 'sticky', + top: 0, + zIndex: 1, + transition: 'all 0.2s ease' }} > {/* First Row: Navigation Filters */} @@ -1188,24 +1217,37 @@ export default function BibleReaderNew() { sx={{ maxWidth: preferences.columnLayout ? 'none' : '800px', mx: 'auto', - width: '100%' + width: '100%', + minHeight: '60vh', // Prevent layout shifts + position: 'relative' }} > - {loading ? ( - - - - ) : ( - + + {loading && ( + + + + )} + + {/* Chapter Header */} - {verses.length} {t('verses')} + {(loading && previousVerses.length > 0 ? previousVerses : verses).length} {t('verses')} {/* Verses */} - {verses.map(renderVerse)} + {(loading && previousVerses.length > 0 ? previousVerses : verses).map(renderVerse)} {/* Chapter Navigation */} @@ -1248,8 +1290,8 @@ export default function BibleReaderNew() { {t('nextChapter')} - - )} + +