Switch nav toggle to tap-only and harden image protection

Replace scroll-direction nav reappear with a one-shot scroll-down hide
plus tap-on-image toggle. Distinguish tap from scroll on touch via
touchstart/touchmove tracking so swipes don't re-show the nav.
Discourage casual image saving with contextmenu prevent, draggable=false,
select-none, and -webkit-touch-callout:none. Add 10.8.0.2 to
allowedDevOrigins for VPN dev access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
yiekheng 2026-04-12 07:56:39 +08:00
parent 57255e2624
commit c099673f6b
2 changed files with 29 additions and 10 deletions

View File

@ -42,7 +42,7 @@ export function PageReader({
const [showUI, setShowUI] = useState(true);
const [showDrawer, setShowDrawer] = useState(false);
const [pages, setPages] = useState<PageData[]>([]);
const lastScrollY = useRef(0);
const hiddenByScrollRef = useRef(false);
const offsetRef = useRef(0);
const doneRef = useRef(false);
const loadingRef = useRef(false);
@ -127,17 +127,31 @@ export function PageReader({
[]
);
// Distinguish tap from scroll on touch devices
const touchMovedRef = useRef(false);
const onTouchStart = useCallback(() => {
touchMovedRef.current = false;
}, []);
const onTouchMove = useCallback(() => {
touchMovedRef.current = true;
}, []);
const onTap = useCallback(() => {
if (touchMovedRef.current) return;
setShowUI((v) => !v);
}, []);
// Hide nav on first scroll down; after that, only tap toggles
useEffect(() => {
const handleScroll = () => {
const currentY = window.scrollY;
if (currentY > lastScrollY.current && currentY > 50) {
if (!hiddenByScrollRef.current && window.scrollY > 50) {
hiddenByScrollRef.current = true;
setShowUI(false);
} else if (currentY < lastScrollY.current) {
setShowUI(true);
window.removeEventListener("scroll", handleScroll);
}
lastScrollY.current = currentY;
};
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
@ -178,8 +192,11 @@ export function PageReader({
{/* Pages - vertical scroll (webtoon style, best for mobile) */}
<div
className="max-w-4xl mx-auto leading-[0]"
onClick={() => setShowUI(!showUI)}
className="max-w-4xl mx-auto leading-[0] select-none"
onClick={onTap}
onTouchStart={onTouchStart}
onTouchMove={onTouchMove}
onContextMenu={(e) => e.preventDefault()}
>
{pages.map((page, i) => (
<div
@ -191,7 +208,8 @@ export function PageReader({
<img
src={page.imageUrl}
alt={`Page ${page.number}`}
className="w-full h-auto block align-bottom -mb-px"
className="w-full h-auto block align-bottom -mb-px [-webkit-touch-callout:none]"
draggable={false}
/>
</div>
))}

View File

@ -1,6 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
allowedDevOrigins: ["10.8.0.2"],
images: {
remotePatterns: [
{