From 2821d21221f55626825d7f6c0621f3fec9ea636e Mon Sep 17 00:00:00 2001 From: ittoview Date: Mon, 11 May 2026 10:00:58 +0100 Subject: [PATCH] fix: use single scrolling practice track --- src/pages/ProcessPurposePracticePage.tsx | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/pages/ProcessPurposePracticePage.tsx b/src/pages/ProcessPurposePracticePage.tsx index 399b0e6..1aaffd9 100644 --- a/src/pages/ProcessPurposePracticePage.tsx +++ b/src/pages/ProcessPurposePracticePage.tsx @@ -93,6 +93,7 @@ export default function ProcessPurposePracticePage() { const latestInputRef = useRef([]) const answerTimerRef = useRef(null) const deckScrollRef = useRef(null) + const currentScrollLimitRef = useRef(0) const { practiceMode } = useAppStore() const itemMap = useMemo( @@ -103,17 +104,9 @@ export default function ProcessPurposePracticePage() { const totalCount = progress.order.length const completedCount = progress.completedIds.length const isFinished = completedCount >= totalCount - const visibleQuestionCards = progress.order - .slice(0, progress.currentIndex + 1) + const deckCards = progress.order .map((id, index) => ({ item: itemMap.get(id), index })) .filter((card): card is { item: NonNullable; index: number } => Boolean(card.item)) - const nextPreviewItem = itemMap.get(progress.order[progress.currentIndex + 1]) - const deckCards = [ - ...visibleQuestionCards.map((card) => ({ ...card, isPreview: false })), - ...(nextPreviewItem - ? [{ item: nextPreviewItem, index: progress.currentIndex + 1, isPreview: true }] - : []), - ] const focusFirstEmptyInput = useCallback(() => { setTimeout(() => { @@ -236,6 +229,7 @@ export default function ProcessPurposePracticePage() { const deckTop = deck.getBoundingClientRect().top const cardTop = currentCard.getBoundingClientRect().top const targetTop = Math.max(deck.scrollTop + cardTop - deckTop - 12, 0) + currentScrollLimitRef.current = targetTop deck.scrollTo({ top: targetTop, behavior: 'smooth' }) }) }, [progress.currentIndex]) @@ -437,6 +431,14 @@ export default function ProcessPurposePracticePage() { focusFirstEmptyInput() }, [focusFirstEmptyInput]) + const handleDeckScroll = useCallback((event: React.UIEvent) => { + const deck = event.currentTarget + const maxScrollTop = currentScrollLimitRef.current + if (deck.scrollTop > maxScrollTop + 2) { + deck.scrollTop = maxScrollTop + } + }, []) + if (!currentItem) return null return ( @@ -479,19 +481,21 @@ export default function ProcessPurposePracticePage() {
- {deckCards.map(({ item, index, isPreview }) => { + {deckCards.map(({ item, index }) => { const isCurrent = index === progress.currentIndex const isAnsweredHistory = index < progress.currentIndex + const isFuture = index > progress.currentIndex return ( @@ -546,7 +550,7 @@ export default function ProcessPurposePracticePage() {

{item.purpose}