From e921967082b26a8abf97dc5fd1f8ddca7bf471c3 Mon Sep 17 00:00:00 2001 From: Gigi Date: Mon, 13 Oct 2025 21:04:39 +0200 Subject: [PATCH] fix: move progress indicator outside reader and fix position tracking - Move ReadingProgressIndicator outside reader div for true fixed positioning - Replace position-indicator library with custom scroll tracking - Track document scroll position instead of content scroll - Remove unused position-indicator dependency - Ensure progress indicator is always visible and shows correct percentage --- package-lock.json | 7 ----- package.json | 1 - src/components/ContentPanel.tsx | 10 +++--- src/hooks/useReadingPosition.ts | 56 ++++++++++++++------------------- 4 files changed, 29 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e2a4151..97c01592 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,6 @@ "applesauce-relay": "^4.0.0", "date-fns": "^4.1.0", "nostr-tools": "^2.4.0", - "position-indicator": "^0.0.12", "prismjs": "^1.30.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -8973,12 +8972,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/position-indicator": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/position-indicator/-/position-indicator-0.0.12.tgz", - "integrity": "sha512-qHQejEylblB7rZ3MfXSI5hu1+Dq7EBv1BYwUIVWzJ3nZ8d6V7LFBi1zC5/XwT/01Wxddf9kaFoOy3L70/5tC+A==", - "license": "MIT" - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", diff --git a/package.json b/package.json index 5b459a8c..1d2be76d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "applesauce-relay": "^4.0.0", "date-fns": "^4.1.0", "nostr-tools": "^2.4.0", - "position-indicator": "^0.0.12", "prismjs": "^1.30.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/components/ContentPanel.tsx b/src/components/ContentPanel.tsx index 89b76023..d9324bff 100644 --- a/src/components/ContentPanel.tsx +++ b/src/components/ContentPanel.tsx @@ -374,8 +374,8 @@ const ContentPanel: React.FC = ({ const highlightRgb = hexToRgb(highlightColor) return ( -
- {/* Reading Progress Indicator */} + <> + {/* Reading Progress Indicator - Outside reader for fixed positioning */} {isTextContent && ( = ({ /> )} - {/* Hidden markdown preview to convert markdown to HTML */} +
+ {/* Hidden markdown preview to convert markdown to HTML */} {markdown && (
= ({

No readable content found for this URL.

)} -
+
+ ) } diff --git a/src/hooks/useReadingPosition.ts b/src/hooks/useReadingPosition.ts index 594aa9a0..775c3a08 100644 --- a/src/hooks/useReadingPosition.ts +++ b/src/hooks/useReadingPosition.ts @@ -1,19 +1,8 @@ import { useEffect, useRef, useState } from 'react' -// @ts-ignore - position-indicator types issue -import { createPositionIndicator } from 'position-indicator' - -interface ReadingPositionData { - position: number // 0 to 1 - prevPosition: number - hasUpdated: boolean - hasScroll: boolean - eventType: 'scroll' | 'resize' | 'heightChange' | 'init' - eventDate: number -} interface UseReadingPositionOptions { enabled?: boolean - onPositionChange?: (data: ReadingPositionData) => void + onPositionChange?: (position: number) => void onReadingComplete?: () => void readingCompleteThreshold?: number // Default 0.9 (90%) } @@ -26,44 +15,45 @@ export const useReadingPosition = ({ }: UseReadingPositionOptions = {}) => { const [position, setPosition] = useState(0) const [isReadingComplete, setIsReadingComplete] = useState(false) - const positionIndicatorRef = useRef(null) const hasTriggeredComplete = useRef(false) useEffect(() => { if (!enabled) return - const handleInit = (data: ReadingPositionData) => { - setPosition(data.position) - onPositionChange?.(data) - } + const handleScroll = () => { + // Get the main content area (reader content) + const readerContent = document.querySelector('.reader-html, .reader-markdown') + if (!readerContent) return - const handleUpdate = (data: ReadingPositionData) => { - setPosition(data.position) - onPositionChange?.(data) + const scrollTop = window.pageYOffset || document.documentElement.scrollTop + const windowHeight = window.innerHeight + const documentHeight = document.documentElement.scrollHeight + + // Calculate position based on how much of the content has been scrolled through + const scrollProgress = Math.min(scrollTop / (documentHeight - windowHeight), 1) + const clampedProgress = Math.max(0, Math.min(1, scrollProgress)) + + setPosition(clampedProgress) + onPositionChange?.(clampedProgress) // Check if reading is complete - if (data.position >= readingCompleteThreshold && !hasTriggeredComplete.current) { + if (clampedProgress >= readingCompleteThreshold && !hasTriggeredComplete.current) { setIsReadingComplete(true) hasTriggeredComplete.current = true onReadingComplete?.() } } - const positionIndicator = createPositionIndicator({ - onInit: handleInit, - onUpdate: handleUpdate, - useResizeListener: true, - useResizeObserver: true - }) + // Initial calculation + handleScroll() - positionIndicator.init() - positionIndicatorRef.current = positionIndicator + // Add scroll listener + window.addEventListener('scroll', handleScroll, { passive: true }) + window.addEventListener('resize', handleScroll, { passive: true }) return () => { - if (positionIndicatorRef.current) { - positionIndicatorRef.current.destroy() - positionIndicatorRef.current = null - } + window.removeEventListener('scroll', handleScroll) + window.removeEventListener('resize', handleScroll) } }, [enabled, onPositionChange, onReadingComplete, readingCompleteThreshold])