From 581aea5694f530cbb190b314dcd13bc3283d8e60 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Thu, 23 Apr 2026 22:37:42 -0500 Subject: [PATCH] Feat: Pin Sources on SourceTab (#48) --- .../discover/components/SourceTab.svelte | 68 ++++++++++++++++++- src/store/state.svelte.ts | 9 +++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/features/discover/components/SourceTab.svelte b/src/features/discover/components/SourceTab.svelte index 8a749de..0aa3b6c 100644 --- a/src/features/discover/components/SourceTab.svelte +++ b/src/features/discover/components/SourceTab.svelte @@ -5,6 +5,8 @@ import { shouldHideNsfw, shouldHideSource } from "@core/util"; import { store } from "@store/state.svelte"; import Thumbnail from "@shared/manga/Thumbnail.svelte"; + import ContextMenu from "@shared/ui/ContextMenu.svelte"; + import { PushPin, PushPinSlash, ArrowRight } from "phosphor-svelte"; import type { Manga, Source } from "@types"; interface Props { @@ -28,6 +30,17 @@ let src_currentPage = $state(1); let src_abortCtrl: AbortController | null = null; + let ctx_x = $state(0); + let ctx_y = $state(0); + let ctx_source: Source | null = $state(null); + + const pinnedIds = $derived(store.settings.pinnedSourceIds ?? []); + const pinnedSources = $derived( + pinnedIds + .map(id => allSources.find(s => s.id === id)) + .filter((s): s is Source => !!s) + ); + $effect(() => { if (!allSources.length) return; const langs = new Set(allSources.map((s) => s.lang)); @@ -93,11 +106,16 @@ if (src_activeSource) srcFetchBrowse(src_activeSource, "POPULAR"); } + function openCtx(e: MouseEvent, src: Source) { + e.preventDefault(); + ctx_x = e.clientX; ctx_y = e.clientY; ctx_source = src; + } + function closeCtx() { ctx_source = null; } + onDestroy(() => { src_abortCtrl?.abort(); });
-
Language @@ -122,6 +140,7 @@ class="splitItem splitItemSource" class:splitItemActive={src_activeSource?.id === localSource.id} onclick={() => srcSelectSource(localSource)} + oncontextmenu={(e) => openCtx(e, localSource)} >
{/if} + + {#if pinnedSources.length > 0} + + {#each pinnedSources as src (src.id)} + + {/each} +
+ + {/if} + {#each src_visibleSources as src (src.id)}
+{#if ctx_source} + {@const isPinned = pinnedIds.includes(ctx_source.id)} + { store.togglePinnedSource(ctx_source!.id); }, + }, + { separator: true }, + { + label: "Browse source", + icon: ArrowRight, + onClick: () => { srcSelectSource(ctx_source!); }, + }, + ]} + /> +{/if} +