feat: improve WatchList UI with refresh button

Enhanced the WatchList component with better layout and manual refresh functionality.

Changes:
- Added Refresh WatchList button with loading state handling
- Restructured header layout using flexbox with justify-between
- Title on left, refresh button on right, vertically aligned with items-center
- Improved button styling with consistent py-2 px-4 padding
- Added CheckIfAniListLoggedInAndLoadWatchList import for refresh functionality
- Maintained mb-4 spacing for consistent vertical rhythm

This gives users manual control over watchlist updates and provides better visual balance to the header section.

UI improvements:
- Horizontal flex container for proper left/right alignment
- Responsive button sizing
- Clear visual separation between title and action
This commit is contained in:
2026-03-21 13:25:45 -04:00
parent 8a8baf7f8f
commit 6ed5fe8b71

View File

@@ -1,68 +1,99 @@
<script lang="ts"> <script lang="ts">
import { import {
aniListLoggedIn, aniListLoggedIn,
aniListWatchlist, aniListWatchlist,
GetAnimeSingleItem, GetAnimeSingleItem,
loading, loading,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte"; } from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
import {push} from "svelte-spa-router"; import { push } from "svelte-spa-router";
import type {AniListCurrentUserWatchList} from "../anilist/types/AniListCurrentUserWatchListType" import type { AniListCurrentUserWatchList } from "../anilist/types/AniListCurrentUserWatchListType";
import {Rating} from "flowbite-svelte"; import { Rating } from "flowbite-svelte";
import loader from '../helperFunctions/loader' import loader from "../helperFunctions/loader";
import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
let isAniListLoggedIn: boolean;
let aniListWatchListLoaded: AniListCurrentUserWatchList;
let isAniListLoggedIn: boolean aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value));
let aniListWatchListLoaded: AniListCurrentUserWatchList aniListWatchlist.subscribe((value) => (aniListWatchListLoaded = value));
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value)
</script> </script>
<div> <div>
{#if isAniListLoggedIn} {#if isAniListLoggedIn}
<div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center"> <div
<h1 class="text-left text-xl font-bold mb-4">Your AniList WatchList</h1> class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center"
>
<div class="flex justify-between items-center mb-4">
<h1 class="text-left text-xl font-bold">Your AniList WatchList</h1>
<button
type="button"
class="py-2 px-4 bg-gray-700 rounded-lg"
on:click={async () => {
loading.set(true);
await CheckIfAniListLoggedInAndLoadWatchList();
loading.set(false);
}}
>
Refresh WatchList
</button>
</div>
<div class="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8"> <div
{#each aniListWatchListLoaded.data.Page.mediaList as media} class="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8"
<div use:loader={loading} class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7"> >
<div class="flex flex-col items-center group"> {#each aniListWatchListLoaded.data.Page.mediaList as media}
<button on:click={() => { <div
push(`#/anime/${media.media.id}`) use:loader={loading}
// loading.set(true) class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7"
// GetAniListSingleItem(media.media.id, true).then(() => { >
// loading.set(false) <div class="flex flex-col items-center group">
// <button
// }) on:click={() => {
}} push(`#/anime/${media.media.id}`);
> // loading.set(true)
<img class="rounded-lg" src={media.media.coverImage.large} alt={ // GetAniListSingleItem(media.media.id, true).then(() => {
media.media.title.english === "" ? // loading.set(false)
media.media.title.romaji : //
media.media.title.english // })
}/> }}
</button> >
<Rating id="anime-rating" total={5} size={35} rating={media.score/2.0}/> <img
<button class="mt-4 text-md font-semibold text-white-700" class="rounded-lg"
on:click={() => GetAnimeSingleItem(media.media.id, true)}> src={media.media.coverImage.large}
{ alt={media.media.title.english === ""
media.media.title.english === "" ? ? media.media.title.romaji
media.media.title.romaji : : media.media.title.english}
media.media.title.english />
} </button>
</button> <Rating
<p class="mt-1 text-lg font-medium text-white-900">{media.progress} id="anime-rating"
/ {media.media.nextAiringEpisode.episode !== 0 ? total={5}
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p> size={35}
{#if media.media.episodes > 0} rating={media.score / 2.0}
<p class="mt-1 text-lg font-medium text-white-900">Total />
Episodes: {media.media.episodes}</p> <button
{/if} class="mt-4 text-md font-semibold text-white-700"
</div> on:click={() => GetAnimeSingleItem(media.media.id, true)}
</div> >
{/each} {media.media.title.english === ""
? media.media.title.romaji
: media.media.title.english}
</button>
<p class="mt-1 text-lg font-medium text-white-900">
{media.progress}
/ {media.media.nextAiringEpisode.episode !== 0
? media.media.nextAiringEpisode.episode - 1
: media.media.episodes}
</p>
{#if media.media.episodes > 0}
<p class="mt-1 text-lg font-medium text-white-900">
Total Episodes: {media.media.episodes}
</p>
{/if}
</div> </div>
</div> </div>
{/if} {/each}
</div>
</div>
{/if}
</div> </div>