- Unified localStorage key to 'theme-preference' across all components
- Fixed header.tsx using wrong localStorage key ('theme' instead of 'theme-preference')
- Added localStorage hybrid persistence for instant theme changes
- Removed router.refresh() which was causing stale data revert
- Replaced Blue theme with Sepia
- Consolidated auth() calls to prevent race conditions
- Updated UserSettingsData types to include all themes
310 lines
9.5 KiB
Markdown
310 lines
9.5 KiB
Markdown
# Proposition de Simplification du Design - Keep App
|
|
|
|
**Date:** 2026-01-17
|
|
**Auteur:** Sally (UX Designer)
|
|
**Status:** Proposition finale
|
|
|
|
---
|
|
|
|
## 🎯 Objectif
|
|
|
|
Simplifier l'interface du NoteCard en réduisant le nombre de boutons visibles, tout en **PRÉSERVANT** tout le contenu existant.
|
|
|
|
---
|
|
|
|
## ✅ Ce qui NE CHANGE PAS
|
|
|
|
### 1. Avatar
|
|
- **Position:** Bas à gauche (`bottom-2 left-2`) - **AUCUN CHANGEMENT**
|
|
- **Taille:** 24x24px (w-6 h-6) - **AUCUN CHANGEMENT**
|
|
- **Style:** Cercle avec initiales - **AUCUN CHANGEMENT**
|
|
|
|
### 2. Images
|
|
- **Affichage:** Pleine largeur dans la note - **AUCUN CHANGEMENT**
|
|
- **Visibilité:** Toujours visible - **AUCUN CHANGEMENT**
|
|
- **Fonctionnalité:** Cliquable pour agrandir - **AUCUN CHANGEMENT**
|
|
|
|
### 3. Liens HTML
|
|
- **Prévisualisation:** Complète avec image, titre, description, hostname - **AUCUN CHANGEMENT**
|
|
- **Position:** Dans le contenu de la note - **AUCUN CHANGEMENT**
|
|
- **Style:** Bordure, fond, hover - **AUCUN CHANGEMENT**
|
|
|
|
### 4. Labels
|
|
- **Affichage:** Badges colorés - **AUCUN CHANGEMENT**
|
|
- **Position:** Sous le contenu - **AUCUN CHANGEMENT**
|
|
|
|
### 5. Date
|
|
- **Affichage:** "il y a X jours" - **AUCUN CHANGEMENT**
|
|
- **Position:** Bas à droite - **AUCUN CHANGEMENT**
|
|
|
|
### 6. Badges Memory Echo
|
|
- **Affichage:** En haut de la note - **AUCUN CHANGEMENT**
|
|
- **Style:** Badges violets - **AUCUN CHANGEMENT**
|
|
|
|
---
|
|
|
|
## 🔄 Ce qui CHANGE
|
|
|
|
### Problème Actuel
|
|
|
|
Le NoteCard affiche **5 boutons en haut** :
|
|
1. Drag handle (déplacer)
|
|
2. Move to notebook (déplacer vers un notebook)
|
|
3. Pin (épingler)
|
|
4. Reminder (rappel)
|
|
5. Connections (connexions)
|
|
|
|
**Problème:** Ces 5 boutons encombrent l'interface et prennent de la place.
|
|
|
|
### Solution Proposée
|
|
|
|
**Remplacer les 5 boutons par 1 seul menu "..."** qui contient toutes les actions.
|
|
|
|
---
|
|
|
|
## 📋 Détails de l'Implémentation
|
|
|
|
### Nouveau Composant : `NoteActionMenu`
|
|
|
|
```tsx
|
|
// keep-notes/components/note-action-menu.tsx
|
|
'use client'
|
|
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu'
|
|
import { MoreHorizontal, Pin, FolderOpen, Bell, Link2, Archive, Trash2, Share2, Palette } from 'lucide-react'
|
|
import { Note } from '@/lib/types'
|
|
|
|
interface NoteActionMenuProps {
|
|
note: Note
|
|
onTogglePin: () => void
|
|
onMoveToNotebook: (notebookId: string | null) => void
|
|
onSetReminder: () => void
|
|
onShowConnections: () => void
|
|
onArchive: () => void
|
|
onDelete: () => void
|
|
onShare: () => void
|
|
onColorChange: (color: string) => void
|
|
}
|
|
|
|
export function NoteActionMenu({
|
|
note,
|
|
onTogglePin,
|
|
onMoveToNotebook,
|
|
onSetReminder,
|
|
onShowConnections,
|
|
onArchive,
|
|
onDelete,
|
|
onShare,
|
|
onColorChange,
|
|
}: NoteActionMenuProps) {
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<button
|
|
className="absolute top-2 right-2 z-20 p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors opacity-0 group-hover:opacity-100"
|
|
title="Actions"
|
|
>
|
|
<MoreHorizontal className="w-5 h-5 text-gray-600 dark:text-gray-400" />
|
|
</button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-56">
|
|
{/* Pin / Unpin */}
|
|
<DropdownMenuItem onClick={onTogglePin}>
|
|
<Pin className={cn("h-4 w-4 mr-2", note.isPinned && "fill-current")} />
|
|
{note.isPinned ? 'Désépingler' : 'Épingler'}
|
|
</DropdownMenuItem>
|
|
|
|
{/* Move to notebook */}
|
|
<DropdownMenuItem onClick={() => onMoveToNotebook(null)}>
|
|
<FolderOpen className="h-4 w-4 mr-2" />
|
|
Déplacer vers...
|
|
</DropdownMenuItem>
|
|
|
|
{/* Reminder */}
|
|
<DropdownMenuItem onClick={onSetReminder}>
|
|
<Bell className="h-4 w-4 mr-2" />
|
|
Rappel
|
|
</DropdownMenuItem>
|
|
|
|
{/* Connections */}
|
|
<DropdownMenuItem onClick={onShowConnections}>
|
|
<Link2 className="h-4 w-4 mr-2" />
|
|
Connexions
|
|
</DropdownMenuItem>
|
|
|
|
{/* Divider */}
|
|
<div className="my-1 border-t border-gray-200 dark:border-gray-700" />
|
|
|
|
{/* Color */}
|
|
<DropdownMenuItem onClick={() => onColorChange('blue')}>
|
|
<Palette className="h-4 w-4 mr-2" />
|
|
Colorer
|
|
</DropdownMenuItem>
|
|
|
|
{/* Share */}
|
|
<DropdownMenuItem onClick={onShare}>
|
|
<Share2 className="h-4 w-4 mr-2" />
|
|
Partager
|
|
</DropdownMenuItem>
|
|
|
|
{/* Archive */}
|
|
<DropdownMenuItem onClick={onArchive}>
|
|
<Archive className="h-4 w-4 mr-2" />
|
|
Archiver
|
|
</DropdownMenuItem>
|
|
|
|
{/* Delete */}
|
|
<DropdownMenuItem onClick={onDelete} className="text-destructive">
|
|
<Trash2 className="h-4 w-4 mr-2" />
|
|
Supprimer
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Modification du NoteCard
|
|
|
|
**Avant (lignes 289-333):**
|
|
```tsx
|
|
{/* Drag Handle - Only visible on mobile/touch devices */}
|
|
<div className="muuri-drag-handle absolute top-2 left-2 z-20 cursor-grab active:cursor-grabbing p-2 md:hidden">
|
|
<GripVertical className="h-5 w-5 text-muted-foreground" />
|
|
</div>
|
|
|
|
{/* Move to Notebook Dropdown Menu */}
|
|
<div onClick={(e) => e.stopPropagation()} className="absolute top-2 right-2 z-20">
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" size="sm" className="h-8 w-8 p-0 bg-blue-100...">
|
|
<FolderOpen className="h-4 w-4" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
...
|
|
</DropdownMenu>
|
|
</div>
|
|
|
|
{/* Pin Button */}
|
|
<Button variant="ghost" size="sm" className="absolute top-2 right-12 z-20...">
|
|
<Pin className={...} />
|
|
</Button>
|
|
|
|
{/* Reminder Icon */}
|
|
{note.reminder && ... && (
|
|
<Bell className="absolute top-3 right-10 h-4 w-4 text-primary" />
|
|
)}
|
|
```
|
|
|
|
**Après:**
|
|
```tsx
|
|
{/* Drag Handle - Only visible on mobile/touch devices */}
|
|
<div className="muuri-drag-handle absolute top-2 left-2 z-20 cursor-grab active:cursor-grabbing p-2 md:hidden">
|
|
<GripVertical className="h-5 w-5 text-muted-foreground" />
|
|
</div>
|
|
|
|
{/* Action Menu - Remplace les 5 boutons */}
|
|
<NoteActionMenu
|
|
note={note}
|
|
onTogglePin={handleTogglePin}
|
|
onMoveToNotebook={handleMoveToNotebook}
|
|
onSetReminder={() => {/* Ouvrir le dialog de rappel - à implémenter */}}
|
|
onShowConnections={() => setShowConnectionsOverlay(true)}
|
|
onArchive={handleToggleArchive}
|
|
onDelete={handleDelete}
|
|
onShare={() => setShowCollaboratorDialog(true)}
|
|
onColorChange={handleColorChange}
|
|
/>
|
|
|
|
{/* Reminder Icon - Visible si rappel actif */}
|
|
{note.reminder && new Date(note.reminder) > new Date() && (
|
|
<Bell className="absolute top-3 right-10 h-4 w-4 text-primary" />
|
|
)}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Comparaison Visuelle
|
|
|
|
### Avant
|
|
```
|
|
┌─────────────────────────────────────┐
|
|
│ [🖱️] [📁] [📌] [🔔] [🔗] │ ← 5 boutons
|
|
│ │
|
|
│ [Badge Memory Echo] │
|
|
│ │
|
|
│ Title │
|
|
│ │
|
|
│ [Image] │
|
|
│ │
|
|
│ Content... │
|
|
│ │
|
|
│ [Link Preview HTML] │
|
|
│ │
|
|
│ [Labels] │
|
|
│ │
|
|
│ [👤] Avatar Date │ ← Avatar bas gauche
|
|
└─────────────────────────────────────┘
|
|
```
|
|
|
|
### Après
|
|
```
|
|
┌─────────────────────────────────────┐
|
|
│ [🖱️] [...] │ ← Drag + Menu
|
|
│ │
|
|
│ [Badge Memory Echo] │
|
|
│ │
|
|
│ Title │
|
|
│ │
|
|
│ [Image] │
|
|
│ │
|
|
│ Content... │
|
|
│ │
|
|
│ [Link Preview HTML] │
|
|
│ │
|
|
│ [Labels] │
|
|
│ │
|
|
│ [👤] Avatar Date │ ← Avatar bas gauche (identique)
|
|
└─────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Avantages
|
|
|
|
1. **Interface plus claire** : Moins de boutons visibles = moins d'encombrement
|
|
2. **Contenu préservé** : TOUT reste identique (avatar, images, liens, labels)
|
|
3. **Actions accessibles** : Menu contextuel au hover (desktop) ou tap (mobile)
|
|
4. **Cohérence** : Style similaire à Google Keep (menu "..." au lieu de multiples boutons)
|
|
|
|
---
|
|
|
|
## 📋 Checklist d'Implémentation
|
|
|
|
- [ ] Créer le composant `NoteActionMenu.tsx`
|
|
- [ ] Modifier `note-card.tsx` pour remplacer les 5 boutons par le menu
|
|
- [ ] Tester sur desktop (hover pour afficher le menu)
|
|
- [ ] Tester sur mobile (tap pour afficher le menu)
|
|
- [ ] Vérifier que l'avatar reste en bas à gauche
|
|
- [ ] Vérifier que les images restent visibles
|
|
- [ ] Vérifier que les liens HTML restent avec prévisualisation complète
|
|
- [ ] Vérifier que les labels restent visibles
|
|
- [ ] Vérifier que la date reste en bas à droite
|
|
|
|
---
|
|
|
|
## 🎯 Résumé
|
|
|
|
**Changement unique :** 5 boutons → 1 menu "..."
|
|
**Tout le reste :** Identique (avatar bas gauche, images, liens HTML, labels, date)
|
|
|
|
---
|
|
|
|
**Document créé le:** 2026-01-17
|
|
**Status:** Prêt pour implémentation
|