Archived
- Backend: Book model with reading progress, DRF ViewSet with full CRUD, search, sort, filter, pagination, mark-as-finished, stats endpoint - Frontend: Library grid, BookCard, BookDetail, BookForm components with React 19 + TypeScript + Vite - Tests: 29 passing tests covering models, API, serializers, permissions - Spec: backend api-spec.md and frontend component-spec.md in docs/ Closes crisleo-hermes/cloud-reader#3
3.2 KiB
3.2 KiB
Frontend Component Specification — Cloud Reader
Overview
React 19 + TypeScript SPA using Vite for development and production builds. State managed via React hooks and Context API. Routing via react-router-dom v7 with lazy/Suspense for code splitting.
Components
App (root)
- Path:
/ - Layout: Header with logo +
<Routes>wrapper - Routing:
/→Library,*→ redirect to/ - Code splitting:
Libraryloaded viaReact.lazy+<Suspense>
Library
- State:
books[],stats,search,sortBy,statusFilter,currentPage,view - Views:
library(grid),detail(selected book),add(modal form) - Sub-components:
BookCard,BookDetail,BookForm - Data flow: Calls
fetchBooks()on mount and when filters/page change
BookCard
- Props:
{ book: Book, onClick: (book: Book) => void } - Display: Cover image (or first-letter placeholder), title, author, genre badge, reading progress bar with status color
- Interaction: Click/keyboard-accessible (Enter/Space)
BookDetail
- Props:
{ bookId: number, onBack: () => void, onUpdated: () => void } - Sections: Cover, metadata (title, author, genre, ISBN), progress bar with page count, action buttons
- Actions: Mark as Finished, Edit Details (switches to BookForm), Delete (with confirmation)
- States: Loading, error, editing mode
BookForm
- Props:
{ initialData?: Book, onSubmit: (data: BookFormData) => Promise<void>, onCancel: () => void } - Fields: Title*, Author*, Genre, Description, Cover URL, ISBN, Total Pages, Current Page, Status
- Client validation: Title/author required, page ≤ total pages
- Loading state: Submit button shows "Saving..." when
isLoading
Types
interface Book {
id: number; title: string; author: string; genre: string;
description: string; cover_image_url: string; isbn: string;
total_pages: number; current_page: number;
reading_status: ReadingStatus; reading_progress: number;
owner: string; created_at: string; updated_at: string;
}
type ReadingStatus = 'not_started' | 'reading' | 'finished' | 'dnf';
interface BookFormData {
title: string; author: string; genre: string;
description: string; cover_image_url: string; isbn: string;
total_pages: number; current_page: number; reading_status: ReadingStatus;
}
API Client (api/books.ts)
| Function | HTTP Call |
|---|---|
fetchBooks(params) |
GET /api/books/ |
fetchBook(id) |
GET /api/books/{id}/ |
createBook(data) |
POST /api/books/ |
updateBook(id, data) |
PATCH /api/books/{id}/ |
deleteBook(id) |
DELETE /api/books/{id}/ |
markAsFinished(id) |
POST /api/books/{id}/mark_finished/ |
fetchBookStats() |
GET /api/books/stats/ |
Styling
Dark theme with CSS custom properties. All styles in App.css. Responsive grid layout with breakpoint at 768px.
Build & Dev
yarn workspace frontend dev— Vite dev server on port 5173 with API proxy to 127.0.0.1:8000yarn workspace frontend build— TypeScript check + Vite production build