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:
parent
57255e2624
commit
c099673f6b
@ -42,7 +42,7 @@ export function PageReader({
|
|||||||
const [showUI, setShowUI] = useState(true);
|
const [showUI, setShowUI] = useState(true);
|
||||||
const [showDrawer, setShowDrawer] = useState(false);
|
const [showDrawer, setShowDrawer] = useState(false);
|
||||||
const [pages, setPages] = useState<PageData[]>([]);
|
const [pages, setPages] = useState<PageData[]>([]);
|
||||||
const lastScrollY = useRef(0);
|
const hiddenByScrollRef = useRef(false);
|
||||||
const offsetRef = useRef(0);
|
const offsetRef = useRef(0);
|
||||||
const doneRef = useRef(false);
|
const doneRef = useRef(false);
|
||||||
const loadingRef = 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(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
const currentY = window.scrollY;
|
if (!hiddenByScrollRef.current && window.scrollY > 50) {
|
||||||
if (currentY > lastScrollY.current && currentY > 50) {
|
hiddenByScrollRef.current = true;
|
||||||
setShowUI(false);
|
setShowUI(false);
|
||||||
} else if (currentY < lastScrollY.current) {
|
window.removeEventListener("scroll", handleScroll);
|
||||||
setShowUI(true);
|
|
||||||
}
|
}
|
||||||
lastScrollY.current = currentY;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("scroll", handleScroll, { passive: true });
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
return () => window.removeEventListener("scroll", handleScroll);
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
}, []);
|
}, []);
|
||||||
@ -178,8 +192,11 @@ export function PageReader({
|
|||||||
|
|
||||||
{/* Pages - vertical scroll (webtoon style, best for mobile) */}
|
{/* Pages - vertical scroll (webtoon style, best for mobile) */}
|
||||||
<div
|
<div
|
||||||
className="max-w-4xl mx-auto leading-[0]"
|
className="max-w-4xl mx-auto leading-[0] select-none"
|
||||||
onClick={() => setShowUI(!showUI)}
|
onClick={onTap}
|
||||||
|
onTouchStart={onTouchStart}
|
||||||
|
onTouchMove={onTouchMove}
|
||||||
|
onContextMenu={(e) => e.preventDefault()}
|
||||||
>
|
>
|
||||||
{pages.map((page, i) => (
|
{pages.map((page, i) => (
|
||||||
<div
|
<div
|
||||||
@ -191,7 +208,8 @@ export function PageReader({
|
|||||||
<img
|
<img
|
||||||
src={page.imageUrl}
|
src={page.imageUrl}
|
||||||
alt={`Page ${page.number}`}
|
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>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
|
allowedDevOrigins: ["10.8.0.2"],
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user