Reader: treat browser refresh as implicit resume
Refreshing the chapter page was landing the user back at the top, because only ?resume=1 triggered the saved-position restore. Added isPageReload() helper (checks performance navigation entry type === 'reload') and OR'd it with the resume flag. Refresh now restores to the last scroll position; drawer/list clicks still go to top as intended. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fb2b032d73
commit
95135942a2
@ -15,6 +15,7 @@ import {
|
|||||||
readProgress,
|
readProgress,
|
||||||
writeProgress,
|
writeProgress,
|
||||||
} from "@/components/ReadingProgressButton";
|
} from "@/components/ReadingProgressButton";
|
||||||
|
import { isPageReload } from "@/lib/progress";
|
||||||
import { LoadingLogo } from "@/components/LoadingLogo";
|
import { LoadingLogo } from "@/components/LoadingLogo";
|
||||||
import {
|
import {
|
||||||
calcScrollRatio,
|
calcScrollRatio,
|
||||||
@ -70,7 +71,8 @@ export function PageReader({
|
|||||||
const [currentChapterNum, setCurrentChapterNum] =
|
const [currentChapterNum, setCurrentChapterNum] =
|
||||||
useState(startChapterNumber);
|
useState(startChapterNumber);
|
||||||
const [currentPageNum, setCurrentPageNum] = useState(() => {
|
const [currentPageNum, setCurrentPageNum] = useState(() => {
|
||||||
if (typeof window === "undefined" || !resume) return 1;
|
if (typeof window === "undefined") return 1;
|
||||||
|
if (!resume && !isPageReload()) return 1;
|
||||||
const p = readProgress(mangaSlug);
|
const p = readProgress(mangaSlug);
|
||||||
if (p && p.chapter === startChapterNumber && p.page > 1) return p.page;
|
if (p && p.chapter === startChapterNumber && p.page > 1) return p.page;
|
||||||
return 1;
|
return 1;
|
||||||
@ -322,15 +324,17 @@ export function PageReader({
|
|||||||
|
|
||||||
// All reader Links use scroll={false} to preserve scroll during in-reader
|
// All reader Links use scroll={false} to preserve scroll during in-reader
|
||||||
// nav (natural scroll between chapters updates URL without remount). On
|
// nav (natural scroll between chapters updates URL without remount). On
|
||||||
// a fresh mount we must actively position the scroll: resume-to-saved
|
// a fresh mount we position scroll: resume-to-saved if ?resume=1 (from
|
||||||
// if ?resume=1 AND the saved chapter matches; otherwise top.
|
// 继续阅读) OR a page reload (so browser refresh preserves position).
|
||||||
|
// Plain chapter-link clicks from drawer / list go to top.
|
||||||
const resumeDoneRef = useRef(false);
|
const resumeDoneRef = useRef(false);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (resumeDoneRef.current) return;
|
if (resumeDoneRef.current) return;
|
||||||
resumeDoneRef.current = true;
|
resumeDoneRef.current = true;
|
||||||
const instantTop = (top: number) =>
|
const instantTop = (top: number) =>
|
||||||
window.scrollTo({ top, behavior: "instant" as ScrollBehavior });
|
window.scrollTo({ top, behavior: "instant" as ScrollBehavior });
|
||||||
if (!resume) {
|
const shouldResume = resume || isPageReload();
|
||||||
|
if (!shouldResume) {
|
||||||
instantTop(0);
|
instantTop(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,3 +66,13 @@ export function writeProgress(
|
|||||||
function defaultStorage(): StorageLike | null {
|
function defaultStorage(): StorageLike | null {
|
||||||
return typeof window === "undefined" ? null : window.localStorage;
|
return typeof window === "undefined" ? null : window.localStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isPageReload(): boolean {
|
||||||
|
if (typeof window === "undefined") return false;
|
||||||
|
if (typeof performance === "undefined") return false;
|
||||||
|
const entries = performance.getEntriesByType("navigation");
|
||||||
|
if (entries.length === 0) return false;
|
||||||
|
return (
|
||||||
|
(entries[0] as PerformanceNavigationTiming).type === "reload"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user