2026-01-22 09:23:24 +09:00
|
|
|
import { motion } from 'framer-motion';
|
|
|
|
|
import { useQuery } from '@tanstack/react-query';
|
|
|
|
|
import { useNavigate } from 'react-router-dom';
|
2026-01-22 18:37:30 +09:00
|
|
|
import { getAlbums } from '@/api';
|
2026-01-22 09:23:24 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Mobile 앨범 목록 페이지
|
|
|
|
|
*/
|
|
|
|
|
function MobileAlbum() {
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
|
|
|
|
|
const { data: albums = [], isLoading: loading } = useQuery({
|
|
|
|
|
queryKey: ['albums'],
|
|
|
|
|
queryFn: getAlbums,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center justify-center h-64">
|
|
|
|
|
<div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin" />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="px-4 py-4">
|
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
|
|
{albums.map((album, index) => (
|
|
|
|
|
<motion.div
|
|
|
|
|
key={album.id}
|
|
|
|
|
initial={{ opacity: 0, y: 20 }}
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
transition={{ delay: index * 0.05 }}
|
|
|
|
|
onClick={() => navigate(`/album/${encodeURIComponent(album.title)}`)}
|
|
|
|
|
className="bg-white rounded-2xl overflow-hidden shadow-md"
|
|
|
|
|
>
|
|
|
|
|
<div className="aspect-square bg-gray-200">
|
|
|
|
|
{album.cover_thumb_url && (
|
|
|
|
|
<img
|
|
|
|
|
src={album.cover_thumb_url}
|
|
|
|
|
alt={album.title}
|
|
|
|
|
className="w-full h-full object-cover"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="p-3">
|
|
|
|
|
<p className="font-semibold text-sm truncate">{album.title}</p>
|
|
|
|
|
<p className="text-xs text-gray-400 mt-0.5">
|
|
|
|
|
{album.album_type_short} · {album.release_date?.slice(0, 4)}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</motion.div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default MobileAlbum;
|