refactor: separate podcasts from downloads — own route + nav item
All checks were successful
Security Checks / dependency-audit (push) Successful in 13s
Security Checks / secret-scanning (push) Successful in 3s
Security Checks / dockerfile-lint (push) Successful in 4s

- /podcasts — new page with PodcastPlayer (headphones icon)
- /downloads — old media page renamed (download icon)
- /media — kept for backward compat (same as downloads)
- Nav: Reader → Podcasts → Downloads → Brain

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yusuf Suleman
2026-04-03 07:42:56 -05:00
parent 587040b7a6
commit 0e9702d494
13 changed files with 105 additions and 3442 deletions

BIN
Platform-clean.zip Normal file

Binary file not shown.

View File

@@ -7,7 +7,9 @@
CalendarDays,
CircleDot,
Compass,
Download,
Dumbbell,
Headphones,
Landmark,
LibraryBig,
Menu,
@@ -42,7 +44,8 @@
{ id: 'budget', href: '/budget', label: 'Budget', icon: Landmark },
{ id: 'inventory', href: '/inventory', label: 'Inventory', icon: Package2 },
{ id: 'reader', href: '/reader', label: 'Reader', icon: BookOpen },
{ id: 'media', href: '/media', label: 'Media', icon: LibraryBig },
{ id: 'media', href: '/podcasts', label: 'Podcasts', icon: Headphones },
{ id: 'downloads', href: '/downloads', label: 'Downloads', icon: Download },
{ id: 'brain', href: '/brain', label: 'Brain', icon: Brain },
{ id: 'settings', href: '/settings', label: 'Settings', icon: Settings2 }
];

View File

