aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tools
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-12-30 17:18:22 -0800
committerFuwn <[email protected]>2023-12-30 17:18:22 -0800
commit3de6d077b690bac153ba91d6c1483e58b1998e4b (patch)
tree2e5d266ef5e3ed42a5dc9e8e8bddacfd1c5c558c /src/lib/Tools
parentfix(anilist): final push page (diff)
downloaddue.moe-3de6d077b690bac153ba91d6c1483e58b1998e4b.tar.xz
due.moe-3de6d077b690bac153ba91d6c1483e58b1998e4b.zip
feat(wrapped): move preview next to options
Diffstat (limited to 'src/lib/Tools')
-rw-r--r--src/lib/Tools/Wrapped.svelte622
1 files changed, 318 insertions, 304 deletions
diff --git a/src/lib/Tools/Wrapped.svelte b/src/lib/Tools/Wrapped.svelte
index 35f3e0e3..a9af64c4 100644
--- a/src/lib/Tools/Wrapped.svelte
+++ b/src/lib/Tools/Wrapped.svelte
@@ -487,341 +487,344 @@
{#await wrapped(user, currentUserIdentity)}
{@html nbsp('Loading user data ...')}
{:then wrapped}
- <div
- id="wrapped"
- class:light-theme={lightMode}
- style={`width: ${width}px;`}
- class:transparent={transparency}
- >
- {#if !disableActivityHistory && activityHistoryPosition === 'TOP'}
- <div class="categories-grid" style="padding-bottom: 0;">
- <div class="category-grid bottom-category pure-category category">
- <div id="activity-history">
- <ActivityHistoryGrid {user} activityData={activities} />
+ <div id="list-container">
+ <div
+ id="wrapped"
+ class:light-theme={lightMode}
+ style={`width: ${width}px; flex-shrink: 0;`}
+ class:transparent={transparency}
+ >
+ {#if !disableActivityHistory && activityHistoryPosition === 'TOP'}
+ <div class="categories-grid" style="padding-bottom: 0;">
+ <div class="category-grid bottom-category pure-category category">
+ <div id="activity-history">
+ <ActivityHistoryGrid {user} activityData={activities} />
+ </div>
</div>
</div>
- </div>
- {/if}
- <div class="categories-grid" style="padding-bottom: 0;">
- <div class="grid-item image-grid avatar-grid category top-category">
- <a href={`https://anilist.co/user/${currentUserIdentity.name}`} target="_blank">
- <img src={proxy(wrapped.avatar.large)} alt="User Avatar" on:load={updateWidth} />
- </a>
- <div>
+ {/if}
+ <div class="categories-grid" style="padding-bottom: 0;">
+ <div class="grid-item image-grid avatar-grid category top-category">
+ <a href={`https://anilist.co/user/${currentUserIdentity.name}`} target="_blank">
+ <img src={proxy(wrapped.avatar.large)} alt="User Avatar" on:load={updateWidth} />
+ </a>
<div>
- <a href={`https://anilist.co/user/${currentUserIdentity.name}`} target="_blank">
- <b>
- {currentUserIdentity.name}
- </b>
- </a>
+ <div>
+ <a href={`https://anilist.co/user/${currentUserIdentity.name}`} target="_blank">
+ <b>
+ {currentUserIdentity.name}
+ </b>
+ </a>
+ </div>
+ <div>
+ Status Posts: {wrapped.activities.statusCount}
+ </div>
+ <div>
+ Messages: {wrapped.activities.messageCount}
+ </div>
+ <div>
+ Days Active: {activities.length}/{useFullActivityHistory ? 365 : 189}
+ </div>
</div>
- <div>
- Status Posts: {wrapped.activities.statusCount}
+ </div>
+ <div class="category-grid pure-category category top-category">
+ <div class="grid-item">
+ <b>Anime</b>
</div>
- <div>
- Messages: {wrapped.activities.messageCount}
+ <div class="grid-item">
+ Time Watched: {((minutesWatched || 0) / 60 / 24).toFixed(2)} days
</div>
- <div>
- Days Active: {activities.length}/{useFullActivityHistory ? 365 : 189}
+ <div class="grid-item">
+ Completed: {animeList?.length}
</div>
+ <div class="grid-item">Episodes: {episodes}</div>
</div>
- </div>
- <div class="category-grid pure-category category top-category">
- <div class="grid-item">
- <b>Anime</b>
- </div>
- <div class="grid-item">
- Time Watched: {((minutesWatched || 0) / 60 / 24).toFixed(2)} days
- </div>
- <div class="grid-item">
- Completed: {animeList?.length}
- </div>
- <div class="grid-item">Episodes: {episodes}</div>
- </div>
- <div class="category-grid pure-category category top-category">
- <div class="grid-item">
- <b>Manga</b>
- </div>
- <div class="grid-item">
- Time Read: {estimatedDayReading(chapters).toFixed(2)} days
- </div>
- <div class="grid-item">
- Completed: {mangaList?.length}
- </div>
- <div class="grid-item">
- Chapters: {chapters}
+ <div class="category-grid pure-category category top-category">
+ <div class="grid-item">
+ <b>Manga</b>
+ </div>
+ <div class="grid-item">
+ Time Read: {estimatedDayReading(chapters).toFixed(2)} days
+ </div>
+ <div class="grid-item">
+ Completed: {mangaList?.length}
+ </div>
+ <div class="grid-item">
+ Chapters: {chapters}
+ </div>
</div>
</div>
- </div>
- {#if !disableActivityHistory && activityHistoryPosition === 'BELOW_TOP'}
- <div class="categories-grid" style="padding-bottom: 0;">
- <div class="category-grid bottom-category pure-category category">
- <div id="activity-history">
- <ActivityHistoryGrid {user} activityData={activities} />
+ {#if !disableActivityHistory && activityHistoryPosition === 'BELOW_TOP'}
+ <div class="categories-grid" style="padding-bottom: 0;">
+ <div class="category-grid bottom-category pure-category category">
+ <div id="activity-history">
+ <ActivityHistoryGrid {user} activityData={activities} />
+ </div>
</div>
</div>
- </div>
- {/if}
- {#if animeList !== undefined || mangaList !== undefined}
- <div class="categories-grid">
- {#if animeList !== undefined && animeList.length !== 0}
- <div class="category-grid pure-category category middle-category">
- <div class="grid-item image-grid">
- <a href={`https://anilist.co/anime/${animeList[0].id}`} target="_blank">
- <img
- src={proxy(animeList[0].coverImage.extraLarge)}
- alt="Highest Rated Anime Cover"
- class="cover-image"
- on:load={updateWidth}
- />
- </a>
- <div>
- <b>{animeMostTitle} Anime</b>
- <ol>
- {#each animeList?.slice(0, highestRatedCount) as anime}
- <li>
- <a href={`https://anilist.co/anime/${anime.id}`} target="_blank">
- <MediaTitleDisplay title={anime.title} />
- </a>
- {highestRatedMediaPercentage ? `: ${anime.mediaListEntry?.score}%` : ''}
- </li>
- {/each}
- </ol>
+ {/if}
+ {#if animeList !== undefined || mangaList !== undefined}
+ <div class="categories-grid">
+ {#if animeList !== undefined && animeList.length !== 0}
+ <div class="category-grid pure-category category middle-category">
+ <div class="grid-item image-grid">
+ <a href={`https://anilist.co/anime/${animeList[0].id}`} target="_blank">
+ <img
+ src={proxy(animeList[0].coverImage.extraLarge)}
+ alt="Highest Rated Anime Cover"
+ class="cover-image"
+ on:load={updateWidth}
+ />
+ </a>
+ <div>
+ <b>{animeMostTitle} Anime</b>
+ <ol>
+ {#each animeList?.slice(0, highestRatedCount) as anime}
+ <li>
+ <a href={`https://anilist.co/anime/${anime.id}`} target="_blank">
+ <MediaTitleDisplay title={anime.title} />
+ </a>
+ {highestRatedMediaPercentage ? `: ${anime.mediaListEntry?.score}%` : ''}
+ </li>
+ {/each}
+ </ol>
+ </div>
</div>
</div>
- </div>
- {/if}
- {#if mangaList !== undefined && mangaList.length !== 0}
- <div class="category-grid pure-category category middle-category">
- <div class="grid-item image-grid">
- <a href={`https://anilist.co/manga/${mangaList[0].id}`} target="_blank">
- <img
- src={proxy(mangaList[0].coverImage.extraLarge)}
- alt="Highest Rated Manga Cover"
- class="cover-image"
- on:load={updateWidth}
- />
- </a>
- <div>
- <b>{mangaMostTitle} Manga</b>
- <ol>
- {#each mangaList?.slice(0, highestRatedCount) as manga}
- <li>
- <a href={`https://anilist.co/manga/${manga.id}`} target="_blank">
- <MediaTitleDisplay title={manga.title} />
- </a>
- {highestRatedMediaPercentage ? `: ${manga.mediaListEntry?.score}%` : ''}
- </li>
- {/each}
- </ol>
+ {/if}
+ {#if mangaList !== undefined && mangaList.length !== 0}
+ <div class="category-grid pure-category category middle-category">
+ <div class="grid-item image-grid">
+ <a href={`https://anilist.co/manga/${mangaList[0].id}`} target="_blank">
+ <img
+ src={proxy(mangaList[0].coverImage.extraLarge)}
+ alt="Highest Rated Manga Cover"
+ class="cover-image"
+ on:load={updateWidth}
+ />
+ </a>
+ <div>
+ <b>{mangaMostTitle} Manga</b>
+ <ol>
+ {#each mangaList?.slice(0, highestRatedCount) as manga}
+ <li>
+ <a href={`https://anilist.co/manga/${manga.id}`} target="_blank">
+ <MediaTitleDisplay title={manga.title} />
+ </a>
+ {highestRatedMediaPercentage ? `: ${manga.mediaListEntry?.score}%` : ''}
+ </li>
+ {/each}
+ </ol>
+ </div>
</div>
</div>
- </div>
- {/if}
- </div>
- {/if}
- {#if topMedia && topGenresTags && ((topMedia.topGenreMedia && topMedia.genres.length > 0) || (topMedia.topTagMedia && topMedia.tags.length > 0))}
- <div class="categories-grid" style="padding-top: 0;">
- {#if topMedia.topGenreMedia && topMedia.genres.length > 0}
- <div class="category-grid pure-category category">
- <div class="grid-item image-grid">
- <a
- href={`https://anilist.co/${topMedia.topGenreMedia.type.toLowerCase()}/${
- topMedia.topGenreMedia.id
- }`}
- target="_blank"
- >
- <img
- src={proxy(topMedia.topGenreMedia.coverImage.extraLarge)}
- alt="Highest Rated Genre Cover"
- class="cover-image"
- on:load={updateWidth}
- />
- </a>
- <div>
- <b>{genreTagTitle} Genres</b>
- <ol>
- {#each topMedia.genres as genre}
- <li>
- <a
- href={`https://anilist.co/search/anime?genres=${genre.genre}`}
- target="_blank"
- >
- {genre.genre}{highestRatedGenreTagPercentage
- ? `: ${genre.averageScore}%`
- : ''}
- </a>
- </li>
- {/each}
- </ol>
+ {/if}
+ </div>
+ {/if}
+ {#if topMedia && topGenresTags && ((topMedia.topGenreMedia && topMedia.genres.length > 0) || (topMedia.topTagMedia && topMedia.tags.length > 0))}
+ <div class="categories-grid" style="padding-top: 0;">
+ {#if topMedia.topGenreMedia && topMedia.genres.length > 0}
+ <div class="category-grid pure-category category">
+ <div class="grid-item image-grid">
+ <a
+ href={`https://anilist.co/${topMedia.topGenreMedia.type.toLowerCase()}/${
+ topMedia.topGenreMedia.id
+ }`}
+ target="_blank"
+ >
+ <img
+ src={proxy(topMedia.topGenreMedia.coverImage.extraLarge)}
+ alt="Highest Rated Genre Cover"
+ class="cover-image"
+ on:load={updateWidth}
+ />
+ </a>
+ <div>
+ <b>{genreTagTitle} Genres</b>
+ <ol>
+ {#each topMedia.genres as genre}
+ <li>
+ <a
+ href={`https://anilist.co/search/anime?genres=${genre.genre}`}
+ target="_blank"
+ >
+ {genre.genre}{highestRatedGenreTagPercentage
+ ? `: ${genre.averageScore}%`
+ : ''}
+ </a>
+ </li>
+ {/each}
+ </ol>
+ </div>
</div>
</div>
- </div>
- {/if}
- {#if topMedia.topTagMedia && topMedia.tags.length > 0}
- <div class="category-grid pure-category category">
- <div class="grid-item image-grid">
- <a
- href={`https://anilist.co/${topMedia.topTagMedia.type.toLowerCase()}/${
- topMedia.topTagMedia.id
- }`}
- target="_blank"
- >
- <img
- src={proxy(topMedia.topTagMedia.coverImage.extraLarge)}
- alt="Highest Rated Tag Cover"
- class="cover-image"
- on:load={updateWidth}
- />
- </a>
- <div>
- <b>{genreTagTitle} Tags</b>
- <ol>
- {#each topMedia.tags as tag}
- <li>
- <a
- href={`https://anilist.co/search/anime?genres=${tag.tag}`}
- target="_blank"
- >
- {tag.tag}{highestRatedGenreTagPercentage
- ? `: ${tag.averageScore}%`
- : ''}
- </a>
- </li>
- {/each}
- </ol>
+ {/if}
+ {#if topMedia.topTagMedia && topMedia.tags.length > 0}
+ <div class="category-grid pure-category category">
+ <div class="grid-item image-grid">
+ <a
+ href={`https://anilist.co/${topMedia.topTagMedia.type.toLowerCase()}/${
+ topMedia.topTagMedia.id
+ }`}
+ target="_blank"
+ >
+ <img
+ src={proxy(topMedia.topTagMedia.coverImage.extraLarge)}
+ alt="Highest Rated Tag Cover"
+ class="cover-image"
+ on:load={updateWidth}
+ />
+ </a>
+ <div>
+ <b>{genreTagTitle} Tags</b>
+ <ol>
+ {#each topMedia.tags as tag}
+ <li>
+ <a
+ href={`https://anilist.co/search/anime?genres=${tag.tag}`}
+ target="_blank"
+ >
+ {tag.tag}{highestRatedGenreTagPercentage
+ ? `: ${tag.averageScore}%`
+ : ''}
+ </a>
+ </li>
+ {/each}
+ </ol>
+ </div>
</div>
</div>
- </div>
- {/if}
- </div>
- {/if}
- {#if !disableActivityHistory && activityHistoryPosition === 'ORIGINAL'}
- <div class="categories-grid" style="padding-top: 0;">
- <div class="category-grid bottom-category pure-category category">
- <div id="activity-history">
- <ActivityHistoryGrid {user} activityData={activities} />
+ {/if}
+ </div>
+ {/if}
+ {#if !disableActivityHistory && activityHistoryPosition === 'ORIGINAL'}
+ <div class="categories-grid" style="padding-top: 0;">
+ <div class="category-grid bottom-category pure-category category">
+ <div id="activity-history">
+ <ActivityHistoryGrid {user} activityData={activities} />
+ </div>
</div>
</div>
- </div>
- {/if}
- {#if watermark}
- <div class="categories-grid" style="padding-top: 0;">
- <div class="category-grid pure-category" id="watermark">
- <a href="https://due.moe/wrapped" target="_blank">due.moe/wrapped</a>
+ {/if}
+ {#if watermark}
+ <div class="categories-grid" style="padding-top: 0;">
+ <div class="category-grid pure-category" id="watermark">
+ <a href="https://due.moe/wrapped" target="_blank">due.moe/wrapped</a>
+ </div>
</div>
- </div>
- {/if}
- </div>
-
- <p />
-
- <p>
- <a href={'#'} on:click={screenshot} data-umami-event="Generate Wrapped">Generate image</a>
- </p>
+ {/if}
+ </div>
+ <div class="list">
+ <p>
+ <a href={'#'} on:click={screenshot} data-umami-event="Generate Wrapped"
+ >Generate image</a
+ >
+ </p>
- <details open>
- <summary>Options</summary>
- <div id="options">
<details open>
- <summary>Display</summary>
-
- <input type="checkbox" bind:checked={watermark} /> Show watermark<br />
- <input type="checkbox" bind:checked={transparency} /> Enable background transparency<br
- />
- <input type="checkbox" bind:checked={lightMode} />
- Enable light mode<br />
- <input type="checkbox" bind:checked={topGenresTags} />
- Show top genres and tags<br />
- <input type="checkbox" bind:checked={disableActivityHistory} /> Hide activity history<br
- />
- <input type="checkbox" bind:checked={highestRatedMediaPercentage} /> Show highest rated
- media percentages<br />
- <input type="checkbox" bind:checked={highestRatedGenreTagPercentage} /> Show highest
- rated genre and tag percentages<br />
- <select bind:value={activityHistoryPosition}>
- <option value="ORIGINAL">Original</option>
- <option value="TOP">Top</option>
- <option value="BELOW_TOP">Below Top</option>
- </select>
- Activity history position<br />
- <select bind:value={highestRatedCount}>
- {#each [3, 4, 5, 6, 7, 8, 9, 10] as count}
- <option value={count}>{count}</option>
- {/each}
- </select>
- Highest rated media count<br />
- <select bind:value={genreTagCount}>
- {#each [3, 4, 5, 6, 7, 8, 9, 10] as count}
- <option value={count}>{count}</option>
- {/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>
- Width adjustment<br />
+ <summary>Options</summary>
+ <div id="options">
+ <details open>
+ <summary>Display</summary>
+
+ <input type="checkbox" bind:checked={watermark} /> Show watermark<br />
+ <input type="checkbox" bind:checked={transparency} /> Enable background transparency<br
+ />
+ <input type="checkbox" bind:checked={lightMode} />
+ Enable light mode<br />
+ <input type="checkbox" bind:checked={topGenresTags} />
+ Show top genres and tags<br />
+ <input type="checkbox" bind:checked={disableActivityHistory} /> Hide activity
+ history<br />
+ <input type="checkbox" bind:checked={highestRatedMediaPercentage} /> Show highest
+ rated media percentages<br />
+ <input type="checkbox" bind:checked={highestRatedGenreTagPercentage} /> Show highest
+ rated genre and tag percentages<br />
+ <select bind:value={activityHistoryPosition}>
+ <option value="ORIGINAL">Original</option>
+ <option value="TOP">Top</option>
+ <option value="BELOW_TOP">Below Top</option>
+ </select>
+ Activity history position<br />
+ <select bind:value={highestRatedCount}>
+ {#each [3, 4, 5, 6, 7, 8, 9, 10] as count}
+ <option value={count}>{count}</option>
+ {/each}
+ </select>
+ Highest rated media count<br />
+ <select bind:value={genreTagCount}>
+ {#each [3, 4, 5, 6, 7, 8, 9, 10] as count}
+ <option value={count}>{count}</option>
+ {/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>
+ Width adjustment<br />
+ </details>
+
+ <p />
+
+ <details open>
+ <summary>Calculation</summary>
+
+ <input type="checkbox" bind:checked={useFullActivityHistory} />
+ Enable full-year activity<br />
+ <SettingHint>
+ If you have many activities, you may rate-limited and you may need multiple
+ attempts to fully populate your local activity history database.<br />If you get
+ rate-limited, wait one minute, then try again.
+ <a href={'#'} on:click={pruneFullYear}>Refresh data</a>
+ </SettingHint><br />
+ <p />
+ <select bind:value={mediaSort}>
+ <option value={SortOptions.SCORE}>Score</option>
+ <option value={SortOptions.MINUTES_WATCHED}>Minutes Watched/Read</option>
+ </select>
+ Anime and manga sort<br />
+ <select bind:value={genreTagsSort}>
+ <option value={SortOptions.SCORE}>Score</option>
+ <option value={SortOptions.MINUTES_WATCHED}>Minutes Watched/Read</option>
+ <option value={SortOptions.COUNT}>Count</option>
+ </select>
+ Genre and tag sort<br />
+ <input type="checkbox" bind:checked={includeMusic} /> Include music<br />
+ <input type="checkbox" bind:checked={includeRepeats} /> Include rewatches & rereads<br
+ />
+ <input type="checkbox" bind:checked={includeSpecials} /> Include specials<br />
+ <input type="checkbox" bind:checked={includeOVAs} /> Include OVAs<br />
+ <input type="checkbox" bind:checked={includeMovies} /> Include movies<br />
+ <input
+ type="text"
+ bind:value={excludedKeywordsInput}
+ on:keypress={(e) => {
+ e.key === 'Enter' && submitExcludedKeywords();
+ }}
+ />
+ Excluded keywords
+ <a href={`#`} on:click={submitExcludedKeywords} title="Or click your Enter key"
+ >Submit</a
+ >
+ <br />
+ <SettingHint>Comma separated list (e.g., "My Hero, Kaguya")</SettingHint>
+ </details>
+ </div>
</details>
<p />
- <details open>
- <summary>Calculation</summary>
-
- <input type="checkbox" bind:checked={useFullActivityHistory} />
- Enable full-year activity<br />
- <SettingHint>
- If you have many activities, you may rate-limited and you may need multiple attempts
- to fully populate your local activity history database.<br />If you get rate-limited,
- wait one minute, then try again.
- <a href={'#'} on:click={pruneFullYear}>Refresh data</a>
- </SettingHint><br />
- <p />
- <select bind:value={mediaSort}>
- <option value={SortOptions.SCORE}>Score</option>
- <option value={SortOptions.MINUTES_WATCHED}>Minutes Watched/Read</option>
- </select>
- Anime and manga sort<br />
- <select bind:value={genreTagsSort}>
- <option value={SortOptions.SCORE}>Score</option>
- <option value={SortOptions.MINUTES_WATCHED}>Minutes Watched/Read</option>
- <option value={SortOptions.COUNT}>Count</option>
- </select>
- Genre and tag sort<br />
- <input type="checkbox" bind:checked={includeMusic} /> Include music<br />
- <input type="checkbox" bind:checked={includeRepeats} /> Include rewatches & rereads<br
- />
- <input type="checkbox" bind:checked={includeSpecials} /> Include specials<br />
- <input type="checkbox" bind:checked={includeOVAs} /> Include OVAs<br />
- <input type="checkbox" bind:checked={includeMovies} /> Include movies<br />
- <input
- type="text"
- bind:value={excludedKeywordsInput}
- on:keypress={(e) => {
- e.key === 'Enter' && submitExcludedKeywords();
- }}
- />
- Excluded keywords
- <a href={`#`} on:click={submitExcludedKeywords} title="Or click your Enter key"
- >Submit</a
- >
- <br />
- <SettingHint>Comma separated list (e.g., "My Hero, Kaguya")</SettingHint>
- </details>
- </div>
- </details>
-
- <p />
+ <div id="wrapped-final" />
- <div id="wrapped-final" />
-
- {#if generated}
- <p />
+ {#if generated}
+ <p />
- <blockquote>
- Click on the image to download, or right click and select "Save Image As...".
- </blockquote>
- {/if}
+ <blockquote>
+ Click on the image to download, or right click and select "Save Image As...".
+ </blockquote>
+ {/if}
+ </div>
+ </div>
{:catch}
<Error />
{/await}
@@ -920,4 +923,15 @@
height: auto;
width: 50%;
}
+
+ #list-container {
+ display: flex;
+ gap: 1rem;
+ flex-wrap: wrap;
+ }
+
+ .list {
+ flex-grow: 1;
+ flex-basis: 1%;
+ }
</style>