mirror of
https://github.com/wahyd4/you-music.git
synced 2026-08-09 05:06:44 +10:00
Update
This commit is contained in:
@@ -77,15 +77,19 @@ export default function ArtistDetailPage({ onPlayMusic }: ArtistDetailProps) {
|
||||
</Button>
|
||||
|
||||
<div className="flex items-end gap-6">
|
||||
{artistInfo?.image && (
|
||||
<div className="hidden md:block">
|
||||
<div className="hidden md:block">
|
||||
{artistInfo?.image ? (
|
||||
<img
|
||||
src={artistInfo.image}
|
||||
src={artistInfo.image.startsWith('http') ? artistInfo.image : `/${artistInfo.image}`}
|
||||
alt={decodedArtistName}
|
||||
className="w-48 h-48 rounded-lg shadow-2xl object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
) : (
|
||||
<div className="w-48 h-48 rounded-lg bg-gradient-to-br from-white/20 to-white/5 backdrop-blur-sm shadow-2xl flex items-center justify-center">
|
||||
<Music2 className="h-20 w-20 text-white/80" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 text-white">
|
||||
<p className="text-sm font-medium mb-2 opacity-90">Artist</p>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { artistApi } from '@/api/client'
|
||||
import { Artist } from '@/types'
|
||||
import { Artist, ArtistInfo } from '@/types'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Music2, Loader2 } from 'lucide-react'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export default function ArtistsPage() {
|
||||
const navigate = useNavigate()
|
||||
const [artistsWithImages, setArtistsWithImages] = useState<Map<string, string>>(new Map())
|
||||
|
||||
const { data: artists, isLoading } = useQuery({
|
||||
queryKey: ['artists'],
|
||||
@@ -15,6 +17,33 @@ export default function ArtistsPage() {
|
||||
},
|
||||
})
|
||||
|
||||
// Fetch artist images
|
||||
useEffect(() => {
|
||||
if (!artists) return
|
||||
|
||||
const fetchArtistImages = async () => {
|
||||
const imageMap = new Map<string, string>()
|
||||
|
||||
// Fetch images for all artists in parallel
|
||||
const promises = artists.map(async (artist) => {
|
||||
try {
|
||||
const response = await artistApi.getArtistInfo(artist.name)
|
||||
const info = response.data as ArtistInfo
|
||||
if (info.image) {
|
||||
imageMap.set(artist.name, info.image)
|
||||
}
|
||||
} catch (error) {
|
||||
// Silently fail for individual artists
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
setArtistsWithImages(imageMap)
|
||||
}
|
||||
|
||||
fetchArtistImages()
|
||||
}, [artists])
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="max-w-screen-xl mx-auto p-4">
|
||||
@@ -30,26 +59,36 @@ export default function ArtistsPage() {
|
||||
<h2 className="text-2xl font-bold mb-6">Artists</h2>
|
||||
|
||||
{artists && artists.length > 0 ? (
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
||||
{artists.map((artist) => (
|
||||
<button
|
||||
key={artist.name}
|
||||
onClick={() => navigate(`/artists/${encodeURIComponent(artist.name)}`)}
|
||||
className="p-4 rounded-lg bg-card hover:bg-accent transition-colors text-left"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<div className="w-12 h-12 rounded-full bg-primary/10 flex items-center justify-center">
|
||||
<Music2 className="h-6 w-6 text-primary" />
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
|
||||
{artists.map((artist) => {
|
||||
const artistImage = artistsWithImages.get(artist.name)
|
||||
|
||||
return (
|
||||
<button
|
||||
key={artist.name}
|
||||
onClick={() => navigate(`/artists/${encodeURIComponent(artist.name)}`)}
|
||||
className="group p-4 rounded-lg bg-card hover:bg-accent transition-all text-center"
|
||||
>
|
||||
<div className="mb-3">
|
||||
{artistImage ? (
|
||||
<img
|
||||
src={artistImage.startsWith('http') ? artistImage : `/${artistImage}`}
|
||||
alt={artist.name}
|
||||
className="w-32 h-32 mx-auto rounded-full object-cover shadow-lg group-hover:shadow-xl transition-shadow"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-32 h-32 mx-auto rounded-full bg-gradient-to-br from-primary/20 to-primary/5 flex items-center justify-center">
|
||||
<Music2 className="h-12 w-12 text-primary" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold truncate">{artist.name}</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{artist.song_count} {artist.song_count === 1 ? 'song' : 'songs'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
<h3 className="font-semibold truncate mb-1">{artist.name}</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{artist.song_count} {artist.song_count === 1 ? 'song' : 'songs'}
|
||||
</p>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-12">
|
||||
|
||||
Reference in New Issue
Block a user