feat(ui): add ViewTransition to PlaylistDetail and PlaylistManager views

- PlaylistDetailView: outer slide-down (200ms), spinner fadeout, content slide-up
- PlaylistManagerView: outer slide-down (200ms), spinner fadeout, content slide-up
- Matches the FavoritesView transition pattern
This commit is contained in:
vicrodh committed 2026-01-29 19:58:06 -06:00
1 parent 4ce7694290
commit df17f859e0
2 files changed
+42 -5

No files matched your search

@@ -3,6 +3,7 @@
import AlbumMenu from '../AlbumMenu.svelte';
import PlaylistCollage from '../PlaylistCollage.svelte';
import PlaylistModal from '../PlaylistModal.svelte';
import ViewTransition from '../ViewTransition.svelte';
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
import { invoke } from '@tauri-apps/api/core';
import { open } from '@tauri-apps/plugin-dialog';
@@ -205,6 +206,7 @@
);
let loading = $state(true);
let spinnerFading = $state(false);
let error = $state<string | null>(null);
let scrollContainer: HTMLDivElement | null = $state(null);
@@ -499,7 +501,11 @@
console.error('Failed to load playlist:', err);
error = String(err);
} finally {
loading = false;
spinnerFading = true;
setTimeout(() => {
loading = false;
spinnerFading = false;
}, 200);
}
}
@@ -1402,6 +1408,7 @@
}
</script>
<ViewTransition duration={200} distance={12} direction="down">
<div class="playlist-detail" bind:this={scrollContainer}>
<!-- Navigation Row -->
<div class="nav-row">
@@ -1417,7 +1424,7 @@
</div>
{#if loading}
<div class="loading">
<div class="loading" class:fading={spinnerFading}>
<div class="spinner"></div>
<p>Loading playlist...</p>
</div>
@@ -1428,6 +1435,7 @@
<button class="retry-btn" onclick={loadPlaylist}>Retry</button>
</div>
{:else if playlist}
<ViewTransition duration={200} distance={12} direction="up">
<!-- Playlist Header -->
<div class="playlist-header">
<!-- Playlist Artwork - Collage or Custom -->
@@ -1736,9 +1744,10 @@
showReasons={false}
/>
{/if}
</ViewTransition>
{/if}
</div>
</ViewTransition>
<!-- Edit Playlist Modal -->
{#if playlist}
@@ -1835,6 +1844,15 @@
color: var(--text-muted);
}
.loading {
opacity: 1;
transition: opacity 200ms ease-out;
}
.loading.fading {
opacity: 0;
}
.spinner {
width: 32px;
height: 32px;
@@ -4,6 +4,7 @@
import { ArrowLeft, Filter, ArrowUpDown, LayoutGrid, List, GripVertical, EyeOff, Eye, BarChart2, Play, Pencil, Search, X, Cloud, CloudOff, Wifi, Heart, Folder, FolderPlus, ChevronRight, ChevronDown, ChevronUp, Trash2, Star, Music, Disc, Library, Info } from 'lucide-svelte';
import PlaylistCollage from '../PlaylistCollage.svelte';
import PlaylistModal from '../PlaylistModal.svelte';
import ViewTransition from '../ViewTransition.svelte';
import FolderEditModal from '../FolderEditModal.svelte';
import { t } from '$lib/i18n';
import {
@@ -76,6 +77,7 @@
let localTrackCounts = $state<Map<number, number>>(new Map());
let pendingPlaylistsMap = $state<Map<number, import('$lib/stores/offlineStore').PendingPlaylist>>(new Map());
let loading = $state(true);
let spinnerFading = $state(false);
// Offline state
let offlineStatus = $state<OfflineStatus>(getOfflineStatus());
@@ -447,7 +449,11 @@
} catch (err) {
console.error('Failed to load playlists:', err);
} finally {
loading = false;
spinnerFading = true;
setTimeout(() => {
loading = false;
spinnerFading = false;
}, 200);
}
}
@@ -750,6 +756,7 @@
}
</script>
<ViewTransition duration={200} distance={12} direction="down">
<div class="playlist-manager">
<!-- Header -->
<div class="header">
@@ -920,11 +927,12 @@
<!-- Content -->
{#if loading}
<div class="loading">
<div class="loading" class:fading={spinnerFading}>
<div class="spinner"></div>
<p>Loading playlists...</p>
</div>
{:else}
<ViewTransition duration={200} distance={12} direction="up">
<!-- Folders Section (only at root level) -->
{#if !currentFolderId && folders.length > 0}
<div class="folders-section">
@@ -1288,8 +1296,10 @@
</div>
{/if}
{/if}
</ViewTransition>
{/if}
</div>
</ViewTransition>
<!-- Folder Modal -->
<FolderEditModal
@@ -1901,6 +1911,15 @@
color: var(--text-muted);
}
.loading {
opacity: 1;
transition: opacity 200ms ease-out;
}
.loading.fading {
opacity: 0;
}
.spinner {
width: 32px;
height: 32px;