- Replace cyan/magenta/purple gradients with primary/secondary - duration-200/300 → duration-[var(--duration-normal)] - Textarea: min-h-[100px] → min-h-24 - SearchPageHeader, DashboardPage, PlaylistHeader - UserProfilePageHeader/Hero, PlaylistDetailPageHero - SocialViewFeedItem, WishlistView, PostCard, ProductCard, CourseCard - SearchPageResults, MarketplaceHome Co-authored-by: Cursor <cursoragent@cursor.com>
129 lines
4.6 KiB
TypeScript
129 lines
4.6 KiB
TypeScript
/**
|
|
* Composant PlaylistHeader
|
|
* T0460: Create Playlist Detail Page
|
|
*/
|
|
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import { Music, Lock, Users, Calendar, User } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
import type { Playlist } from '../types';
|
|
import { PlaylistFollowButton } from './PlaylistFollowButton';
|
|
|
|
interface PlaylistHeaderProps {
|
|
playlist: Playlist;
|
|
className?: string;
|
|
}
|
|
|
|
const formatDate = (dateString: string): string => {
|
|
const date = new Date(dateString);
|
|
return date.toLocaleDateString('fr-FR', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
});
|
|
};
|
|
|
|
export function PlaylistHeader({ playlist, className }: PlaylistHeaderProps) {
|
|
return (
|
|
<Card
|
|
className={cn('mb-6', className)}
|
|
role="region"
|
|
aria-label={`Détails de la playlist ${playlist.title}`}
|
|
>
|
|
<CardContent className="p-4 sm:p-6">
|
|
<div className="flex flex-col md:flex-row gap-4 sm:gap-6">
|
|
{/* Cover Image - Mobile optimized */}
|
|
<div className="relative w-full md:w-64 h-48 sm:h-64 flex-shrink-0 rounded-lg overflow-hidden bg-gradient-to-br from-primary/40 to-secondary/40">
|
|
{playlist.cover_url ? (
|
|
<img
|
|
src={playlist.cover_url}
|
|
alt={`Couverture de la playlist ${playlist.title}`}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div
|
|
className="w-full h-full flex items-center justify-center"
|
|
role="img"
|
|
aria-label={`Pas de couverture pour la playlist ${playlist.title}`}
|
|
>
|
|
<Music className="w-24 h-24 text-white/50" aria-hidden="true" />
|
|
</div>
|
|
)}
|
|
{/* Visibility Badge */}
|
|
<div className="absolute top-3 right-3">
|
|
{playlist.is_public ? (
|
|
<div
|
|
className="bg-kodo-lime/100/90 text-white px-4 py-1.5 rounded-full text-sm flex items-center gap-2"
|
|
aria-label="Playlist publique"
|
|
>
|
|
<Users className="w-4 h-4" aria-hidden="true" />
|
|
Public
|
|
</div>
|
|
) : (
|
|
<div
|
|
className="bg-muted/90 text-white px-4 py-1.5 rounded-full text-sm flex items-center gap-2"
|
|
aria-label="Playlist privée"
|
|
>
|
|
<Lock className="w-4 h-4" aria-hidden="true" />
|
|
Privé
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Playlist Info - Mobile optimized */}
|
|
<div className="flex-1 space-y-4 sm:space-y-4">
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="flex-1">
|
|
<h1
|
|
className="text-2xl sm:text-3xl font-bold mb-2"
|
|
id="playlist-main-title"
|
|
>
|
|
{playlist.title}
|
|
</h1>
|
|
{playlist.description && (
|
|
<p
|
|
className="text-muted-foreground text-base sm:text-lg"
|
|
id="playlist-main-description"
|
|
>
|
|
{playlist.description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
<PlaylistFollowButton
|
|
playlistId={playlist.id}
|
|
initialFollowerCount={(playlist as any).follower_count}
|
|
initialFollowing={(playlist as any).is_following}
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
className="flex flex-wrap gap-4 sm:gap-4 text-xs sm:text-sm text-muted-foreground"
|
|
aria-labelledby="playlist-main-title"
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
<Music className="w-4 h-4" aria-hidden="true" />
|
|
<span>
|
|
{playlist.track_count} track
|
|
{playlist.track_count !== 1 ? 's' : ''}
|
|
</span>
|
|
</div>
|
|
{playlist.user && (
|
|
<div className="flex items-center gap-2">
|
|
<User className="w-4 h-4" aria-hidden="true" />
|
|
<span aria-label={`Créée par ${playlist.user.username}`}>
|
|
par {playlist.user.username}
|
|
</span>
|
|
</div>
|
|
)}
|
|
<div className="flex items-center gap-2">
|
|
<Calendar className="w-4 h-4" aria-hidden="true" />
|
|
<span>Créée le {formatDate(playlist.created_at)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|