feat: add keyboard shortcuts and statistics dashboard

Keyboard Shortcuts:
- Create useKeyboardShortcuts hook with configurable shortcuts
- Support Ctrl/Cmd, Alt, Shift modifiers
- Add 7 global shortcuts (New note, Search, Quick capture, etc.)
- Create KeyboardShortcutsHelp modal with categorized shortcuts
- Show formatted shortcut keys (⌘ on Mac, Ctrl on Windows)
- Press ? to open shortcuts help

Statistics Dashboard:
- Create StatsDashboard component with productivity metrics
- Calculate productivity score (0-100) based on completion rate
- Show notes statistics (total, active, archived, priority)
- Display todos statistics with completion rate
- Track content stats (notes with todos/images/files, unique tags)
- Show recent activity (notes updated in last 7 days)
- Visual progress bar for productivity score
- Integrate dashboard in left column below calendar
This commit is contained in:
Claude committed 2025-11-27 19:43:26 +00:00
1 parent 1e9795e5d9
commit a3d8167a46
4 files changed
+454

No files matched your search

+81
View File
@@ -41,6 +41,9 @@ import { PomodoroTimer } from "@/components/PomodoroTimer";
import { KanbanBoard } from "@/components/KanbanBoard";
import { getSmartTagSuggestions } from "@/utils/smartTags";
import { QuickCaptureWidget } from "@/components/QuickCaptureWidget";
import { StatsDashboard } from "@/components/StatsDashboard";
import { KeyboardShortcutsHelp } from "@/components/KeyboardShortcutsHelp";
import { useKeyboardShortcuts, type KeyboardShortcut } from "@/hooks/useKeyboardShortcuts";
// ===== FONCTIONS UTILITAIRES TIMEZONE EUROPE/PARIS =====
@@ -170,6 +173,8 @@ const Index = () => {
const [selectedImage, setSelectedImage] = useState<string | null>(null);
const [addEventModal, setAddEventModal] = useState(false);
const [editEventModal, setEditEventModal] = useState<{ open: boolean, event?: CalendarEvent }>({ open: false });
const [showKeyboardHelp, setShowKeyboardHelp] = useState(false);
const [showStatsDashboard, setShowStatsDashboard] = useState(false);
// Pagination states
const [notesPage, setNotesPage] = useState(0);
@@ -934,6 +939,72 @@ const Index = () => {
setCalendarPage(0);
}, [calendarEvents.length]);
// Define keyboard shortcuts
const keyboardShortcuts: KeyboardShortcut[] = [
{
key: 'n',
ctrl: true,
description: 'Nouvelle note',
handler: () => !showAdmin && handleCreateNote()
},
{
key: 'k',
ctrl: true,
description: 'Rechercher',
handler: () => {
const searchInput = document.querySelector('input[type="search"]') as HTMLInputElement;
if (searchInput) searchInput.focus();
}
},
{
key: 'q',
ctrl: true,
description: 'Capture rapide',
handler: () => {
const captureButton = document.querySelector('[title="Capture rapide (Ctrl+Q)"]') as HTMLButtonElement;
if (captureButton) captureButton.click();
}
},
{
key: 'Escape',
description: 'Fermer note/modal',
handler: () => {
if (openNote) setOpenNote(null);
else if (showAdmin) setShowAdmin(false);
else if (showKeyboardHelp) setShowKeyboardHelp(false);
},
preventDefault: false
},
{
key: '?',
shift: true,
description: 'Aide raccourcis',
handler: () => setShowKeyboardHelp(true)
},
{
key: 'e',
ctrl: true,
description: 'Archiver note',
handler: async () => {
if (openNote?.id) {
await handleUpdateNote({ archived: !openNote.archived });
}
}
},
{
key: 's',
ctrl: true,
description: 'Sauvegarder (auto)',
handler: () => {
// Note: Auto-save is handled by the editor
showSuccess('Auto-save actif');
}
}
];
// Register keyboard shortcuts
useKeyboardShortcuts(keyboardShortcuts, !showAdmin);
// Pagination for todos
const activeTodos = todos.filter(t => !t.completed);
const completedTodos = todos.filter(t => t.completed);
@@ -1191,6 +1262,9 @@ const Index = () => {
)}
</CardContent>
</Card>
{/* Statistics Dashboard */}
<StatsDashboard notes={notes} todos={todos} />
</div>
{/* Middle Column: Notes or Open Note */}
@@ -3068,6 +3142,13 @@ const Index = () => {
</div>
)}
{/* Keyboard Shortcuts Help Modal */}
<KeyboardShortcutsHelp
open={showKeyboardHelp}
onOpenChange={setShowKeyboardHelp}
shortcuts={keyboardShortcuts}
/>
{/* Quick Capture Widget */}
<QuickCaptureWidget onNoteCaptured={loadNotes} />
</div>