mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-18 04:39:18 +02:00
Feature: Affichage tags et icône priorité dans les cartes notes
Ajout de deux nouvelles fonctionnalités pour les notes: 1. Affichage des tags dans les cartes repliées: - Les tags sont maintenant visibles dans les cartes de notes sans avoir à les ouvrir - Badge avec icône TagIcon et nom du tag - Chargement automatique des tags depuis la base de données 2. Icône de priorité cliquable: - Bouton "!" en haut à droite de chaque carte de note - Rouge (!) quand la note est prioritaire (toujours visible) - Gris clair (!) quand non prioritaire (visible au hover) - Toggle au clic pour marquer/démarquer comme prioritaire - Les notes prioritaires sont triées en premier Backend: - Route PATCH /api/notes/:id/priority pour toggle la priorité - Modification GET /api/notes pour charger tags et priority - Tri par priority DESC, updated_at DESC - Migration automatique pour ajouter colonne priority - Index pour performance des requêtes de tri Frontend: - Interface Note étendue avec tags et priority - Méthode togglePriority dans NotesService - Affichage conditionnel de l'icône (toujours visible si prioritaire) - Empêche le clic sur l'icône d'ouvrir la note (stopPropagation) Migration: - Ajout automatique de la colonne priority (INTEGER DEFAULT 0) - Création d'index idx_notes_priority pour performance - Fichier de migration 002_add_priority.sql créé pour référence
This commit is contained in:
5 files changed
+119
-7
No files matched your search
+33
-2
@@ -944,11 +944,34 @@ const Index = () => {
|
||||
paginatedNotes.map(note => (
|
||||
<Card
|
||||
key={note.id}
|
||||
className="cursor-pointer hover:shadow-md transition-all group"
|
||||
className="cursor-pointer hover:shadow-md transition-all group relative"
|
||||
onClick={() => handleOpenNote(note)}
|
||||
>
|
||||
<CardContent className="p-4">
|
||||
<h3 className="font-semibold text-base mb-2 line-clamp-1">
|
||||
{/* Priority icon */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className={`absolute top-2 right-2 h-6 w-6 transition-opacity ${
|
||||
note.priority ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
|
||||
}`}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
const newPriority = !note.priority;
|
||||
if (note.id) {
|
||||
NotesService.togglePriority(note.id, newPriority);
|
||||
setNotes(notes.map(n => n.id === note.id ? { ...n, priority: newPriority } : n));
|
||||
}
|
||||
}}
|
||||
>
|
||||
{note.priority ? (
|
||||
<span className="text-red-500 text-lg font-bold">!</span>
|
||||
) : (
|
||||
<span className="text-muted-foreground text-lg">!</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<h3 className="font-semibold text-base mb-2 line-clamp-1 pr-8">
|
||||
{note.title || "Sans titre"}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground line-clamp-2 mb-3">
|
||||
@@ -973,6 +996,14 @@ const Index = () => {
|
||||
{note.files.length}
|
||||
</Badge>
|
||||
)}
|
||||
{note.tags && note.tags.length > 0 && (
|
||||
note.tags.map((tag) => (
|
||||
<Badge key={tag.id} variant="outline" className="text-xs">
|
||||
<TagIcon className="h-3 w-3 mr-1" />
|
||||
{tag.name}
|
||||
</Badge>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
{note.updated_at && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
|
||||
@@ -31,6 +31,8 @@ export interface Note {
|
||||
todos: Todo[];
|
||||
images: Image[];
|
||||
files?: NoteFile[];
|
||||
tags?: Array<{ id: number; name: string }>;
|
||||
priority?: boolean;
|
||||
}
|
||||
|
||||
class NotesService {
|
||||
@@ -158,11 +160,30 @@ class NotesService {
|
||||
method: "DELETE",
|
||||
headers: AuthService.getHeaders()
|
||||
});
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de la suppression de l'image");
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : "Erreur serveur");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async togglePriority(noteId: number, priority: boolean): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`/api/notes/${noteId}/priority`, {
|
||||
method: "PATCH",
|
||||
headers: AuthService.getHeaders(),
|
||||
body: JSON.stringify({ priority })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de la mise à jour de la priorité");
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : "Erreur serveur");
|
||||
|
||||
Reference in new issue
Block a user