Update album component motion and interaction
This commit is contained in:
parent
188e95f597
commit
1bbc4260de
2 changed files with 58 additions and 14 deletions
|
|
@ -9,33 +9,41 @@
|
||||||
|
|
||||||
interface AlbumProps {
|
interface AlbumProps {
|
||||||
album?: Album
|
album?: Album
|
||||||
|
albumId?: string
|
||||||
|
hoveredAlbumId?: string | null
|
||||||
|
onHover?: (albumId: string | null) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
let { album = undefined }: AlbumProps = $props()
|
let { album = undefined, albumId = '', hoveredAlbumId = null, onHover }: AlbumProps = $props()
|
||||||
|
|
||||||
let isHovering = $state(false)
|
let isHovering = $state(false)
|
||||||
let audio: HTMLAudioElement | null = $state(null)
|
let audio: HTMLAudioElement | null = $state(null)
|
||||||
|
|
||||||
// Create a unique ID for this album
|
// Create a unique ID for this album if not provided
|
||||||
const albumId = $derived(album ? `${album.artist.name}-${album.name}` : '')
|
const currentAlbumId = $derived(albumId || (album ? `${album.artist.name}-${album.name}` : ''))
|
||||||
|
|
||||||
// Subscribe to the store to know if this album is playing
|
// Subscribe to the store to know if this album is playing
|
||||||
let isPlaying = $state(false)
|
let isPlaying = $state(false)
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const unsubscribe = audioPreview.subscribe((state) => {
|
const unsubscribe = audioPreview.subscribe((state) => {
|
||||||
isPlaying = state.currentAlbumId === albumId && state.isPlaying
|
isPlaying = state.currentAlbumId === currentAlbumId && state.isPlaying
|
||||||
})
|
})
|
||||||
return unsubscribe
|
return unsubscribe
|
||||||
})
|
})
|
||||||
|
|
||||||
const scale = new Spring(1, {
|
const scale = new Spring(1, {
|
||||||
stiffness: 0.1,
|
stiffness: 0.2,
|
||||||
damping: 0.25
|
damping: 0.12
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Determine if this album should shrink
|
||||||
|
const shouldShrink = $derived(hoveredAlbumId !== null && hoveredAlbumId !== currentAlbumId)
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (isHovering) {
|
if (isHovering) {
|
||||||
scale.target = 1.1
|
scale.target = 1.1
|
||||||
|
} else if (shouldShrink) {
|
||||||
|
scale.target = 0.95
|
||||||
} else {
|
} else {
|
||||||
scale.target = 1
|
scale.target = 1
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +65,7 @@
|
||||||
audioPreview.stop()
|
audioPreview.stop()
|
||||||
} else {
|
} else {
|
||||||
// Update the store first, then play
|
// Update the store first, then play
|
||||||
audioPreview.play(audio, albumId)
|
audioPreview.play(audio, currentAlbumId)
|
||||||
try {
|
try {
|
||||||
await audio.play()
|
await audio.play()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -111,8 +119,14 @@
|
||||||
href={album.url}
|
href={album.url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onmouseenter={() => (isHovering = true)}
|
onmouseenter={() => {
|
||||||
onmouseleave={() => (isHovering = false)}
|
isHovering = true
|
||||||
|
onHover?.(currentAlbumId)
|
||||||
|
}}
|
||||||
|
onmouseleave={() => {
|
||||||
|
isHovering = false
|
||||||
|
onHover?.(null)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div class="artwork-container">
|
<div class="artwork-container">
|
||||||
<img
|
<img
|
||||||
|
|
@ -124,9 +138,10 @@
|
||||||
{#if isNowPlaying}
|
{#if isNowPlaying}
|
||||||
<NowPlaying trackName={nowPlayingTrack !== album.name ? nowPlayingTrack : undefined} />
|
<NowPlaying trackName={nowPlayingTrack !== album.name ? nowPlayingTrack : undefined} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if hasPreview && isHovering}
|
{#if hasPreview && (isHovering || isPlaying)}
|
||||||
<button
|
<button
|
||||||
class="preview-button"
|
class="preview-button"
|
||||||
|
class:corner={isPlaying && !isHovering}
|
||||||
onclick={togglePreview}
|
onclick={togglePreview}
|
||||||
aria-label={isPlaying ? 'Pause preview' : 'Play preview'}
|
aria-label={isPlaying ? 'Pause preview' : 'Play preview'}
|
||||||
class:playing={isPlaying}
|
class:playing={isPlaying}
|
||||||
|
|
@ -206,12 +221,26 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.3s ease;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
|
|
||||||
|
&.corner {
|
||||||
|
top: auto;
|
||||||
|
left: $unit * 1.5;
|
||||||
|
bottom: $unit-2x;
|
||||||
|
transform: none;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.5);
|
||||||
transform: translate(-50%, -50%) scale(1.1);
|
transform: translate(-50%, -50%) scale(1.1);
|
||||||
|
|
||||||
|
&.corner {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.playing {
|
&.playing {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,30 @@
|
||||||
import Album from '$components/Album.svelte'
|
import Album from '$components/Album.svelte'
|
||||||
import type { Album as AlbumType } from '$lib/types/lastfm'
|
import type { Album as AlbumType } from '$lib/types/lastfm'
|
||||||
|
|
||||||
export let albums: AlbumType[] = []
|
interface RecentAlbumsProps {
|
||||||
|
albums?: AlbumType[]
|
||||||
|
}
|
||||||
|
|
||||||
|
let { albums = [] }: RecentAlbumsProps = $props()
|
||||||
|
|
||||||
|
let hoveredAlbumId: string | null = $state(null)
|
||||||
|
|
||||||
|
function handleAlbumHover(albumId: string | null) {
|
||||||
|
hoveredAlbumId = albumId
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="recent-albums">
|
<section class="recent-albums">
|
||||||
{#if albums.length > 0}
|
{#if albums.length > 0}
|
||||||
<ul>
|
<ul>
|
||||||
{#each albums.slice(0, 4) as album}
|
{#each albums.slice(0, 4) as album, index}
|
||||||
<li>
|
<li>
|
||||||
<Album {album} />
|
<Album
|
||||||
|
{album}
|
||||||
|
albumId={`${album.artist.name}-${album.name}`}
|
||||||
|
{hoveredAlbumId}
|
||||||
|
onHover={handleAlbumHover}
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue