Files
lidify/frontend/features/home/components/FeaturedPlaylistsGrid.tsx
2025-12-25 18:58:06 -06:00

105 lines
4.0 KiB
TypeScript

"use client";
import { Music2 } from "lucide-react";
import { useRouter } from "next/navigation";
import { HorizontalCarousel, CarouselItem } from "@/components/ui/HorizontalCarousel";
import { memo } from "react";
interface PlaylistPreview {
id: string;
source: string;
type: string;
title: string;
description: string | null;
creator: string;
imageUrl: string | null;
trackCount: number;
url: string;
}
interface FeaturedPlaylistsGridProps {
playlists: PlaylistPreview[];
}
// Deezer icon
const DeezerIcon = ({ className }: { className?: string }) => (
<svg viewBox="0 0 24 24" className={className} fill="currentColor">
<path d="M18.81 4.16v3.03H24V4.16h-5.19zM6.27 8.38v3.027h5.189V8.38h-5.19zm12.54 0v3.027H24V8.38h-5.19zM6.27 12.595v3.027h5.189v-3.027h-5.19zm6.27 0v3.027h5.19v-3.027h-5.19zm6.27 0v3.027H24v-3.027h-5.19zM0 16.81v3.029h5.19v-3.03H0zm6.27 0v3.029h5.189v-3.03h-5.19zm6.27 0v3.029h5.19v-3.03h-5.19zm6.27 0v3.029H24v-3.03h-5.19z" />
</svg>
);
interface PlaylistCardProps {
playlist: PlaylistPreview;
onClick: () => void;
}
const PlaylistCard = memo(function PlaylistCard({
playlist,
onClick
}: PlaylistCardProps) {
return (
<CarouselItem>
<div
onClick={onClick}
className="p-3 rounded-md group cursor-pointer hover:bg-white/5 transition-colors"
>
<div className="relative aspect-square mb-3 rounded-md overflow-hidden bg-[#282828] shadow-lg">
{playlist.imageUrl ? (
<img
src={playlist.imageUrl}
alt={playlist.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
/>
) : (
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-[#AD47FF]/30 to-[#AD47FF]/10">
<Music2 className="w-10 h-10 text-gray-600" />
</div>
)}
{/* Play button on hover */}
<div className="absolute bottom-2 right-2 opacity-0 group-hover:opacity-100 translate-y-2 group-hover:translate-y-0 transition-all duration-200">
<div className="w-10 h-10 rounded-full bg-[#ecb200] flex items-center justify-center shadow-xl hover:scale-105 transition-transform">
<svg viewBox="0 0 24 24" className="w-4 h-4 text-black ml-0.5" fill="currentColor">
<path d="M8 5v14l11-7z" />
</svg>
</div>
</div>
{/* Deezer badge */}
<div className="absolute top-2 left-2">
<DeezerIcon className="w-4 h-4 text-[#AD47FF] drop-shadow-lg" />
</div>
</div>
<h3 className="text-sm font-semibold text-white truncate">
{playlist.title}
</h3>
<p className="text-xs text-gray-400 mt-0.5">
{playlist.trackCount} songs
</p>
</div>
</CarouselItem>
);
});
export function FeaturedPlaylistsGrid({ playlists }: FeaturedPlaylistsGridProps) {
const router = useRouter();
const handlePlaylistClick = (playlist: PlaylistPreview) => {
router.push(`/browse/playlists/${playlist.id}`);
};
if (!playlists || playlists.length === 0) {
return null;
}
return (
<HorizontalCarousel>
{playlists.slice(0, 20).map((playlist, index) => (
<PlaylistCard
key={`home-playlist-${playlist.id}-${index}`}
playlist={playlist}
onClick={() => handlePlaylistClick(playlist)}
/>
))}
</HorizontalCarousel>
);
}