diff options
Diffstat (limited to 'src/routes/subscriptions/+page.svelte')
| -rw-r--r-- | src/routes/subscriptions/+page.svelte | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/routes/subscriptions/+page.svelte b/src/routes/subscriptions/+page.svelte new file mode 100644 index 0000000..9f318ac --- /dev/null +++ b/src/routes/subscriptions/+page.svelte @@ -0,0 +1,151 @@ +<script lang="ts"> + import { subscriptions } from '$lib/stores/subscriptions'; + import { getChannel, type VideoInfo } from '$lib/api/youtube'; + import VideoCard from '$lib/components/VideoCard.svelte'; + import ChannelCard from '$lib/components/ChannelCard.svelte'; + + let videos = $state<VideoInfo[]>([]); + let loading = $state(true); + let error = $state(''); + let activeTab = $state<'feed' | 'channels'>('feed'); + + $effect(() => { + if ($subscriptions.length > 0 && activeTab === 'feed') { + loadFeed(); + } else if ($subscriptions.length === 0) { + loading = false; + } + }); + + async function loadFeed() { + loading = true; + error = ''; + + try { + const results = await Promise.all( + $subscriptions.map(sub => + getChannel(sub.channelId).catch(() => ({ videos: [] })) + ) + ); + + const allVideos = results.flatMap(r => r.videos); + videos = allVideos.slice(0, 50); + } catch (e) { + error = e instanceof Error ? e.message : 'Failed to load feed'; + } finally { + loading = false; + } + } +</script> + +<svelte:head> + <title>Subscriptions - ActualYT</title> +</svelte:head> + +<div class="container"> + <div class="header"> + <h1 class="section-title">Subscriptions</h1> + <div class="tabs"> + <button + class="tab" + class:active={activeTab === 'feed'} + onclick={() => activeTab = 'feed'} + > + Feed + </button> + <button + class="tab" + class:active={activeTab === 'channels'} + onclick={() => activeTab = 'channels'} + > + Channels ({$subscriptions.length}) + </button> + </div> + </div> + + {#if $subscriptions.length === 0} + <div class="empty"> + <p>You haven't subscribed to any channels yet.</p> + <p>Find channels you like and click Subscribe to see their videos here.</p> + </div> + {:else if activeTab === 'feed'} + {#if loading} + <div class="loading">Loading your feed</div> + {:else if error} + <div class="error">{error}</div> + {:else if videos.length === 0} + <div class="empty">No recent videos from your subscriptions</div> + {:else} + <div class="video-grid"> + {#each videos as video (video.videoId)} + <VideoCard + videoId={video.videoId} + title={video.title} + author={video.author} + authorId={video.authorId} + thumbnails={video.videoThumbnails} + viewCount={video.viewCount} + publishedText={video.publishedText} + lengthSeconds={video.lengthSeconds} + /> + {/each} + </div> + {/if} + {:else} + <div class="channel-list"> + {#each $subscriptions as sub (sub.channelId)} + <ChannelCard + channelId={sub.channelId} + channelName={sub.channelName} + thumbnails={[{ url: sub.thumbnail, width: 88, height: 88 }]} + /> + {/each} + </div> + {/if} +</div> + +<style> + .header { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 1rem; + margin-bottom: 1.5rem; + } + + .section-title { + margin-bottom: 0; + } + + .tabs { + display: flex; + gap: 0.5rem; + } + + .tab { + padding: 0.5rem 1rem; + border: none; + border-radius: 20px; + background: var(--bg-secondary); + color: var(--text-secondary); + font-size: 0.9rem; + cursor: pointer; + transition: background 0.15s ease, color 0.15s ease; + } + + .tab:hover { + background: var(--bg-hover); + } + + .tab.active { + background: var(--text-primary); + color: var(--bg-primary); + } + + .channel-list { + display: flex; + flex-direction: column; + gap: 0.5rem; + } +</style> |
