Changeset 1579b4f for frontend/src/components/search
- Timestamp:
- 02/10/26 21:58:39 (5 months ago)
- Branches:
- main
- Children:
- 92db381
- Parents:
- 0808ef2
- File:
-
- 1 edited
-
frontend/src/components/search/SongResult.tsx (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/components/search/SongResult.tsx
r0808ef2 r1579b4f 1 import { useNavigate } from "react-router-dom"; 2 import { usePlayer } from "../../context/playerContext"; 1 import axiosInstance from "../../api/axiosInstance"; 3 2 import type { Song } from "../../utils/types"; 3 import SongItem from "../SongItem"; 4 4 5 5 interface SongResultProps { 6 6 song: Song; 7 /** Propagate like state change upward if needed */ 8 onLikeToggled?: (songId: number, isLiked: boolean) => void; 7 9 } 8 10 9 const toEmbedUrl = (url: string): string=> {10 try{11 const parsed = new URL(url);12 if(13 (parsed.hostname === "www.youtube.com" ||14 parsed.hostname === "youtube.com") &&15 parsed.searchParams.has("v")16 ) {17 return `https://www.youtube.com/embed/${parsed.searchParams.get("v")}`;11 const SongResult = ({ song, onLikeToggled }: SongResultProps) => { 12 const handleLike = async (songId: number) => { 13 try { 14 const response = await axiosInstance.post( 15 `/musical-entity/${songId}/like`, 16 ); 17 onLikeToggled?.(songId, response.data.isLiked); 18 } catch (err) { 19 console.error("Error toggling like:", err); 18 20 } 19 if (parsed.hostname === "youtu.be") { 20 return `https://www.youtube.com/embed${parsed.pathname}`; 21 } 22 return url; 23 } catch { 24 return url; 25 } 26 }; 21 }; 27 22 28 const SongResult = ({ song }: SongResultProps) => { 29 const navigate = useNavigate(); 30 const { play, currentSong } = usePlayer(); 31 32 return ( 33 <div 34 onClick={() => navigate(`/songs/${song.id}`)} 35 className="flex items-center gap-4 p-3 rounded-lg hover:bg-white/5 cursor-pointer transition-colors group" 36 > 37 <img 38 src={song.cover || "/favicon.png"} 39 alt={song.title} 40 className="w-12 h-12 rounded object-cover" 41 onError={(e) => { 42 (e.target as HTMLImageElement).src = "/favicon.png"; 43 }} 44 /> 45 <div className="flex-1 min-w-0"> 46 <p className="text-white font-medium truncate">{song.title}</p> 47 <p className="text-sm text-gray-400 truncate"> 48 Song • {song.releasedBy} 49 </p> 50 </div> 51 <span className="text-xs text-gray-500 uppercase tracking-wider mr-2"> 52 {song.genre} 53 </span> 54 {song.link && ( 55 <button 56 onClick={(e) => { 57 e.stopPropagation(); 58 play({ 59 id: song.id, 60 title: song.title, 61 artist: song.releasedBy, 62 cover: song.cover, 63 embedUrl: toEmbedUrl(song.link!), 64 }); 65 }} 66 className={`p-2 rounded-full transition-all opacity-0 group-hover:opacity-100 ${ 67 currentSong?.id === song.id 68 ? "bg-white text-[#1db954]" 69 : "bg-[#1db954] text-black hover:scale-110" 70 }`} 71 aria-label={currentSong?.id === song.id ? "Now playing" : "Play song"} 72 > 73 {currentSong?.id === song.id ? ( 74 <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> 75 <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" /> 76 </svg> 77 ) : ( 78 <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> 79 <path d="M8 5v14l11-7z" /> 80 </svg> 81 )} 82 </button> 83 )} 84 </div> 85 ); 23 return <SongItem song={song} label="Song" onLikeToggle={handleLike} />; 86 24 }; 87 25
Note:
See TracChangeset
for help on using the changeset viewer.
