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