Skip resetting loading state to true when the blob URL already exists,
avoiding an unnecessary opacity-0 → opacity-100 CSS transition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use router.replace instead of router.push when auto-advancing to next book,
so closing the reader navigates back to the series view instead of the previous book.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a toggleable anonymous mode (eye icon in header) that:
- Stops syncing read progress to the server while reading
- Hides mark as read/unread buttons on book covers and lists
- Hides reading status badges on series and books
- Hides progress bars on series and book covers
- Hides "continue reading" and "continue series" sections on home
- Persists the setting server-side in user preferences (anonymousMode)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show an orange badge with BookX icon on series covers when the Stripstream
API reports missing books in the collection. Also display a warning status
badge on the series detail page header.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow users to expand long series descriptions with a "Show more" button
and scroll through the full text, instead of being limited to 3 lines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only render <img> when blob URL is available from prefetch, preventing
broken image icons from src={undefined} or failed direct URL fallbacks.
Reset error state when blob URL arrives to recover from transient failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetch metadata from GET /libraries/{id}/series/{name}/metadata and display
authors with icon and description in the series header.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Temporarily inject maximum-scale=1 into viewport meta tag on orientation
change to cancel the automatic zoom iOS Safari applies, then restore
it to keep pinch-zoom available.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After pinch-zoom then de-zoom, visualViewport.scale may not return
exactly to 1.0, blocking swipe navigation. Use 1.05 threshold instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Arrow buttons now swap next/previous in RTL mode. Swipe navigation
receives isRTL from parent state instead of creating its own independent
copy, so toggling direction takes effect immediately without reload.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses /books/ongoing as single source for Stripstream, displayed with
featured header style. Removes separate "up next" section.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Displays a carousel of favorite series after the ongoing sections.
Hidden when the user has no favorites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix POST requests (series/list, books/list) not being cached by Next.js fetch cache
by wrapping them with unstable_cache in the private fetch method
- Wrap getHomeData() entirely with unstable_cache so all 5 home requests are cached
as a single unit, reducing cold-start cost from 5 parallel calls to 0 on cache hit
- Remove N+1 book count enrichment from getLibraries() (8 extra calls per cold start)
as LibraryDto does not return booksCount and the value was only used in BackgroundSettings
- Simplify getLibraryById() to reuse cached getLibraries() data instead of making
separate HTTP calls (saves 2 calls per library page load)
- Fix cache debug logs: replace misleading x-nextjs-cache header check (always UNKNOWN
on external APIs) with pre-request logs showing the configured cache strategy
- Remove book count display from BackgroundSettings as it is no longer fetched
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Introduced a new resolver function to streamline fetching Stripstream configuration from the database or environment variables.
- Updated various components and API routes to utilize the new configuration resolver, improving code maintainability and reducing direct database calls.
- Added optional environment variables for Stripstream URL and token in the .env.example file.
- Refactored image loading logic in the reader components to improve performance and error handling.
- Introduce provider abstraction layer (IMediaProvider, KomgaProvider, StripstreamProvider)
- Add Stripstream Librarian as second media provider with full feature parity
- Migrate all pages and components from direct Komga services to provider factory
- Remove dead service code (BaseApiService, HomeService, LibraryService, SearchService, TestService)
- Fix library/series page-based pagination for both providers (Komga 0-indexed, Stripstream 1-indexed)
- Fix unread filter and search on library page for both providers
- Fix read progress display for Stripstream (reading_status mapping)
- Fix series read status (books_read_count) for Stripstream
- Add global search with series results for Stripstream (series_hits from Meilisearch)
- Fix thumbnail proxy to return 404 gracefully instead of JSON on upstream error
- Replace duration-based cache debug detection with x-nextjs-cache header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Show a clean placeholder (icon + label) instead of the browser's broken image icon when a page fails to load
- Track error state per page (page 1 and page 2) and reset on page navigation
- Center each page within its half in double page mode instead of pushing toward the spine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add revalidateForRefresh(scope, id) server action for home/library/series
- Library/Series wrappers: revalidate cache then router.refresh(), 400ms delay for animation
- Home: revalidate home-data + path before refresh
- RefreshButton uses refreshLibrary from RefreshContext when not passed as prop
- Library/Series pages pass id to wrapper for context and pull-to-refresh
- read-progress: pass 'max' to revalidateTag for Next 16 types
Made-with: Cursor
Refine the global loading experience to feel smoother and less flashy while keeping brand accents. Simplify the home continue-reading highlight by styling the section header instead of using a heavy card wrapper.
Move library header/covers to deterministic server-side rendering, split preference controls into controlled/uncontrolled modes, and remove client cover wrapper to eliminate hydration mismatches and provider coupling on library pages.
- Add src/app/actions/admin.ts with updateUserRoles, deleteUser, resetUserPassword
- Update EditUserDialog, DeleteUserDialog, ResetPasswordDialog to use Server Actions
- Remove admin users API routes (PATCH/DELETE/PUT)
- Add src/app/actions/library.ts with scanLibrary
- Update ScanButton to use Server Action
- Remove POST from api/komga/libraries/[libraryId]/scan route
- Add src/app/actions/favorites.ts with addToFavorites and removeFromFavorites
- Update SeriesHeader to use Server Actions instead of fetch
- Keep API route GET only (POST/DELETE removed)
- Create src/app/actions/read-progress.ts with updateReadProgress and deleteReadProgress
- Update mark-as-read-button and mark-as-unread-button to use Server Actions
- Update usePageNavigation hook to use Server Action
- Use revalidateTag with 'min' profile for cache invalidation