From 079290f881e422b03e504da27f89d4e997e63a25 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Wed, 28 Jan 2026 23:55:47 -0800 Subject: feat(Landing): Update to match LandingHero --- src/lib/Landing.svelte | 553 +++++++++++++++++++++------ src/lib/List/Anime/AnimeListTemplate.svelte | 3 + src/lib/List/Anime/CleanAnimeList.svelte | 2 + src/lib/List/Anime/CompletedAnimeList.svelte | 58 ++- src/lib/List/CleanGrid.svelte | 4 +- src/lib/List/Manga/CleanMangaList.svelte | 3 +- src/lib/List/Manga/MangaListTemplate.svelte | 44 ++- src/routes/+page.svelte | 6 +- 8 files changed, 499 insertions(+), 174 deletions(-) (limited to 'src') diff --git a/src/lib/Landing.svelte b/src/lib/Landing.svelte index 8fb8f72b..4c824a8d 100644 --- a/src/lib/Landing.svelte +++ b/src/lib/Landing.svelte @@ -1,154 +1,481 @@ -
-
-
- -
-
+
+
+
+
+
+ +
+
-
- Manga, Without the Guesswork + -
+

+ Automatically track new chapters, get notified of releases, and stay organised. Completed + and ongoing series stay neatly arranged so you can instantly see what needs your + attention. +

+

Simulated data shown

+
+
+ - +
+
+ +
+ +
+
+ + +
+ + +
(demoFocused = true)} + role="button" + tabindex="0" + onkeydown={(e) => e.key === 'Enter' && (demoFocused = true)} + > + Demo +
+
+
+
- - -
-
- Smarter Tools, Better Experience - -

- due.moe isn't just tracking—it's a full suite of tools designed to enhance - your AniList experience. From Wrapped to Sequel Spy, everything you need is right here. -

- -
    -
  • AniList Wrapped — Your Year on AniList
  • -
  • - Badge Wall — A unified badge collection experience for AniList -
    - Easily display all of your earned badges in a single place, with your Anime Watching Club - (AWC) badges automatically included! -
    -
  • -
  • - Subtitle Schedule — A release calendar which displaying the - scheduled subtitle release times for simulcast anime! -
  • -
  • - Today's Character Birthdays — A calendar to help you stay up - to date with your favourite characters' birthdays, featuring an even bigger character database - than AniList! -
  • -
  • - Sequel Spy — Find media with prequels you haven't seen - for any simulcast season -
  • -
- -

- - - { - await localforage.setItem( - 'redirect', - window.location.origin + window.location.pathname + window.location.search - ); - }}>Log in - with AniList, and due.moe does the rest. - -
+{#if demoFocused} +
(demoFocused = false)} + role="button" + tabindex="0" + onkeydown={(e) => e.key === 'Escape' && (demoFocused = false)} + > +
+ Demo -
- - Demo - +

Click anywhere to close

