feat(page): 곡 검색 결과를 리스트 행으로, 대기열 접기/펴기 추가 — 익숙한 형태로 정렬

"많이 쓰는 음악 사이트처럼" 이라는 요구에 맞춰, 형태가 관행과 달랐던 두 곳을 바꿨다.

1) 검색 결과: 그리드 카드 -> 리스트 행
   그리드(커버 중심)는 앨범·재생목록을 훑을 때 쓰는 형태이고, 개별 곡 검색 결과는
   스포티파이·유튜브뮤직 모두 행(번호/썸네일/제목·아티스트/재생시간) 형식이다.
   행 전체가 버튼이라 터치로도 바로 누를 수 있고, 마우스 환경에서는 번호 자리에
   재생 아이콘이 겹치는 스포티파이 곡 목록 방식을 따랐다. 좁은 화면은 hover 가 없어
   썸네일에 재생 아이콘을 항상 얹는다.

2) 대기열 접기/펴기
   재생바 우측(스포티파이와 같은 자리)에 대기열 버튼을 두어 넓은 화면에서도 접을 수 있게 했다.
   화면 크기별 기본값이 달라(좁은 화면=접힘, 넓은 화면=펼침) 상태를 둘로 나눴다.
   창 크기를 읽어 한 상태로 합치면 SSR/하이드레이션이 어긋나고 setState-in-effect 경고도 난다.

검증: tsc 통과, lint 에러 0. 데스크톱(1440x900)·모바일(390x844)에서 검색 결과 행 렌더링과
대기열 접기/펴기 동작을 실제 화면으로 확인. README 5-3 비교표에 두 항목 추가.
This commit is contained in:
2026-09-29 14:11:06 +09:00
parent 2b7a91774d
commit 3406ba64c4
4 changed files with 65 additions and 27 deletions

View File

@@ -18,8 +18,12 @@ export default function MusicPlayerLayout() {
const [viewMode, setViewMode] = useState<ViewMode>("SERVER_LIST");
const [selectedServer, setSelectedServer] = useState<DiscordServer | null>(null);
const [searchQuery, setSearchQuery] = useState("");
// 모바일에서 대기열은 상시 컬럼이 아니라 오른쪽에서 밀려나오는 패널로 띄운다.
// 대기열 표시 상태는 화면 크기별로 기본값이 달라서 두 개로 나눠 둔다.
// (창 크기를 읽어 한 상태로 합치면 SSR·하이드레이션이 어긋난다)
// · 좁은 화면: 기본 접힘 → 버튼으로 슬라이드 패널을 연다
// · 넓은 화면: 기본 펼침 → 재생바의 대기열 버튼으로 접을 수 있다
const [isQueueOpen, setIsQueueOpen] = useState(false);
const [isQueueDocked, setIsQueueDocked] = useState(true);
// 재생바가 이미 폴링하는 현재 곡을 대기열 패널과 공유한다(같은 API 를 두 번 부르지 않기 위함).
const [nowPlaying, setNowPlaying] = useState<Track | null>(null);
const handleNowPlayingChange = useCallback((t: Track | null) => setNowPlaying(t), []);
@@ -95,8 +99,9 @@ export default function MusicPlayerLayout() {
<div
className={`absolute inset-y-0 right-0 z-40 w-[22rem] max-w-[88%] transform border-l border-neutral-800 bg-neutral-950 shadow-2xl transition-transform duration-300 ease-out
${isQueueOpen ? "translate-x-0" : "translate-x-full"}
lg:static lg:z-auto lg:w-80 lg:max-w-none lg:translate-x-0 lg:shadow-none`}
aria-hidden={!isQueueOpen && typeof window !== "undefined" && window.innerWidth < 1024}
${isQueueDocked
? "lg:static lg:z-auto lg:w-80 lg:max-w-none lg:translate-x-0 lg:shadow-none"
: "lg:hidden"}`}
>
<QueueSidebar
selectedServer={selectedServer}
@@ -113,6 +118,8 @@ export default function MusicPlayerLayout() {
selectedServer={selectedServer}
onToggleQueue={() => setIsQueueOpen((v) => !v)}
isQueueOpen={isQueueOpen}
onToggleDock={() => setIsQueueDocked((v) => !v)}
isQueueDocked={isQueueDocked}
onNowPlayingChange={handleNowPlayingChange}
/>
)}