diff --git a/src/shared/ui/Link.tsx b/src/shared/ui/Link.tsx index 90ab994b..37c1dca0 100644 --- a/src/shared/ui/Link.tsx +++ b/src/shared/ui/Link.tsx @@ -6,11 +6,12 @@ import type { Track } from '@/entities/playlist' interface LinkProps { variant?: 'large' | 'small' data: Track + onClick?: () => void } -const Link = ({ variant = 'large', data }: LinkProps) => { +const Link = ({ variant = 'large', data, onClick }: LinkProps) => { return ( - + {!data.youtubeThumbnail && ( diff --git a/src/widgets/playlist/PlaylistInfo.tsx b/src/widgets/playlist/PlaylistInfo.tsx index ac57db1b..fc495aa0 100644 --- a/src/widgets/playlist/PlaylistInfo.tsx +++ b/src/widgets/playlist/PlaylistInfo.tsx @@ -2,6 +2,7 @@ import { useNavigate } from 'react-router-dom' import styled from 'styled-components' +import { usePlaylist } from '@/app/providers/PlayerProvider' import { Cancel } from '@/assets/icons' import type { PlaylistDetailResponse } from '@/entities/playlist' import { getGenreLabel } from '@/shared/lib' @@ -17,6 +18,13 @@ interface PlaylistInfoProps { const PlaylistInfo = ({ playlistData, isLoading, isError }: PlaylistInfoProps) => { const navigate = useNavigate() + const { setPlaylist, currentPlaylist } = usePlaylist() + + const handleClickTrack = (trackIndex: number) => { + if (!currentPlaylist) return + navigate(-1) + setPlaylist(currentPlaylist, trackIndex, 0) + } if (isError || !playlistData) { return ( @@ -50,7 +58,12 @@ const PlaylistInfo = ({ playlistData, isLoading, isError }: PlaylistInfoProps) = {playlistData.songs && playlistData.songs.map((track, index) => ( - + handleClickTrack(index)} + /> ))} diff --git a/src/widgets/playlist/PlaylistLayout.tsx b/src/widgets/playlist/PlaylistLayout.tsx index 0e6ef0d1..4015c151 100644 --- a/src/widgets/playlist/PlaylistLayout.tsx +++ b/src/widgets/playlist/PlaylistLayout.tsx @@ -80,7 +80,7 @@ const PlaylistLayout = ({ )} - + {isMobile && ( )} @@ -130,6 +130,18 @@ const Container = styled.div` justify-content: space-between; ` -const CdWrapper = styled.div` +const CdWrapper = styled.div<{ $isPlaying: boolean }>` position: relative; + animation: spin 40s linear infinite; + animation-play-state: ${(props) => (props.$isPlaying ? 'running' : 'paused')}; + transform-origin: center; + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } ` diff --git a/src/widgets/playlist/YoutubePlayer.tsx b/src/widgets/playlist/YoutubePlayer.tsx index 214b26a2..caff8d96 100644 --- a/src/widgets/playlist/YoutubePlayer.tsx +++ b/src/widgets/playlist/YoutubePlayer.tsx @@ -1,7 +1,7 @@ +import { useRef, useEffect } from 'react' import YouTube from 'react-youtube' -import type { YouTubeProps, YouTubeEvent, YouTubePlayer } from 'react-youtube' // +import type { YouTubeProps, YouTubeEvent, YouTubePlayer } from 'react-youtube' -import { useDevice } from '@/shared/lib/useDevice' interface YoutubePlayerProps { videoId: string @@ -10,23 +10,38 @@ interface YoutubePlayerProps { } function YoutubePlayer({ videoId, onReady, onStateChange }: YoutubePlayerProps) { - const deviceType = useDevice() - const isMobile = deviceType === 'mobile' + const playerRef = useRef(null) + const isFirstLoad = useRef(true) const playerOpts: YouTubeProps['opts'] = { playerVars: { autoplay: 1, - mute: isMobile ? 1 : 0, + mute: 0, playsinline: 1, // 모바일 인라인 재생 }, } + useEffect(() => { + if (!isFirstLoad.current && playerRef.current && videoId) { + // 첫 로딩 제외하고 loadVideoById 호출 + try { + playerRef.current.loadVideoById(videoId) + } catch (e) { + console.error('loadVideoById 실패', e) + } + } + isFirstLoad.current = false + }, [videoId]) + return (
{ + playerRef.current = e.target + onReady(e) + }} onStateChange={onStateChange} />