+
-
+{/if} diff --git a/src/lib/List/Anime/AnimeListTemplate.svelte b/src/lib/List/Anime/AnimeListTemplate.svelte index 6e8d6d6c..bcd4e806 100644 --- a/src/lib/List/Anime/AnimeListTemplate.svelte +++ b/src/lib/List/Anime/AnimeListTemplate.svelte @@ -31,6 +31,7 @@ export let notYetReleased = false; export let dummy = false; export let disableFilter = false; + export let limit: number | undefined = undefined; let lastUpdatedMedia = -1; let previousAnimeList: Media[]; @@ -69,6 +70,7 @@ bind:pendingUpdate {dummy} {disableFilter} + {limit} /> {:else} @@ -91,6 +93,7 @@ bind:pendingUpdate {dummy} {disableFilter} + {limit} /> {/if} {:catch} diff --git a/src/lib/List/Anime/CleanAnimeList.svelte b/src/lib/List/Anime/CleanAnimeList.svelte index fef76c03..04b1d03c 100644 --- a/src/lib/List/Anime/CleanAnimeList.svelte +++ b/src/lib/List/Anime/CleanAnimeList.svelte @@ -33,6 +33,7 @@ export let notYetReleased = false; export let dummy = false; export let disableFilter = false; + export let limit: number | undefined = undefined; let showRoulette = false; let keyCacher: NodeJS.Timeout; @@ -183,6 +184,7 @@ {upcoming} {notYetReleased} reverseSort={$settings.displayReverseSort} + {limit} >
{#if !upcoming && !notYetReleased} diff --git a/src/lib/List/Anime/CompletedAnimeList.svelte b/src/lib/List/Anime/CompletedAnimeList.svelte index 8e914ef6..b9e86ba0 100644 --- a/src/lib/List/Anime/CompletedAnimeList.svelte +++ b/src/lib/List/Anime/CompletedAnimeList.svelte @@ -18,7 +18,9 @@ tokenType: '' }; export let dummy = false; + export let dummyCount = 7; export let disableFilter = false; + export let limit: number | undefined = undefined; let animeLists: Promise; let startTime: number; let endTime: number; @@ -27,40 +29,29 @@ startTime = performance.now(); if (dummy) { + // Use deterministic selection for consistent display + const filtered = sampleAnime.filter( + (anime) => + anime.episodes && + !anime.tags.some((tag) => tag.name === 'Nudity') && + !anime.tags.some((tag) => tag.name === 'Rape') && + !anime.tags.some((tag) => tag.name === 'Tragedy') && + !anime.tags.some((tag) => tag.name === 'Bondage') && + !anime.genres.some((genre) => genre === 'Hentai') && + anime.genres.some((genre) => genre === 'Comedy') && + anime.status !== 'NOT_YET_RELEASED' && + anime.episodes > 1 + ); animeLists = Promise.resolve( - sampleAnime - .filter( - (anime) => - anime.episodes && - !anime.tags.some((tag) => tag.name === 'Nudity') && - !anime.tags.some((tag) => tag.name === 'Rape') && - !anime.tags.some((tag) => tag.name === 'Tragedy') && - !anime.tags.some((tag) => tag.name === 'Bondage') && - !anime.genres.some((genre) => genre === 'Hentai') && - anime.genres.some((genre) => genre === 'Comedy') && - anime.status !== 'NOT_YET_RELEASED' && - anime.episodes > 1 - ) - .sort(() => 0.5 - Math.random()) - .map((anime) => { - const nextEpisode = Math.floor(Math.random() * (anime.episodes || 0)) + 1 || 1; - - anime.status = 'FINISHED'; - anime.nextAiringEpisode = { - airingAt: - Math.floor(Date.now() / 1000) + - Math.floor(Math.random() * 7 * 24 * 60 * 60) + - 60 * 60, - episode: Math.floor(Math.random() * (anime.episodes || 0)) + 1 || 1 - }; - anime.mediaListEntry.progress = Math.floor(Math.random() * nextEpisode) || 1; - - return anime; - }) - .sort( - (a, b) => (a.nextAiringEpisode?.airingAt || 0) - (b.nextAiringEpisode?.airingAt || 0) - ) - .slice(0, 7) as unknown as Media[] + filtered.slice(0, dummyCount).map((anime, index) => { + anime.status = 'FINISHED'; + anime.nextAiringEpisode = { + airingAt: Math.floor(Date.now() / 1000) + (index + 1) * 24 * 60 * 60, + episode: Math.floor((anime.episodes || 12) * 0.8) + }; + anime.mediaListEntry.progress = Math.floor((anime.nextAiringEpisode.episode || 5) * 0.6); + return anime; + }) as unknown as Media[] ); } else { animeLists = mediaListCollection(user, $identity, Type.Anime, $anime, $lastPruneTimes.anime, { @@ -127,4 +118,5 @@ completed {dummy} {disableFilter} + {limit} /> diff --git a/src/lib/List/CleanGrid.svelte b/src/lib/List/CleanGrid.svelte index 119e4d71..ed4a9733 100644 --- a/src/lib/List/CleanGrid.svelte +++ b/src/lib/List/CleanGrid.svelte @@ -13,10 +13,12 @@ export let upcoming = false; export let notYetReleased = false; export let reverseSort = false; + export let limit: number | undefined = undefined; let uniqueID = new Date().getTime(); - $: processedMedia = reverseSort ? media.reverse() : media; + $: sortedMedia = reverseSort ? media.reverse() : media; + $: processedMedia = limit !== undefined ? sortedMedia.slice(0, limit) : sortedMedia;
; @@ -165,7 +166,7 @@ {/if} {#if $settings.displayCoverModeManga || dummy} - +
{pendingUpdate === manga.id ? progress + 1 : progress}{#if !due} /{manga.chapters || '?'} diff --git a/src/lib/List/Manga/MangaListTemplate.svelte b/src/lib/List/Manga/MangaListTemplate.svelte index 16665d56..c2fc0513 100644 --- a/src/lib/List/Manga/MangaListTemplate.svelte +++ b/src/lib/List/Manga/MangaListTemplate.svelte @@ -31,7 +31,9 @@ export let displayUnresolved: boolean; export let due: boolean; export let dummy = $settings.debugDummyLists || false; + export let dummyCount = 7; export let disableFilter = false; + export let limit: number | undefined = undefined; const authorised = privilegedUser($identity.id); let mangaLists: Promise; let startTime: number; @@ -67,28 +69,25 @@ startTime = performance.now(); if (dummy) { + // Use deterministic selection for consistent display + const filtered = sampleManga.filter( + (manga) => + manga.chapters && + !manga.tags.some((tag) => tag.name === 'Nudity') && + !manga.tags.some((tag) => tag.name === 'Rape') && + !manga.tags.some((tag) => tag.name === 'Tragedy') && + !manga.tags.some((tag) => tag.name === 'Bondage') && + !manga.genres.some((genre) => genre === 'Hentai') && + manga.genres.some((genre) => genre === 'Comedy') && + manga.status !== 'NOT_YET_RELEASED' + ); mangaLists = Promise.resolve( - sampleManga - .filter( - (manga) => - manga.chapters && - !manga.tags.some((tag) => tag.name === 'Nudity') && - !manga.tags.some((tag) => tag.name === 'Rape') && - !manga.tags.some((tag) => tag.name === 'Tragedy') && - !manga.tags.some((tag) => tag.name === 'Bondage') && - !manga.genres.some((genre) => genre === 'Hentai') && - manga.genres.some((genre) => genre === 'Comedy') && - manga.status !== 'NOT_YET_RELEASED' - ) - .sort(() => 0.5 - Math.random()) - .map((manga) => { - manga.status = 'FINISHED'; - manga.episodes = Math.floor(Math.random() * (manga.chapters || 0)) as unknown as null; - manga.mediaListEntry.progress = Math.floor(Math.random() * (manga.episodes || 0)) + 1; - - return manga; - }) - .slice(0, 7) as unknown as Media[] + filtered.slice(0, dummyCount).map((manga) => { + manga.status = 'FINISHED'; + manga.episodes = Math.floor((manga.chapters || 10) * 0.7) as unknown as null; + manga.mediaListEntry.progress = Math.floor((manga.episodes || 5) * 0.5) + 1; + return manga; + }) as unknown as Media[] ); } else { mangaLists = mediaListCollection(user, $identity, Type.Manga, $manga, $lastPruneTimes.manga, { @@ -262,6 +261,7 @@ {authorised} {dummy} {disableFilter} + {limit} /> {:else} {#if !authorised} @@ -310,6 +310,7 @@ {authorised} {dummy} {disableFilter} + {limit} /> {:else} {#if !authorised} @@ -378,6 +379,7 @@ {authorised} {dummy} {disableFilter} + {limit} /> {:catch} {#if authorised} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a66d10c2..ca356724 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -36,11 +36,7 @@ {#if data.user === undefined} - - -
Please log in to view due media.
- - + {:else} -- cgit v1.2.3