feat(web): accueil — refonte sobre et moderne : hero resserré, cartes de livres simplifiées (renderHomeBook : couverture + titre + auteur, sans pill de métadonnées ni Meter) et liste des livres en cours limitée à 3 éléments visibles avant scroll (tuiles 112px — évolution #45)

This commit is contained in:
Git Agent
2026-08-28 23:07:39 +02:00
parent cf8779781f
commit 11bb529322
3 changed files with 144 additions and 41 deletions

View File

@ -1,10 +1,9 @@
import { useEffect, useState } from "react";
import { BookOpen, LibraryBig, ScanLine } from "lucide-react";
import { api } from "../api/client";
import { hasActiveCoverWork, isBookCoverUpdating, type DashboardData } from "../api/types";
import { bookDisplayTitle, bookMetadataState, bookMetadataStateLabel, bookVolumeLabel, displayPublishedDate } from "../book/metadata";
import { BookCard } from "../components/BookCard";
import { EmptyState, LoadingState, Meter, Panel } from "../components/ui";
import type { DashboardData } from "../api/types";
import { bookDisplayTitle, bookVolumeLabel } from "../book/metadata";
import { EmptyState, LoadingState, Panel } from "../components/ui";
import { navigate } from "../router";
export function HomePage() {
@ -28,14 +27,29 @@ export function HomePage() {
}, []);
if (!state) return <LoadingState />;
const fallbackCoverLoading = hasActiveCoverWork(state.jobs);
const renderHomeBook = (item: DashboardData["books"][number], className = "home-book-card") => {
const volumeLabel = bookVolumeLabel(item);
return (
<button key={item.id} className={className} onClick={() => navigate(`/book/${item.id}`)}>
<span className="home-book-cover" aria-hidden="true">
{item.coverPath ? <img src={api.bookCoverUrl(item.id)} alt="" /> : <BookOpen size={24} />}
</span>
<span className="home-book-copy">
{volumeLabel && <span className="home-book-volume">{volumeLabel}</span>}
<strong>{bookDisplayTitle(item)}</strong>
<span>{item.author ?? "Auteur inconnu"}</span>
</span>
</button>
);
};
return (
<div className="page-grid">
<section className="hero-band">
<div className="page-grid home-page">
<section className="hero-band home-hero">
<div>
<p>Cabinet de curiosites numerique</p>
<h1>Ouvrir, classer, reprendre.</h1>
<p>Bibliotheque personnelle</p>
<h1>Reprendre la lecture.</h1>
<span>{fallback ? "API absente ou incomplete : specimens de demonstration actifs." : "Catalogue branche sur le serveur local."}</span>
</div>
<button className="primary-button" onClick={() => navigate("/search")}>
@ -46,30 +60,12 @@ export function HomePage() {
<Panel className="span-2">
<div className="section-heading">
<h2>Reprise de lecture</h2>
<span>{state.continueReading.length} traces</span>
<h2>Livres en cours</h2>
<span>{state.continueReading.length} lectures</span>
</div>
{state.continueReading.length ? (
<div className="continue-grid">
{state.continueReading.map((item) => {
const metadataState = bookMetadataState(item.book);
const publishedDate = displayPublishedDate(item.book.publishedDate);
const volumeLabel = bookVolumeLabel(item.book);
return (
<button key={item.book.id} className="continue-tile" onClick={() => navigate(`/reader/${item.book.id}`)}>
<span className="continue-cover" aria-hidden="true">
{item.book.coverPath ? <img src={api.bookCoverUrl(item.book.id)} alt="" /> : <BookOpen size={22} />}
</span>
<span className="continue-copy">
<strong>{bookDisplayTitle(item.book)}</strong>
<span>{item.book.author ?? "Auteur inconnu"}</span>
{(volumeLabel || publishedDate) && <span>{[volumeLabel, publishedDate].filter(Boolean).join(" · ")}</span>}
<span className={`metadata-pill metadata-${metadataState}`}>{bookMetadataStateLabel(item.book)}</span>
<Meter value={item.progress.percent} />
</span>
</button>
);
})}
{state.continueReading.map((item) => renderHomeBook(item.book, "home-book-card continue-tile"))}
</div>
) : (
<EmptyState title="Aucune trace" detail="Les lectures reprises apparaitront ici." />
@ -91,10 +87,8 @@ export function HomePage() {
</div>
</Panel>
<section className="book-grid span-3">
{state.books.map((book) => (
<BookCard key={book.id} book={book} coverLoading={isBookCoverUpdating(book, fallbackCoverLoading)} />
))}
<section className="home-book-grid span-3">
{state.books.map((book) => renderHomeBook(book))}
</section>
</div>
);