style(admin): 곡 검색 다이얼로그 선택 순서 번호 표시

- 체크 아이콘 대신 선택 순서(1, 2, 3...) 숫자 뱃지 표시
- 선택 해제 시 남은 곡 번호 자동 재계산
- 숫자 시각 중심 보정 (leading-none + translate-y)
- 순서는 이미 클릭 순서대로 세트리스트에 추가됨 (selectedTracks push 순서 유지)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-04-23 17:25:42 +09:00
parent 18efd952c4
commit 9e87549ca3

View file

@ -1,7 +1,7 @@
import { useState, useMemo } from "react";
import { createPortal } from "react-dom";
import { motion, AnimatePresence } from "framer-motion";
import { X, Search, Music, Check, Disc3 } from "lucide-react";
import { X, Search, Music, Disc3 } from "lucide-react";
/**
* 검색 다이얼로그
@ -71,7 +71,14 @@ function SongSearchDialog({ isOpen, onClose, onSelect, albums }) {
});
};
const isSelected = (trackId) => selectedTracks.some((t) => t.id === trackId);
// (trackId )
const selectionOrder = useMemo(() => {
const m = new Map();
selectedTracks.forEach((t, i) => m.set(t.id, i + 1));
return m;
}, [selectedTracks]);
const isSelected = (trackId) => selectionOrder.has(trackId);
//
const handleConfirm = () => {
@ -169,41 +176,41 @@ function SongSearchDialog({ isOpen, onClose, onSelect, albums }) {
{/* 트랙 목록 */}
<div className="space-y-1">
{group.tracks.map((track) => (
<button
key={track.id}
type="button"
onClick={() => toggleTrack(track)}
className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-colors ${
isSelected(track.id)
? "bg-primary/10"
: "hover:bg-gray-50"
}`}
>
<div
className={`w-5 h-5 rounded border flex items-center justify-center flex-shrink-0 ${
isSelected(track.id)
? "bg-primary border-primary"
: "border-gray-300"
{group.tracks.map((track) => {
const order = selectionOrder.get(track.id);
const selected = order !== undefined;
return (
<button
key={track.id}
type="button"
onClick={() => toggleTrack(track)}
className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-colors ${
selected ? "bg-primary/10" : "hover:bg-gray-50"
}`}
>
{isSelected(track.id) && (
<Check size={12} className="text-white" />
)}
</div>
<span className="text-sm text-gray-400 w-5 text-right flex-shrink-0">
{track.trackNumber}
</span>
<span className="text-sm text-gray-900 flex-1 truncate">
{track.songName}
</span>
{!!track.isTitleTrack && (
<span className="text-[10px] px-1.5 py-0.5 bg-primary/10 text-primary rounded font-medium flex-shrink-0">
타이틀
<div
className={`w-5 h-5 rounded-full flex items-center justify-center flex-shrink-0 text-[11px] font-bold leading-none transition-colors ${
selected
? "bg-primary text-white"
: "border border-gray-300 text-transparent"
}`}
>
<span className="translate-y-[0.5px]">{order ?? ""}</span>
</div>
<span className="text-sm text-gray-400 w-5 text-right flex-shrink-0">
{track.trackNumber}
</span>
)}
</button>
))}
<span className="text-sm text-gray-900 flex-1 truncate">
{track.songName}
</span>
{!!track.isTitleTrack && (
<span className="text-[10px] px-1.5 py-0.5 bg-primary/10 text-primary rounded font-medium flex-shrink-0">
타이틀
</span>
)}
</button>
);
})}
</div>
</div>
))}