Settings reorganization

This commit is contained in:
Stefan Hardegger
2025-09-17 15:06:35 +02:00
parent c0b3ae3b72
commit 64f97f5648
9 changed files with 1200 additions and 952 deletions

View File

@@ -20,6 +20,7 @@ export default function CollectionReadingView({
}: CollectionReadingViewProps) {
const { story, collection } = data;
const [hasScrolledToPosition, setHasScrolledToPosition] = useState(false);
const [readingPercentage, setReadingPercentage] = useState(0);
const contentRef = useRef<HTMLDivElement>(null);
const saveTimeoutRef = useRef<NodeJS.Timeout | null>(null);
@@ -43,28 +44,38 @@ export default function CollectionReadingView({
return Math.floor(scrollRatio * textLength);
}, [story]);
// Calculate reading percentage from character position
const calculateReadingPercentage = useCallback((currentPosition: number): number => {
if (!story) return 0;
const totalLength = story.contentPlain?.length || story.contentHtml.length;
if (totalLength === 0) return 0;
return Math.round((currentPosition / totalLength) * 100);
}, [story]);
// Convert character position back to scroll position for auto-scroll
const scrollToCharacterPosition = useCallback((position: number) => {
if (!contentRef.current || !story || hasScrolledToPosition) return;
const textLength = story.contentPlain?.length || story.contentHtml.length;
if (textLength === 0 || position === 0) return;
const ratio = position / textLength;
const content = contentRef.current;
const contentTop = content.offsetTop;
const contentHeight = content.scrollHeight;
const windowHeight = window.innerHeight;
// Calculate target scroll position
const targetScroll = contentTop + (ratio * contentHeight) - (windowHeight * 0.3);
// Smooth scroll to position
window.scrollTo({
top: Math.max(0, targetScroll),
behavior: 'smooth'
});
setHasScrolledToPosition(true);
}, [story, hasScrolledToPosition]);
@@ -102,23 +113,28 @@ export default function CollectionReadingView({
console.log('Collection view - initializing reading position tracking, saved position:', story.readingPosition);
if (story.readingPosition && story.readingPosition > 0) {
console.log('Collection view - auto-scrolling to saved position:', story.readingPosition);
const initialPercentage = calculateReadingPercentage(story.readingPosition);
setReadingPercentage(initialPercentage);
scrollToCharacterPosition(story.readingPosition);
} else {
console.log('Collection view - no saved position, starting fresh tracking');
setReadingPercentage(0);
setHasScrolledToPosition(true);
}
}, 500);
return () => clearTimeout(timeout);
}
}, [story, scrollToCharacterPosition, hasScrolledToPosition]);
}, [story, scrollToCharacterPosition, calculateReadingPercentage, hasScrolledToPosition]);
// Track reading progress and save position
useEffect(() => {
const handleScroll = () => {
if (hasScrolledToPosition) {
const characterPosition = getCharacterPositionFromScroll();
console.log('Collection view - scroll detected, character position:', characterPosition);
const percentage = calculateReadingPercentage(characterPosition);
console.log('Collection view - scroll detected, character position:', characterPosition, 'percentage:', percentage);
setReadingPercentage(percentage);
debouncedSavePosition(characterPosition);
} else {
console.log('Collection view - scroll detected but not ready for tracking yet');
@@ -132,7 +148,7 @@ export default function CollectionReadingView({
clearTimeout(saveTimeoutRef.current);
}
};
}, [hasScrolledToPosition, getCharacterPositionFromScroll, debouncedSavePosition]);
}, [hasScrolledToPosition, getCharacterPositionFromScroll, calculateReadingPercentage, debouncedSavePosition]);
const handlePrevious = () => {
if (collection.previousStoryId) {
@@ -190,6 +206,11 @@ export default function CollectionReadingView({
{/* Progress Bar */}
<div className="flex items-center gap-4">
{/* Reading percentage indicator */}
<div className="text-sm text-blue-700 dark:text-blue-300 font-mono bg-blue-100 dark:bg-blue-900 px-2 py-1 rounded">
{readingPercentage}%
</div>
<div className="w-32 bg-blue-200 dark:bg-blue-800 rounded-full h-2">
<div
className="bg-blue-600 dark:bg-blue-400 h-2 rounded-full transition-all duration-300"