- Add width/height columns to Page (default 0, migration SQL committed).
- Backfill script ranges first 16KB of each R2 object and parses with
image-size. Probed all 26,209 existing pages successfully.
- Export keyFromPublicUrl from lib/r2 so the script reuses the existing
URL→key logic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the user resumes at a mid-chapter page, the reader previously
skipped the earlier pages entirely. This adds a scroll-up prefetch so
those earlier pages appear smoothly as the user scrolls toward the top.
- prependBatch() mirrors fetchBatch but decrements the offset cursor
and prepends the new pages. prependExhaustedRef fires when the
cursor hits 0 (start of chapter).
- Trigger: scrollY < 2500px fires prepend — well before the user
reaches the top, so the DOM + images spawn ahead of the scroll
position.
- Scroll preservation: aspect-[3/4] on <img> reserves vertical space
before the image bytes arrive, so scrollHeight is accurate
immediately after React commits. A single scrollBy(delta) keeps the
previously-visible page visually anchored — no per-image jitter.
- Forward-fetch trigger indices + loadedCountRef are shifted by
batch.length on each prepend so next-batch prefetch still fires at
the correct page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upgrades the reader's last-read tracking from {chapter} to {chapter, page}.
- ReadingProgressButton: storage is now JSON {chapter, page}; legacy
bare-number values are read back as {chapter, page: 1}. Button label
is unchanged ("继续阅读 · #N title") — the extra precision lives in
the reader's first-fetch offset, not the label.
- PageReader: on mount with saved progress, seed offsetRef to
(page - 1) so the first /api/pages call starts AT the resumed page
instead of the beginning of the chapter. currentPageNum state is
initialized from storage too, so the first persist write is a no-op
that matches the saved value.
- Scroll tracker now also tracks currentPageNum (last page whose top
has crossed above viewport top+80), and persistence writes the
{chapter, page} pair on each change.
Known limitation: earlier pages of the resumed chapter aren't loaded
yet — a follow-up commit adds scroll-up prefetch for those.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reading progress
- New ReadingProgressButton client component that reads/writes
localStorage key "sunnymh:last-read:{slug}"
- PageReader writes the currently-visible chapter as the user scrolls
through continuous chapters
- Manga detail CTA now reads: "开始阅读" on first visit, or
"继续阅读 · #{N} {title}" when a prior chapter is stored (with
spacing and truncation for long titles)
Multiple genres
- lib/genres.ts with parseGenres() and collectGenres() helpers to
split "冒险, 恋爱, 魔幻" into a list and aggregate across a collection
- Manga detail renders one pill per genre
- GenreTabs filters via parseGenres(...).includes(activeGenre) so a
multi-genre manga appears under each of its genres
- Home / Genre pages compute the tab list from collectGenres(signedManga)
- Card captions (GenreTabs + TrendingCarousel) show "冒险 · 恋爱 · 魔幻"
with truncation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the fixed-position reader with a sticky layout that works
correctly on iPhone Safari and Edge, while also auto-appending the
next chapter's pages when the current one finishes.
Layout
- Swap all position:fixed for sticky (Header, BottomNav, reader top nav)
— fixed-positioning quirks broke the bottom nav in Edge and
prevented Safari's URL bar from collapsing on scroll
- Viewport: viewport-fit=cover + interactiveWidget=overlays-content
so manga extends edge-to-edge and the URL bar overlays content
without resizing the viewport
- Add pt-safe / pb-safe utilities; apply on nav bars so chrome
respects the notch and home-indicator
- Drop fixed-positioning bottom padding now that BottomNav is in flow
Continuous reading
- PageReader now receives the full chapter manifest (id + totalPages)
and auto-fetches the next chapter when the current one is done
- Subtle chapter divider strip appears between chapters in the scroll
- Top nav chapter title updates as the user scrolls into a new chapter
(rAF-throttled scroll listener, cached offsetTop)
- Double-tap on left/right viewport half navigates prev/next chapter
- End-of-manga footer fills the viewport with a Back-to-Manga action
Theme polish
- Light theme: white body/background, blue accent preserved for
chapter numbers, badges, active states
- Modern chapter drawer: white sheet, rounded-t-3xl, two-column
rows with chapter-number badge, blue highlight for current chapter
- Suppress hydration warnings for extension-injected attributes on
<html> and the search input
- Manga detail CTA localized to 开始阅读
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
- Sign all image URLs server-side with 60s expiry presigned URLs
- Add /api/pages endpoint for batched page fetching (7 per batch)
- PageReader prefetches next batch when user scrolls to 3rd page
- Move chapter count badge outside overflow-hidden for 3D effect
- Fix missing URL signing on search and genre pages
- Extract signCoverUrls helper to reduce duplication
- Clamp API limit param to prevent abuse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nav bars hide when scrolling down and reappear on scroll up.
Replace static page count with a chapter picker that opens as a
bottom sheet drawer for quick chapter navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simple landing page for initial Portainer GitOps deployment.
Includes Dockerfile, docker-compose.yml with pull_policy: build,
and project documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>