From a7bc2e9800fe9470e8771cea785b08ea288be22f Mon Sep 17 00:00:00 2001 From: caadiq Date: Sat, 24 Jan 2026 12:03:33 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=A1=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=ED=8A=B8=EB=9E=99=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EC=8B=9C=20=EC=8A=A4=ED=81=AC=EB=A1=A4/=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ScrollToTop: PC 레이아웃의 main 요소 스크롤 초기화 추가 - TrackDetail: key prop으로 트랙 변경 시 컴포넌트 리마운트 - TrackDetail: main 요소 스크롤 초기화 (PC는 main에서 스크롤) - 수록곡 선택 시 Link 대신 button + navigate 사용 Co-Authored-By: Claude Opus 4.5 --- .../src/components/common/ScrollToTop.jsx | 6 ++++ .../src/pages/mobile/album/TrackDetail.jsx | 9 +++-- .../src/pages/pc/public/album/TrackDetail.jsx | 35 +++++++++++++++---- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/common/ScrollToTop.jsx b/frontend/src/components/common/ScrollToTop.jsx index 99bcedc..5b50752 100644 --- a/frontend/src/components/common/ScrollToTop.jsx +++ b/frontend/src/components/common/ScrollToTop.jsx @@ -16,6 +16,12 @@ function ScrollToTop() { if (mobileContent) { mobileContent.scrollTop = 0; } + + // PC 레이아웃 스크롤 컨테이너 초기화 + const main = document.querySelector('main'); + if (main) { + main.scrollTop = 0; + } }, [pathname]); return null; diff --git a/frontend/src/pages/mobile/album/TrackDetail.jsx b/frontend/src/pages/mobile/album/TrackDetail.jsx index 2e76f45..b50cca3 100644 --- a/frontend/src/pages/mobile/album/TrackDetail.jsx +++ b/frontend/src/pages/mobile/album/TrackDetail.jsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useEffect } from 'react'; +import { useState, useMemo, useEffect, useLayoutEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import { motion } from 'framer-motion'; @@ -40,6 +40,11 @@ function MobileTrackDetail() { const youtubeVideoId = useMemo(() => getYoutubeVideoId(track?.video_url), [track?.video_url]); const videoLabel = track?.video_type === 'special' ? '스페셜 영상' : '뮤직비디오'; + // 트랙 변경 시 스크롤 맨 위로 + useLayoutEffect(() => { + window.scrollTo({ top: 0, behavior: 'instant' }); + }, [trackTitle]); + // 가사 펼침 상태 const [showFullLyrics, setShowFullLyrics] = useState(false); @@ -93,7 +98,7 @@ function MobileTrackDetail() { } return ( -
+
{/* 트랙 정보 헤더 */} getYoutubeVideoId(track?.video_url), [track?.video_url]); const videoLabel = track?.video_type === 'special' ? '스페셜 영상' : '뮤직비디오'; + // 트랙 변경 시 스크롤 맨 위로 + useLayoutEffect(() => { + const main = document.querySelector('main'); + if (main) { + main.scrollTop = 0; + } + }, [trackTitle]); + if (loading) { return ( +
{/* 브레드크럼 네비게이션 */}
@@ -218,11 +232,18 @@ function PCTrackDetail() { {track.otherTracks?.map((t) => { const isCurrent = t.title === track.title; return ( - { + if (!isCurrent) { + navigate( + `/album/${encodeURIComponent(track.album?.title || albumName)}/track/${encodeURIComponent(t.title)}`, + { replace: true } + ); + } + }} + className={`w-full group flex items-center gap-3 px-3 py-2.5 rounded-xl transition-all ${ isCurrent ? 'bg-primary text-white' : 'hover:bg-gray-50' }`} > @@ -259,7 +280,7 @@ function PCTrackDetail() { {t.duration || ''} - + ); })}