@@ -24,7 +24,7 @@ export const load: LayoutServerLoad = async ({ cookies, url }) => {
// Hides nav items but does NOT block direct URL access.
// This is intentional: all shared services are accessible to all authenticated users.
// Hiding reduces clutter for users who don't need certain apps day-to-day.
const allApps = ['tasks', 'trips', 'fitness', 'inventory', 'budget', 'reader', 'media', 'brain'];
const allApps = ['tasks', 'trips', 'fitness', 'inventory', 'budget', 'reader', 'media', 'downloads', 'brain'];
const hiddenByUser: Record<string, string[]> = {
'madiha': ['inventory', 'reader', 'brain'],
};

View File

@@ -0,0 +1,75 @@
<script lang="ts">
import { page } from '$app/state';
import BookSearch from '$lib/components/media/BookSearch.svelte';
import MusicSearch from '$lib/components/media/MusicSearch.svelte';
import BookLibrary from '$lib/components/media/BookLibrary.svelte';
type MediaTab = 'books' | 'music' | 'library';
const urlMode = page.url.searchParams.get('mode');
let activeTab = $state<MediaTab>(urlMode === 'music' ? 'music' : urlMode === 'library' ? 'library' : 'books');
</script>
<div class="page">
<div class="app-surface">
<div class="page-header">
<div class="page-title">DOWNLOADS</div>
<div class="page-subtitle">
{#if activeTab === 'books'}Book Downloads
{:else if activeTab === 'music'}Music Downloads
{:else}Book Library{/if}
</div>
</div>
<div class="media-tabs">
<button class="tab" class:active={activeTab === 'books'} onclick={() => activeTab = 'books'}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Books
</button>
<button class="tab" class:active={activeTab === 'music'} onclick={() => activeTab = 'music'}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>
Music
</button>
<button class="tab" class:active={activeTab === 'library'} onclick={() => activeTab = 'library'}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Library
</button>
</div>
{#if activeTab === 'books'}
<BookSearch />
{:else if activeTab === 'music'}
<MusicSearch />
{:else}
<BookLibrary />
{/if}
</div>
</div>
<style>
.page-subtitle {
font-size: var(--text-2xl);
font-weight: 300;
color: var(--text-1);
line-height: 1.2;
}
.media-tabs {
display: flex; gap: var(--sp-1); margin-bottom: var(--sp-5);
border-bottom: 1px solid var(--border); padding-bottom: 0;
}
.tab {
display: flex; align-items: center; gap: var(--sp-2);
flex: 1; padding: 10px var(--sp-2) 12px; font-size: var(--text-base); font-weight: 500;
color: var(--text-3); background: none; border: none; border-bottom: 2px solid transparent;
cursor: pointer; font-family: var(--font); transition: all var(--transition);
text-align: center; justify-content: center; margin-bottom: -1px;
}
.tab:hover { color: var(--text-2); }
.tab.active { color: var(--text-1); border-bottom-color: var(--accent); font-weight: 600; }
.tab svg { width: 16px; height: 16px; flex-shrink: 0; }
@media (max-width: 768px) {
.page-subtitle { font-size: var(--text-xl); }
}
</style>

View File

@@ -3,27 +3,20 @@
import BookSearch from '$lib/components/media/BookSearch.svelte';
import MusicSearch from '$lib/components/media/MusicSearch.svelte';
import BookLibrary from '$lib/components/media/BookLibrary.svelte';
import PodcastPlayer from '$lib/components/media/PodcastPlayer.svelte';
type MediaTab = 'books' | 'music' | 'library' | 'podcasts';
type MediaTab = 'books' | 'music' | 'library';
const urlMode = page.url.searchParams.get('mode');
let activeTab = $state<MediaTab>(
urlMode === 'music' ? 'music'
: urlMode === 'library' ? 'library'
: urlMode === 'podcasts' ? 'podcasts'
: 'books'
);
let activeTab = $state<MediaTab>(urlMode === 'music' ? 'music' : urlMode === 'library' ? 'library' : 'books');
</script>
<div class="page">
<div class="app-surface">
<div class="page-header">
<div class="page-title">MEDIA</div>
<div class="page-title">DOWNLOADS</div>
<div class="page-subtitle">
{#if activeTab === 'books'}Book Downloads
{:else if activeTab === 'music'}Music Downloads
{:else if activeTab === 'podcasts'}Podcast Player
{:else}Book Library{/if}
</div>
</div>
@@ -37,10 +30,6 @@
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>
Music
</button>
<button class="tab" class:active={activeTab === 'podcasts'} onclick={() => activeTab = 'podcasts'}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="20" r="1"/></svg>
Podcasts
</button>
<button class="tab" class:active={activeTab === 'library'} onclick={() => activeTab = 'library'}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Library
@@ -51,8 +40,6 @@
<BookSearch />
{:else if activeTab === 'music'}
<MusicSearch />
{:else if activeTab === 'podcasts'}
<PodcastPlayer />
{:else}
<BookLibrary />
{/if}

View File

@@ -0,0 +1,22 @@
<script lang="ts">
import PodcastPlayer from '$lib/components/media/PodcastPlayer.svelte';
</script>
<div class="page">
<div class="app-surface">
<div class="page-header">
<div class="page-title">PODCASTS</div>
<div class="page-subtitle">Your podcast library</div>
</div>
<PodcastPlayer />
</div>
</div>
<style>
.page-subtitle {
font-size: var(--text-2xl);
font-weight: 300;
color: var(--text-1);
line-height: 1.2;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,19 +0,0 @@
%PDF-1.0
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj
2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj
3 0 obj<</Type/Page/MediaBox[0 0 612 792]/Parent 2 0 R/Resources<</Font<</F1 4 0 R>>>>/Contents 5 0 R>>endobj
4 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj
5 0 obj<</Length 200>>
stream
BT /F1 18 Tf 72 700 Td (State Farm Insurance Policy) Tj ET
BT /F1 12 Tf 72 670 Td (Policy Number: SF-2024-881234) Tj ET
BT /F1 12 Tf 72 650 Td (Policyholder: Yusuf Suleman) Tj ET
BT /F1 12 Tf 72 630 Td (Deductible: 500 dollars) Tj ET
endstream
endobj
xref
0 6
trailer<</Size 6/Root 1 0 R>>
startxref
0
%%EOF

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long