|
|
@@ -17,7 +17,8 @@ import {
|
|
|
ChevronDown,
|
|
|
ChevronRight,
|
|
|
BookOpen,
|
|
|
- Trash2
|
|
|
+ Trash2,
|
|
|
+ ArrowRight
|
|
|
} from 'lucide-react';
|
|
|
import { useAuth } from '@/hooks/useAuth';
|
|
|
import { NewsItem } from '@/types/news';
|
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
AlertDialogTrigger,
|
|
|
} from '@/components/ui/alert-dialog';
|
|
|
import { useState } from 'react';
|
|
|
+import { Link } from 'react-router-dom';
|
|
|
|
|
|
interface CategoryFilterProps {
|
|
|
categories: NewsCategory[];
|
|
|
@@ -256,106 +258,111 @@ const CategoryFilter = ({
|
|
|
Aucun article épinglé
|
|
|
</div>
|
|
|
) : (
|
|
|
- <ScrollArea className="max-h-96">
|
|
|
- <div className="space-y-2 pr-2">
|
|
|
- {pinnedArticles.slice(0, 10).map((article) => (
|
|
|
- <div
|
|
|
- key={article.id}
|
|
|
- className="border rounded-lg p-3 bg-card hover:bg-muted/50 transition-colors"
|
|
|
- >
|
|
|
- <div className="flex items-start gap-2">
|
|
|
- <div
|
|
|
- className="flex-1 min-w-0 cursor-pointer"
|
|
|
- onClick={() => onOpenArticle?.(article)}
|
|
|
- >
|
|
|
- <h4 className="text-sm font-medium line-clamp-2 mb-1 hover:text-primary transition-colors">
|
|
|
- {article.title}
|
|
|
- </h4>
|
|
|
- <div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
|
- <span>{article.source}</span>
|
|
|
- <span>•</span>
|
|
|
- <span>{new Date(article.publishedAt).toLocaleDateString('fr-FR')}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className="flex items-center gap-1">
|
|
|
- {!article.isRead && onMarkAsRead && (
|
|
|
- <AlertDialog>
|
|
|
- <AlertDialogTrigger asChild>
|
|
|
- <Button
|
|
|
- variant="ghost"
|
|
|
- size="sm"
|
|
|
- className="h-7 w-7 p-0"
|
|
|
- title="Marquer comme lu"
|
|
|
- >
|
|
|
- <BookOpen className="h-3 w-3" />
|
|
|
- </Button>
|
|
|
- </AlertDialogTrigger>
|
|
|
- <AlertDialogContent>
|
|
|
- <AlertDialogHeader>
|
|
|
- <AlertDialogTitle>Marquer comme lu</AlertDialogTitle>
|
|
|
- <AlertDialogDescription>
|
|
|
- Êtes-vous sûr de vouloir marquer cet article comme lu ?
|
|
|
- </AlertDialogDescription>
|
|
|
- </AlertDialogHeader>
|
|
|
- <AlertDialogFooter>
|
|
|
- <AlertDialogCancel>Annuler</AlertDialogCancel>
|
|
|
- <AlertDialogAction onClick={() => onMarkAsRead(article.id)}>
|
|
|
- Marquer comme lu
|
|
|
- </AlertDialogAction>
|
|
|
- </AlertDialogFooter>
|
|
|
- </AlertDialogContent>
|
|
|
- </AlertDialog>
|
|
|
- )}
|
|
|
- {onTogglePin && (
|
|
|
- <AlertDialog>
|
|
|
- <AlertDialogTrigger asChild>
|
|
|
- <Button
|
|
|
- variant="ghost"
|
|
|
- size="sm"
|
|
|
- className="h-7 w-7 p-0"
|
|
|
- title="Désépingler"
|
|
|
- >
|
|
|
- <Pin className="h-3 w-3 fill-current" />
|
|
|
- </Button>
|
|
|
- </AlertDialogTrigger>
|
|
|
- <AlertDialogContent>
|
|
|
- <AlertDialogHeader>
|
|
|
- <AlertDialogTitle>Désépingler l'article</AlertDialogTitle>
|
|
|
- <AlertDialogDescription>
|
|
|
- Êtes-vous sûr de vouloir désépingler cet article ?
|
|
|
- </AlertDialogDescription>
|
|
|
- </AlertDialogHeader>
|
|
|
- <AlertDialogFooter>
|
|
|
- <AlertDialogCancel>Annuler</AlertDialogCancel>
|
|
|
- <AlertDialogAction onClick={() => onTogglePin(article.id)}>
|
|
|
- Désépingler
|
|
|
- </AlertDialogAction>
|
|
|
- </AlertDialogFooter>
|
|
|
- </AlertDialogContent>
|
|
|
- </AlertDialog>
|
|
|
- )}
|
|
|
- {onDeleteArticle && (
|
|
|
- <Button
|
|
|
- variant="ghost"
|
|
|
- size="sm"
|
|
|
- className="h-7 w-7 p-0 text-destructive hover:text-destructive"
|
|
|
- onClick={() => onDeleteArticle(article.id)}
|
|
|
- title="Supprimer"
|
|
|
- >
|
|
|
- <Trash2 className="h-3 w-3" />
|
|
|
- </Button>
|
|
|
- )}
|
|
|
+ <div className="space-y-2">
|
|
|
+ {pinnedArticles.slice(0, 3).map((article) => (
|
|
|
+ <div
|
|
|
+ key={article.id}
|
|
|
+ className="border rounded-lg p-3 bg-card hover:bg-muted/50 transition-colors"
|
|
|
+ >
|
|
|
+ <div className="flex items-start gap-2">
|
|
|
+ <div
|
|
|
+ className="flex-1 min-w-0 cursor-pointer"
|
|
|
+ onClick={() => onOpenArticle?.(article)}
|
|
|
+ >
|
|
|
+ <h4 className="text-sm font-medium line-clamp-2 mb-1 hover:text-primary transition-colors">
|
|
|
+ {article.title}
|
|
|
+ </h4>
|
|
|
+ <div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
|
+ <span>{article.source}</span>
|
|
|
+ <span>•</span>
|
|
|
+ <span>{new Date(article.publishedAt).toLocaleDateString('fr-FR')}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div className="flex items-center gap-1">
|
|
|
+ {!article.isRead && onMarkAsRead && (
|
|
|
+ <AlertDialog>
|
|
|
+ <AlertDialogTrigger asChild>
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ className="h-7 w-7 p-0"
|
|
|
+ title="Marquer comme lu"
|
|
|
+ >
|
|
|
+ <BookOpen className="h-3 w-3" />
|
|
|
+ </Button>
|
|
|
+ </AlertDialogTrigger>
|
|
|
+ <AlertDialogContent>
|
|
|
+ <AlertDialogHeader>
|
|
|
+ <AlertDialogTitle>Marquer comme lu</AlertDialogTitle>
|
|
|
+ <AlertDialogDescription>
|
|
|
+ Êtes-vous sûr de vouloir marquer cet article comme lu ?
|
|
|
+ </AlertDialogDescription>
|
|
|
+ </AlertDialogHeader>
|
|
|
+ <AlertDialogFooter>
|
|
|
+ <AlertDialogCancel>Annuler</AlertDialogCancel>
|
|
|
+ <AlertDialogAction onClick={() => onMarkAsRead(article.id)}>
|
|
|
+ Marquer comme lu
|
|
|
+ </AlertDialogAction>
|
|
|
+ </AlertDialogFooter>
|
|
|
+ </AlertDialogContent>
|
|
|
+ </AlertDialog>
|
|
|
+ )}
|
|
|
+ {onTogglePin && (
|
|
|
+ <AlertDialog>
|
|
|
+ <AlertDialogTrigger asChild>
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ className="h-7 w-7 p-0"
|
|
|
+ title="Désépingler"
|
|
|
+ >
|
|
|
+ <Pin className="h-3 w-3 fill-current" />
|
|
|
+ </Button>
|
|
|
+ </AlertDialogTrigger>
|
|
|
+ <AlertDialogContent>
|
|
|
+ <AlertDialogHeader>
|
|
|
+ <AlertDialogTitle>Désépingler l'article</AlertDialogTitle>
|
|
|
+ <AlertDialogDescription>
|
|
|
+ Êtes-vous sûr de vouloir désépingler cet article ?
|
|
|
+ </AlertDialogDescription>
|
|
|
+ </AlertDialogHeader>
|
|
|
+ <AlertDialogFooter>
|
|
|
+ <AlertDialogCancel>Annuler</AlertDialogCancel>
|
|
|
+ <AlertDialogAction onClick={() => onTogglePin(article.id)}>
|
|
|
+ Désépingler
|
|
|
+ </AlertDialogAction>
|
|
|
+ </AlertDialogFooter>
|
|
|
+ </AlertDialogContent>
|
|
|
+ </AlertDialog>
|
|
|
+ )}
|
|
|
+ {onDeleteArticle && (
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ className="h-7 w-7 p-0 text-destructive hover:text-destructive"
|
|
|
+ onClick={() => onDeleteArticle(article.id)}
|
|
|
+ title="Supprimer"
|
|
|
+ >
|
|
|
+ <Trash2 className="h-3 w-3" />
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- ))}
|
|
|
- {pinnedArticles.length > 10 && (
|
|
|
- <div className="text-center py-2 text-xs text-muted-foreground">
|
|
|
- +{pinnedArticles.length - 10} articles supplémentaires
|
|
|
- </div>
|
|
|
- )}
|
|
|
- </div>
|
|
|
- </ScrollArea>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ {pinnedArticles.length > 3 && (
|
|
|
+ <Link to="/pinned">
|
|
|
+ <Button
|
|
|
+ variant="outline"
|
|
|
+ className="w-full gap-2 mt-2"
|
|
|
+ size="sm"
|
|
|
+ >
|
|
|
+ Voir tous les articles épinglés ({pinnedArticles.length})
|
|
|
+ <ArrowRight className="h-3 w-3" />
|
|
|
+ </Button>
|
|
|
+ </Link>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
)}
|
|
|
</CollapsibleContent>
|
|
|
</Collapsible>
|