feat(ui): add homepage with Continue Reading, Recently Updated, and stats

Replace the single-button placeholder with a full homepage:
- Stats bar: total books, total chapters, books in progress
- Continue Reading grid (up to 6): links directly to last chapter read
- Recently Updated grid (up to 6): recent books not already in progress
- Empty state with Discover Novels CTA when library is empty

New pocketbase.ts helpers: recentlyAddedBooks(), getHomeStats(),
listN(), countCollection().
This commit is contained in:
Admin
2026-03-04 12:55:03 +05:00
parent 5a7751e6d1
commit 06feb91f4f
3 changed files with 238 additions and 3 deletions

View File

@@ -130,6 +130,25 @@ async function listAll<T>(collection: string, filter = '', sort = ''): Promise<T
return data.items ?? [];
}
async function listN<T>(collection: string, n: number, filter = '', sort = ''): Promise<T[]> {
const params = new URLSearchParams({ perPage: String(n) });
if (filter) params.set('filter', filter);
if (sort) params.set('sort', sort);
const data = await pbGet<PBList<T>>(
`/api/collections/${collection}/records?${params.toString()}`
);
return data.items ?? [];
}
async function countCollection(collection: string, filter = ''): Promise<number> {
const params = new URLSearchParams({ perPage: '1' });
if (filter) params.set('filter', filter);
const data = await pbGet<PBList<unknown>>(
`/api/collections/${collection}/records?${params.toString()}`
);
return (data as { totalItems: number }).totalItems ?? 0;
}
async function listOne<T>(collection: string, filter: string): Promise<T | null> {
const params = new URLSearchParams({ perPage: '1', filter });
const data = await pbGet<PBList<T>>(
@@ -154,6 +173,27 @@ export async function getBook(slug: string): Promise<Book | null> {
return listOne<Book>('books', `slug="${slug}"`);
}
export async function recentlyAddedBooks(limit = 6): Promise<Book[]> {
return listN<Book>('books', limit, '', '-meta_updated');
}
export async function recentlyUpdatedBooks(limit = 6): Promise<Book[]> {
return listN<Book>('books', limit, '', '-meta_updated');
}
export interface HomeStats {
totalBooks: number;
totalChapters: number;
}
export async function getHomeStats(): Promise<HomeStats> {
const [totalBooks, totalChapters] = await Promise.all([
countCollection('books'),
countCollection('chapters_idx')
]);
return { totalBooks, totalChapters };
}
// ─── Chapter index ────────────────────────────────────────────────────────────
export async function listChapterIdx(slug: string): Promise<ChapterIdx[]> {