diff --git a/ui/src/routes/+page.svelte b/ui/src/routes/+page.svelte index c60b095..577fccc 100644 --- a/ui/src/routes/+page.svelte +++ b/ui/src/routes/+page.svelte @@ -10,194 +10,220 @@ try { const parsed = JSON.parse(genres); return Array.isArray(parsed) ? parsed : []; - } catch { - return []; - } + } catch { return []; } } + + // Deduplicate recentlyUpdated by slug, keeping the first occurrence and + // counting how many times the same book appears (= new chapters added). + const dedupedRecent = $derived.by(() => { + const seen = new Map(); + for (const book of data.recentlyUpdated) { + if (seen.has(book.slug)) { + seen.get(book.slug)!.count++; + } else { + seen.set(book.slug, { book, count: 1 }); + } + } + return [...seen.values()]; + }); + + const GENRES = [ + 'Action', 'Fantasy', 'Romance', 'Cultivation', 'System', + 'Reincarnation', 'Sci-Fi', 'Horror', 'Slice of Life', 'Adventure', + ]; + + // Hero = first continue-reading item; shelf = the rest + const heroBook = $derived(data.continueReading[0] ?? null); + const shelfBooks = $derived(data.continueReading.slice(1)); {m.home_title()} - -
-
-

{data.stats.totalBooks}

-

{m.home_stat_books()}

-
-
-

{data.stats.totalChapters.toLocaleString()}

-

{m.home_stat_chapters()}

-
-
-

{data.stats.booksInProgress}

-

{m.home_stat_in_progress()}

-
-
- - -{#if data.continueReading.length > 0} -
-
-

{m.home_continue_reading()}

- {m.home_view_all()} + +{#if heroBook} +
+ + +
+ {#if heroBook.book.cover} + {heroBook.book.title} + {:else} +
+ + + +
+ {/if}
-
+{/if} + + +{#if shelfBooks.length > 0} +
+
+

{m.home_continue_reading()}

+ {m.home_view_all()} +
+ +
+{/if} + + +
+
+

Browse by genre

+ {m.home_view_all()} +
+
+ {#each GENRES as genre} + + {genre} + + {/each} +
+
+ + +{#if dedupedRecent.length > 0} +
+
+

{m.home_recently_updated()}

+ {m.home_view_all()} +
+ -
-{/if} - - -{#if data.recentlyUpdated.length > 0} -
-
-

{m.home_recently_updated()}

- {m.home_view_all()} -
- -
-{/if} - - -{#if data.continueReading.length === 0 && data.recentlyUpdated.length === 0} -
-

{m.home_empty_title()}

-

{m.home_empty_body()}

- - {m.home_discover_novels()} - + {/if} +
+
+

{book.title ?? ''}

+ {#if book.author} +

{book.author}

+ {/if} + {#if genres.length > 0} +
+ {#each genres.slice(0, 2) as genre} + {genre} + {/each} +
+ {/if} +
+ + {/each}
+
{/if} - + {#if data.subscriptionFeed.length > 0} -
-
-

{m.home_from_following()}

-
- -
+
+
+

{m.home_from_following()}

+
+ +
{/if} + + +{#if data.continueReading.length === 0 && dedupedRecent.length === 0} +
+

{m.home_empty_title()}

+

{m.home_empty_body()}

+ + {m.home_discover_novels()} + +
+{/if} + + +
+ {data.stats.totalBooks.toLocaleString()} {m.home_stat_books()} + + {data.stats.totalChapters.toLocaleString()} {m.home_stat_chapters()} +