aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tools/Wrapped
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-10-28 15:32:46 -0700
committerFuwn <[email protected]>2024-10-28 15:32:46 -0700
commit39b677404558ae3b7eb34e818d7ca308f62f9cb0 (patch)
tree7f19fca39ecd4237e3c0d1aef2d8e9fa3cec7845 /src/lib/Tools/Wrapped
parentfeat(graphql): paged badges query (diff)
downloaddue.moe-svelte-5.tar.xz
due.moe-svelte-5.zip
feat: update to svelte 5svelte-5
Diffstat (limited to 'src/lib/Tools/Wrapped')
-rw-r--r--src/lib/Tools/Wrapped/ActivityHistory.svelte17
-rw-r--r--src/lib/Tools/Wrapped/Media.svelte33
-rw-r--r--src/lib/Tools/Wrapped/MediaExtras.svelte21
-rw-r--r--src/lib/Tools/Wrapped/Tool.svelte312
-rw-r--r--src/lib/Tools/Wrapped/Top/Activity.svelte22
-rw-r--r--src/lib/Tools/Wrapped/Top/Anime.svelte10
-rw-r--r--src/lib/Tools/Wrapped/Top/Manga.svelte8
7 files changed, 239 insertions, 184 deletions
diff --git a/src/lib/Tools/Wrapped/ActivityHistory.svelte b/src/lib/Tools/Wrapped/ActivityHistory.svelte
index 3da401d4..e652a487 100644
--- a/src/lib/Tools/Wrapped/ActivityHistory.svelte
+++ b/src/lib/Tools/Wrapped/ActivityHistory.svelte
@@ -3,10 +3,19 @@
import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
import ActivityHistoryGrid from '../ActivityHistory/Grid.svelte';
- export let user: AniListAuthorisation;
- export let activities: ActivityHistoryEntry[];
- export let year: number;
- export let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL';
+ interface Props {
+ user: AniListAuthorisation;
+ activities: ActivityHistoryEntry[];
+ year: number;
+ activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL';
+ }
+
+ let {
+ user,
+ activities,
+ year,
+ activityHistoryPosition
+ }: Props = $props();
</script>
<div
diff --git a/src/lib/Tools/Wrapped/Media.svelte b/src/lib/Tools/Wrapped/Media.svelte
index ea8a989b..7f8d4f66 100644
--- a/src/lib/Tools/Wrapped/Media.svelte
+++ b/src/lib/Tools/Wrapped/Media.svelte
@@ -4,14 +4,27 @@
import MediaTitleDisplay from '$lib/List/MediaTitleDisplay.svelte';
import proxy from '$lib/Utility/proxy';
- export let animeList: Media[] | undefined;
- export let mangaList: Media[] | undefined;
- export let wrapped: Wrapped;
- export let updateWidth: () => void;
- export let highestRatedMediaPercentage: boolean;
- export let highestRatedCount: number;
- export let animeMostTitle: string;
- export let mangaMostTitle: string;
+ interface Props {
+ animeList: Media[] | undefined;
+ mangaList: Media[] | undefined;
+ wrapped: Wrapped;
+ updateWidth: () => void;
+ highestRatedMediaPercentage: boolean;
+ highestRatedCount: number;
+ animeMostTitle: string;
+ mangaMostTitle: string;
+ }
+
+ let {
+ animeList,
+ mangaList,
+ wrapped,
+ updateWidth,
+ highestRatedMediaPercentage,
+ highestRatedCount,
+ animeMostTitle,
+ mangaMostTitle
+ }: Props = $props();
</script>
{#if animeList !== undefined || mangaList !== undefined}
@@ -28,7 +41,7 @@
)}
alt="Highest Rated Anime Cover"
class="cover-image"
- on:load={updateWidth}
+ onload={updateWidth}
/>
</a>
<div>
@@ -67,7 +80,7 @@
)}
alt="Highest Rated Manga Cover"
class="cover-image"
- on:load={updateWidth}
+ onload={updateWidth}
/>
</a>
<div>
diff --git a/src/lib/Tools/Wrapped/MediaExtras.svelte b/src/lib/Tools/Wrapped/MediaExtras.svelte
index 9e755ea5..3e083c0b 100644
--- a/src/lib/Tools/Wrapped/MediaExtras.svelte
+++ b/src/lib/Tools/Wrapped/MediaExtras.svelte
@@ -2,10 +2,19 @@
import type { TopMedia } from '$lib/Data/AniList/wrapped';
import proxy from '$lib/Utility/proxy';
- export let topMedia: TopMedia;
- export let updateWidth: () => void;
- export let highestRatedGenreTagPercentage: boolean;
- export let genreTagTitle: string;
+ interface Props {
+ topMedia: TopMedia;
+ updateWidth: () => void;
+ highestRatedGenreTagPercentage: boolean;
+ genreTagTitle: string;
+ }
+
+ let {
+ topMedia,
+ updateWidth,
+ highestRatedGenreTagPercentage,
+ genreTagTitle
+ }: Props = $props();
</script>
<div class="categories-grid" style="padding-top: 0;">
@@ -22,7 +31,7 @@
src={proxy(topMedia.topGenreMedia.coverImage.extraLarge)}
alt="Highest Rated Genre Cover"
class="cover-image"
- on:load={updateWidth}
+ onload={updateWidth}
/>
</a>
<div>
@@ -53,7 +62,7 @@
src={proxy(topMedia.topTagMedia.coverImage.extraLarge)}
alt="Highest Rated Tag Cover"
class="cover-image"
- on:load={updateWidth}
+ onload={updateWidth}
/>
</a>
<div>
diff --git a/src/lib/Tools/Wrapped/Tool.svelte b/src/lib/Tools/Wrapped/Tool.svelte
index 1484ab5c..af817051 100644
--- a/src/lib/Tools/Wrapped/Tool.svelte
+++ b/src/lib/Tools/Wrapped/Tool.svelte
@@ -1,4 +1,6 @@
<script lang="ts">
+ import { run } from 'svelte/legacy';
+
import userIdentity from '$stores/identity';
import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
import { onMount } from 'svelte';
@@ -30,153 +32,50 @@
import tooltip from '$lib/Tooltip/tooltip';
import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
- export let user: AniListAuthorisation;
-
- const currentYear = new Date(Date.now()).getFullYear();
- let selectedYear = new Date(Date.now()).getFullYear();
- let episodes = 0;
- let chapters = 0;
- let minutesWatched = 0;
- let animeList: Media[] | undefined = undefined;
- let mangaList: Media[] | undefined = undefined;
- let calculatedAnimeList: Media[] | undefined = undefined;
- let calculatedMangaList: Media[] | undefined = undefined;
- let originalAnimeList: Media[] | undefined = undefined;
- let originalMangaList: Media[] | undefined = undefined;
- let transparency = false;
- let lightTheme = true;
- let watermark = false;
- let includeMusic = false;
- let includeSpecials = true;
- let includeRepeats = false;
- let width = 1920;
- let lightMode = false;
- let highestRatedCount = 5;
- let genreTagCount = 5;
- let mounted = false;
- let generated = false;
- let disableActivityHistory = true;
- let excludedKeywordsInput = '';
- let excludedKeywords: string[] = [];
- let useFullActivityHistory = false;
- let topGenresTags = true;
- let topMedia: TopMedia;
- let highestRatedMediaPercentage = true;
- let highestRatedGenreTagPercentage = true;
- let genreTagsSort = SortOptions.SCORE;
- let mediaSort = SortOptions.SCORE;
- let includeMovies = true;
- let includeOVAs = true;
- let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL' = 'ORIGINAL';
- let includeOngoingMediaFromPreviousYears = false;
-
- $: {
- if (browser && mounted) {
- $page.url.searchParams.set('transparency', transparency.toString());
- $page.url.searchParams.set('lightTheme', lightTheme.toString());
- $page.url.searchParams.set('watermark', watermark.toString());
- $page.url.searchParams.set('includeMusic', includeMusic.toString());
- $page.url.searchParams.set('includeSpecials', includeSpecials.toString());
- $page.url.searchParams.set('includeRepeats', includeRepeats.toString());
- $page.url.searchParams.set('lightMode', lightMode.toString());
- $page.url.searchParams.set('highestRatedCount', highestRatedCount.toString());
- $page.url.searchParams.set('genreTagCount', genreTagCount.toString());
- $page.url.searchParams.set('disableActivityHistory', disableActivityHistory.toString());
- $page.url.searchParams.set(
- 'highestRatedMediaPercentage',
- highestRatedMediaPercentage.toString()
- );
- $page.url.searchParams.set(
- 'highestRatedGenreTagPercentage',
- highestRatedGenreTagPercentage.toString()
- );
- $page.url.searchParams.set('genreTagsSort', genreTagsSort.toString());
- $page.url.searchParams.set('mediaSort', mediaSort.toString());
- $page.url.searchParams.set('includeMovies', includeMovies.toString());
- $page.url.searchParams.set('includeOVAs', includeOVAs.toString());
-
- history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
- }
- }
- $: {
- includeMusic = includeMusic;
- includeSpecials = includeSpecials;
- includeRepeats = includeRepeats;
- disableActivityHistory = disableActivityHistory;
- highestRatedMediaPercentage = highestRatedMediaPercentage;
- highestRatedGenreTagPercentage = highestRatedGenreTagPercentage;
- topGenresTags = topGenresTags;
- genreTagsSort = genreTagsSort;
- mediaSort = mediaSort;
- includeMovies = includeMovies;
- includeOVAs = includeOVAs;
- selectedYear = selectedYear;
- includeOngoingMediaFromPreviousYears = includeOngoingMediaFromPreviousYears;
-
- update().then(updateWidth).catch(updateWidth);
- }
- $: {
- animeList = animeList;
- mangaList = mangaList;
- highestRatedCount = highestRatedCount;
-
- new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
+ interface Props {
+ user: AniListAuthorisation;
}
- $: {
- genreTagCount = genreTagCount;
-
- if (animeList && mangaList)
- topMedia = tops(
- [...(animeList || []), ...(mangaList || [])],
- genreTagCount,
- genreTagsSort,
- excludedKeywords
- );
- new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
- }
- $: {
- excludedKeywords = excludedKeywords;
+ let { user }: Props = $props();
- if (excludedKeywords.length > 0 && animeList !== undefined && mangaList !== undefined) {
- animeList = originalAnimeList;
- mangaList = originalMangaList;
- animeList = excludeKeywords(animeList as Media[]);
- mangaList = excludeKeywords(mangaList as Media[]);
- }
+ const currentYear = new Date(Date.now()).getFullYear();
+ let selectedYear = $state(new Date(Date.now()).getFullYear());
+ let episodes = $state(0);
+ let chapters = $state(0);
+ let minutesWatched = $state(0);
+ let animeList: Media[] | undefined = $state(undefined);
+ let mangaList: Media[] | undefined = $state(undefined);
+ let calculatedAnimeList: Media[] | undefined = $state(undefined);
+ let calculatedMangaList: Media[] | undefined = $state(undefined);
+ let originalAnimeList: Media[] | undefined = $state(undefined);
+ let originalMangaList: Media[] | undefined = $state(undefined);
+ let transparency = $state(false);
+ let lightTheme = $state(true);
+ let watermark = $state(false);
+ let includeMusic = $state(false);
+ let includeSpecials = $state(true);
+ let includeRepeats = $state(false);
+ let width = $state(1920);
+ let lightMode = $state(false);
+ let highestRatedCount = $state(5);
+ let genreTagCount = $state(5);
+ let mounted = $state(false);
+ let generated = $state(false);
+ let disableActivityHistory = $state(true);
+ let excludedKeywordsInput = $state('');
+ let excludedKeywords: string[] = $state([]);
+ let useFullActivityHistory = $state(false);
+ let topGenresTags = $state(true);
+ let topMedia: TopMedia = $state();
+ let highestRatedMediaPercentage = $state(true);
+ let highestRatedGenreTagPercentage = $state(true);
+ let genreTagsSort = $state(SortOptions.SCORE);
+ let mediaSort = $state(SortOptions.SCORE);
+ let includeMovies = $state(true);
+ let includeOVAs = $state(true);
+ let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL' = $state('ORIGINAL');
+ let includeOngoingMediaFromPreviousYears = $state(false);
- updateWidth();
- }
- $: genreTagTitle = (() => {
- switch (genreTagsSort) {
- case SortOptions.SCORE:
- return 'Highest Rated';
- case SortOptions.MINUTES_WATCHED:
- return 'Most Watched';
- case SortOptions.COUNT:
- return 'Most Common';
- }
- })();
- $: animeMostTitle = (() => {
- switch (mediaSort) {
- case SortOptions.SCORE:
- return 'Highest Rated';
- case SortOptions.MINUTES_WATCHED:
- return 'Most Watched';
- case SortOptions.COUNT:
- return 'Most Common';
- }
- })();
- $: mangaMostTitle = (() => {
- switch (mediaSort) {
- case SortOptions.SCORE:
- return 'Highest Rated';
- case SortOptions.MINUTES_WATCHED:
- return 'Most Read';
- case SortOptions.COUNT:
- return 'Most Common';
- }
- })();
const updateWidth = () => {
if (!browser) return;
@@ -562,6 +461,113 @@
// return mediaCover(top[Math.floor(Math.random() * top.length)].mediaIds[0]);
// };
+ run(() => {
+ includeMusic = includeMusic;
+ includeSpecials = includeSpecials;
+ includeRepeats = includeRepeats;
+ disableActivityHistory = disableActivityHistory;
+ highestRatedMediaPercentage = highestRatedMediaPercentage;
+ highestRatedGenreTagPercentage = highestRatedGenreTagPercentage;
+ topGenresTags = topGenresTags;
+ genreTagsSort = genreTagsSort;
+ mediaSort = mediaSort;
+ includeMovies = includeMovies;
+ includeOVAs = includeOVAs;
+ selectedYear = selectedYear;
+ includeOngoingMediaFromPreviousYears = includeOngoingMediaFromPreviousYears;
+
+ update().then(updateWidth).catch(updateWidth);
+ });
+ run(() => {
+ animeList = animeList;
+ mangaList = mangaList;
+ highestRatedCount = highestRatedCount;
+
+ new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
+ });
+ run(() => {
+ excludedKeywords = excludedKeywords;
+
+ if (excludedKeywords.length > 0 && animeList !== undefined && mangaList !== undefined) {
+ animeList = originalAnimeList;
+ mangaList = originalMangaList;
+ animeList = excludeKeywords(animeList as Media[]);
+ mangaList = excludeKeywords(mangaList as Media[]);
+ }
+
+ updateWidth();
+ });
+ run(() => {
+ genreTagCount = genreTagCount;
+
+ if (animeList && mangaList)
+ topMedia = tops(
+ [...(animeList || []), ...(mangaList || [])],
+ genreTagCount,
+ genreTagsSort,
+ excludedKeywords
+ );
+
+ new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
+ });
+ run(() => {
+ if (browser && mounted) {
+ $page.url.searchParams.set('transparency', transparency.toString());
+ $page.url.searchParams.set('lightTheme', lightTheme.toString());
+ $page.url.searchParams.set('watermark', watermark.toString());
+ $page.url.searchParams.set('includeMusic', includeMusic.toString());
+ $page.url.searchParams.set('includeSpecials', includeSpecials.toString());
+ $page.url.searchParams.set('includeRepeats', includeRepeats.toString());
+ $page.url.searchParams.set('lightMode', lightMode.toString());
+ $page.url.searchParams.set('highestRatedCount', highestRatedCount.toString());
+ $page.url.searchParams.set('genreTagCount', genreTagCount.toString());
+ $page.url.searchParams.set('disableActivityHistory', disableActivityHistory.toString());
+ $page.url.searchParams.set(
+ 'highestRatedMediaPercentage',
+ highestRatedMediaPercentage.toString()
+ );
+ $page.url.searchParams.set(
+ 'highestRatedGenreTagPercentage',
+ highestRatedGenreTagPercentage.toString()
+ );
+ $page.url.searchParams.set('genreTagsSort', genreTagsSort.toString());
+ $page.url.searchParams.set('mediaSort', mediaSort.toString());
+ $page.url.searchParams.set('includeMovies', includeMovies.toString());
+ $page.url.searchParams.set('includeOVAs', includeOVAs.toString());
+
+ history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
+ }
+ });
+ let genreTagTitle = $derived((() => {
+ switch (genreTagsSort) {
+ case SortOptions.SCORE:
+ return 'Highest Rated';
+ case SortOptions.MINUTES_WATCHED:
+ return 'Most Watched';
+ case SortOptions.COUNT:
+ return 'Most Common';
+ }
+ })());
+ let animeMostTitle = $derived((() => {
+ switch (mediaSort) {
+ case SortOptions.SCORE:
+ return 'Highest Rated';
+ case SortOptions.MINUTES_WATCHED:
+ return 'Most Watched';
+ case SortOptions.COUNT:
+ return 'Most Common';
+ }
+ })());
+ let mangaMostTitle = $derived((() => {
+ switch (mediaSort) {
+ case SortOptions.SCORE:
+ return 'Highest Rated';
+ case SortOptions.MINUTES_WATCHED:
+ return 'Most Read';
+ case SortOptions.COUNT:
+ return 'Most Common';
+ }
+ })());
</script>
{#if $userIdentity.id === -2 || user === undefined}
@@ -630,10 +636,10 @@
</div>
<div class="list">
<div class:card={generated}>
- <div id="wrapped-final" />
+ <div id="wrapped-final"></div>
{#if generated}
- <p />
+ <p></p>
<blockquote style="margin: 0 0 0 1.5rem;">
Click on the image to download, or right click and select "Save Image As...".
@@ -642,11 +648,11 @@
</div>
{#if generated}
- <p />
+ <p></p>
{/if}
<div id="options" class="card">
- <button on:click={screenshot} data-umami-event="Generate Wrapped">
+ <button onclick={screenshot} data-umami-event="Generate Wrapped">
Generate image
</button>
@@ -690,9 +696,9 @@
{/each}
</select>
Highest genre and tag count<br />
- <button on:click={updateWidth}>Find best fit</button>
- <button on:click={() => (width -= 25)}>-25px</button>
- <button on:click={() => (width += 25)}>+25px</button>
+ <button onclick={updateWidth}>Find best fit</button>
+ <button onclick={() => (width -= 25)}>-25px</button>
+ <button onclick={() => (width += 25)}>+25px</button>
Width adjustment<br />
</details>
@@ -700,7 +706,7 @@
<summary>Calculation</summary>
<input type="checkbox" bind:checked={useFullActivityHistory} />
- Enable full-year activity<button class="smaller-button" on:click={pruneFullYear}
+ Enable full-year activity<button class="smaller-button" onclick={pruneFullYear}
>Refresh data</button
>
<br />
@@ -732,12 +738,12 @@
<input
type="text"
bind:value={excludedKeywordsInput}
- on:keypress={(e) => {
+ onkeypress={(e) => {
e.key === 'Enter' && submitExcludedKeywords();
}}
/>
Excluded keywords
- <button on:click={submitExcludedKeywords} title="Or click your Enter key" use:tooltip
+ <button onclick={submitExcludedKeywords} title="Or click your Enter key" use:tooltip
>Submit</button
>
<br />
diff --git a/src/lib/Tools/Wrapped/Top/Activity.svelte b/src/lib/Tools/Wrapped/Top/Activity.svelte
index a91bedfb..27dea6a2 100644
--- a/src/lib/Tools/Wrapped/Top/Activity.svelte
+++ b/src/lib/Tools/Wrapped/Top/Activity.svelte
@@ -4,18 +4,28 @@
import type { Wrapped } from '$lib/Data/AniList/wrapped';
import proxy from '$lib/Utility/proxy';
- export let wrapped: Wrapped;
- export let year: number;
- export let activities: ActivityHistoryEntry[];
- export let useFullActivityHistory: boolean;
- export let updateWidth: () => void;
+ interface Props {
+ wrapped: Wrapped;
+ year: number;
+ activities: ActivityHistoryEntry[];
+ useFullActivityHistory: boolean;
+ updateWidth: () => void;
+ }
+
+ let {
+ wrapped,
+ year,
+ activities,
+ useFullActivityHistory,
+ updateWidth
+ }: Props = $props();
const currentYear = new Date(Date.now()).getFullYear();
</script>
<div class="grid-item image-grid avatar-grid category top-category">
<a href={`https://anilist.co/user/${$identity.name}`} target="_blank">
- <img src={proxy(wrapped.avatar.large)} alt="User Avatar" on:load={updateWidth} />
+ <img src={proxy(wrapped.avatar.large)} alt="User Avatar" onload={updateWidth} />
</a>
<div>
<div>
diff --git a/src/lib/Tools/Wrapped/Top/Anime.svelte b/src/lib/Tools/Wrapped/Top/Anime.svelte
index 08df7fd3..275adadf 100644
--- a/src/lib/Tools/Wrapped/Top/Anime.svelte
+++ b/src/lib/Tools/Wrapped/Top/Anime.svelte
@@ -1,9 +1,13 @@
<script lang="ts">
import type { Media } from '$lib/Data/AniList/media';
- export let minutesWatched: number;
- export let animeList: Media[] | undefined;
- export let episodes: number;
+ interface Props {
+ minutesWatched: number;
+ animeList: Media[] | undefined;
+ episodes: number;
+ }
+
+ let { minutesWatched, animeList, episodes }: Props = $props();
</script>
<div class="category-grid pure-category category top-category">
diff --git a/src/lib/Tools/Wrapped/Top/Manga.svelte b/src/lib/Tools/Wrapped/Top/Manga.svelte
index a36f7724..a49d1067 100644
--- a/src/lib/Tools/Wrapped/Top/Manga.svelte
+++ b/src/lib/Tools/Wrapped/Top/Manga.svelte
@@ -2,8 +2,12 @@
import type { Media } from '$lib/Data/AniList/media';
import { estimatedDayReading } from '$lib/Media/Manga/time';
- export let mangaList: Media[] | undefined;
- export let chapters: number;
+ interface Props {
+ mangaList: Media[] | undefined;
+ chapters: number;
+ }
+
+ let { mangaList, chapters }: Props = $props();
</script>
<div class="category-grid pure-category category top-category">