Chore: Revamped Shared Files for Svelte 5 Rewrite

This commit is contained in:
Youwes09
2026-03-19 23:43:43 -05:00
parent 94b92d000f
commit 96bac1ad2b
4 changed files with 239 additions and 208 deletions
+43 -30
View File
@@ -8,31 +8,31 @@
type BrowseType = "POPULAR" | "LATEST" | "SEARCH";
let mangas: Manga[] = [];
let loading = true;
let page = 1;
let hasNextPage = false;
let browseType: BrowseType = "POPULAR";
let search = "";
let searchInput = "";
let ctx: { x: number; y: number; manga: Manga } | null = null;
let mangas: Manga[] = $state([]);
let loading = $state(true);
let page = $state(1);
let hasNextPage = $state(false);
let browseType: BrowseType = $state("POPULAR");
let search = $state("");
let searchInput = $state("");
let ctx: { x: number; y: number; manga: Manga } | null = $state(null);
async function fetchMangas(type: BrowseType, p: number, q: string) {
if (!$activeSource) return;
if (!activeSource) return;
loading = true; mangas = [];
gql<{ fetchSourceManga: { mangas: Manga[]; hasNextPage: boolean } }>(
FETCH_SOURCE_MANGA, { source: $activeSource.id, type, page: p, query: q || null }
FETCH_SOURCE_MANGA, { source: activeSource.id, type, page: p, query: q || null }
).then((d) => { mangas = d.fetchSourceManga.mangas; hasNextPage = d.fetchSourceManga.hasNextPage; })
.catch(console.error)
.finally(() => loading = false);
.finally(() => { loading = false; });
}
$: if ($activeSource) fetchMangas(browseType, page, search);
$effect(() => { if (activeSource) fetchMangas(browseType, page, search); });
function submitSearch() {
search = searchInput.trim();
search = searchInput.trim();
browseType = "SEARCH";
page = 1;
page = 1;
}
function setMode(mode: BrowseType) {
@@ -42,36 +42,48 @@
function buildCtxItems(m: Manga): MenuEntry[] {
return [
{ label: m.inLibrary ? "In Library" : "Add to library", icon: BookmarkSimple, disabled: m.inLibrary,
{
label: m.inLibrary ? "In Library" : "Add to library",
icon: BookmarkSimple,
disabled: m.inLibrary,
onClick: () => gql(UPDATE_MANGA, { id: m.id, inLibrary: true })
.then(() => mangas = mangas.map((x) => x.id === m.id ? { ...x, inLibrary: true } : x))
.catch(console.error) },
...($settings.folders.length > 0 ? [
.then(() => { mangas = mangas.map((x) => x.id === m.id ? { ...x, inLibrary: true } : x); })
.catch(console.error),
},
...(settings.folders.length > 0 ? [
{ separator: true } as MenuEntry,
...$settings.folders.map((f): MenuEntry => ({
label: f.mangaIds.includes(m.id) ? `✓ ${f.name}` : f.name, icon: Folder,
...settings.folders.map((f): MenuEntry => ({
label: f.mangaIds.includes(m.id) ? `✓ ${f.name}` : f.name,
icon: Folder,
onClick: () => assignMangaToFolder(f.id, m.id),
})),
] : []),
{ separator: true },
{ label: "New folder & add", icon: FolderSimplePlus, onClick: () => { const name = prompt("Folder name:"); if (name?.trim()) { const id = addFolder(name.trim()); assignMangaToFolder(id, m.id); } } },
{
label: "New folder & add",
icon: FolderSimplePlus,
onClick: () => {
const name = prompt("Folder name:");
if (name?.trim()) { const id = addFolder(name.trim()); assignMangaToFolder(id, m.id); }
},
},
];
}
</script>
{#if $activeSource}
{#if activeSource}
<div class="root">
<div class="header">
<button class="back" on:click={() => activeSource.set(null)}>
<button class="back" onclick={() => activeSource = null}>
<ArrowLeft size={13} weight="light" /><span>Sources</span>
</button>
<span class="source-name">{$activeSource.displayName}</span>
<span class="source-name">{activeSource.displayName}</span>
</div>
<div class="toolbar">
<div class="tabs">
{#each (["POPULAR", "LATEST"] as BrowseType[]) as mode}
<button class="tab" class:active={browseType === mode && !search} on:click={() => setMode(mode)}>
<button class="tab" class:active={browseType === mode && !search} onclick={() => setMode(mode)}>
{mode.charAt(0) + mode.slice(1).toLowerCase()}
</button>
{/each}
@@ -80,7 +92,7 @@
<div class="search-wrap">
<MagnifyingGlass size={12} class="search-icon" weight="light" />
<input class="search" placeholder="Search source…" bind:value={searchInput}
on:keydown={(e) => e.key === "Enter" && submitSearch()} />
onkeydown={(e) => e.key === "Enter" && submitSearch()} />
</div>
</div>
@@ -95,8 +107,9 @@
{:else}
<div class="grid">
{#each mangas as m (m.id)}
<button class="card" on:click={() => { activeManga.set(m); navPage.set("library"); }}
on:contextmenu={(e) => { e.preventDefault(); e.stopPropagation(); ctx = { x: e.clientX, y: e.clientY, manga: m }; }}>
<button class="card"
onclick={() => { activeManga = m; navPage = "library"; }}
oncontextmenu={(e) => { e.preventDefault(); e.stopPropagation(); ctx = { x: e.clientX, y: e.clientY, manga: m }; }}>
<div class="cover-wrap">
<img src={thumbUrl(m.thumbnailUrl)} alt={m.title} class="cover" />
{#if m.inLibrary}<span class="in-library-badge">In Library</span>{/if}
@@ -109,11 +122,11 @@
{#if !loading && (page > 1 || hasNextPage)}
<div class="pagination">
<button class="page-btn" on:click={() => page = Math.max(1, page - 1)} disabled={page === 1}>
<button class="page-btn" onclick={() => page = Math.max(1, page - 1)} disabled={page === 1}>
<Prev size={13} weight="light" /> Prev
</button>
<span class="page-num">{page}</span>
<button class="page-btn" on:click={() => page++} disabled={!hasNextPage}>
<button class="page-btn" onclick={() => page++} disabled={!hasNextPage}>
Next <Next size={13} weight="light" />
</button>
</div>