From 749f69680b50d2634bda195414ccd4a3ee121a69 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Mon, 29 Sep 2025 17:29:11 +0200 Subject: [PATCH] feat: integrate global keyboard shortcuts across multiple components - Added `KeyboardShortcutsProvider` to `RootLayout` for centralized keyboard shortcut management. - Implemented `useGlobalKeyboardShortcuts` in `DailyPageClient`, `KanbanPageClient`, and `HomePageClient` to enhance navigation and task management with keyboard shortcuts. - Updated `KeyboardShortcuts` component to render a modal for displaying available shortcuts, improving user accessibility. - Enhanced `Header` component with buttons to open the keyboard shortcuts modal, streamlining user interaction. --- src/app/daily/DailyPageClient.tsx | 8 + src/app/kanban/KanbanPageClient.tsx | 14 ++ src/app/layout.tsx | 15 +- src/components/HomePageClient.tsx | 15 ++ src/components/KeyboardShortcuts.tsx | 13 +- src/components/ui/Header.tsx | 20 ++ src/components/ui/KeyboardShortcutsModal.tsx | 96 +++++++++ src/contexts/KeyboardShortcutsContext.tsx | 210 +++++++++++++++++++ src/hooks/useGlobalKeyboardShortcuts.ts | 102 +++++++++ src/hooks/useKeyboardShortcuts.ts | 2 +- 10 files changed, 487 insertions(+), 8 deletions(-) create mode 100644 src/components/ui/KeyboardShortcutsModal.tsx create mode 100644 src/contexts/KeyboardShortcutsContext.tsx create mode 100644 src/hooks/useGlobalKeyboardShortcuts.ts diff --git a/src/app/daily/DailyPageClient.tsx b/src/app/daily/DailyPageClient.tsx index 8a9897e..f9ebf84 100644 --- a/src/app/daily/DailyPageClient.tsx +++ b/src/app/daily/DailyPageClient.tsx @@ -14,6 +14,7 @@ import { PendingTasksSection } from '@/components/daily/PendingTasksSection'; import { dailyClient } from '@/clients/daily-client'; import { Header } from '@/components/ui/Header'; import { getPreviousWorkday, formatDateLong, isToday, generateDateTitle, formatDateShort, isYesterday } from '@/lib/date-utils'; +import { useGlobalKeyboardShortcuts } from '@/hooks/useGlobalKeyboardShortcuts'; interface DailyPageClientProps { initialDailyView?: DailyView; @@ -85,6 +86,13 @@ export function DailyPageClient({ await refreshDailyDates(); }; + // Raccourcis clavier globaux pour la page Daily + useGlobalKeyboardShortcuts({ + onNavigatePrevious: goToPreviousDay, + onNavigateNext: goToNextDay, + onGoToToday: goToToday + }); + const handleToggleCheckbox = async (checkboxId: string) => { await toggleCheckbox(checkboxId); }; diff --git a/src/app/kanban/KanbanPageClient.tsx b/src/app/kanban/KanbanPageClient.tsx index f7432c0..c47413f 100644 --- a/src/app/kanban/KanbanPageClient.tsx +++ b/src/app/kanban/KanbanPageClient.tsx @@ -12,6 +12,7 @@ import { CreateTaskForm } from '@/components/forms/CreateTaskForm'; import { MobileControls } from '@/components/kanban/MobileControls'; import { DesktopControls } from '@/components/kanban/DesktopControls'; import { useIsMobile } from '@/hooks/useIsMobile'; +import { useGlobalKeyboardShortcuts } from '@/hooks/useGlobalKeyboardShortcuts'; interface KanbanPageClientProps { initialTasks: Task[]; @@ -55,6 +56,19 @@ function KanbanPageContent() { setIsCreateModalOpen(false); }; + // Raccourcis clavier globaux pour la page Kanban + useGlobalKeyboardShortcuts({ + onCreateTask: () => setIsCreateModalOpen(true), + onToggleFilters: handleToggleFilters, + onToggleCompactView: handleToggleCompactView, + onToggleSwimlanes: handleToggleSwimlanes, + onOpenSearch: () => { + // Focus sur le champ de recherche dans les contrôles desktop + const searchInput = document.querySelector('input[placeholder*="Rechercher"]') as HTMLInputElement; + searchInput?.focus(); + } + }); + return (
- - - - {children} - - + + + + + {children} + + + diff --git a/src/components/HomePageClient.tsx b/src/components/HomePageClient.tsx index 1eef6d9..ef4f1f5 100644 --- a/src/components/HomePageClient.tsx +++ b/src/components/HomePageClient.tsx @@ -10,6 +10,7 @@ import { RecentTasks } from '@/components/dashboard/RecentTasks'; import { ProductivityAnalytics } from '@/components/dashboard/ProductivityAnalytics'; import { ProductivityMetrics } from '@/services/analytics/analytics'; import { DeadlineMetrics } from '@/services/analytics/deadline-analytics'; +import { useGlobalKeyboardShortcuts } from '@/hooks/useGlobalKeyboardShortcuts'; interface HomePageClientProps { initialTasks: Task[]; @@ -31,6 +32,20 @@ function HomePageContent({ productivityMetrics, deadlineMetrics }: { await createTask(data); }; + // Raccourcis clavier globaux pour la page Dashboard + useGlobalKeyboardShortcuts({ + onOpenSearch: () => { + // Focus sur le champ de recherche s'il existe, sinon naviguer vers Kanban + const searchInput = document.querySelector('input[placeholder*="Rechercher"]') as HTMLInputElement; + if (searchInput) { + searchInput.focus(); + } else { + // Naviguer vers Kanban où il y a une recherche + window.location.href = '/kanban'; + } + } + }); + return (
+ ); } diff --git a/src/components/ui/Header.tsx b/src/components/ui/Header.tsx index e8b79c3..dc51842 100644 --- a/src/components/ui/Header.tsx +++ b/src/components/ui/Header.tsx @@ -7,6 +7,7 @@ import Link from 'next/link'; import { useState } from 'react'; import { Theme } from '@/lib/theme-config'; import { THEME_CONFIG, getThemeMetadata } from '@/lib/theme-config'; +import { useKeyboardShortcutsModal } from '@/contexts/KeyboardShortcutsContext'; interface HeaderProps { title?: string; @@ -20,6 +21,7 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s const pathname = usePathname(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [themeDropdownOpen, setThemeDropdownOpen] = useState(false); + const { openModal: openShortcutsModal } = useKeyboardShortcutsModal(); // Liste des thèmes disponibles avec leurs labels et icônes const themes: { value: Theme; label: string; icon: string }[] = THEME_CONFIG.allThemes.map(themeValue => { @@ -97,6 +99,15 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s {/* Controls mobile/tablette */}
+ {/* Keyboard Shortcuts */} + + {/* Theme Dropdown */}
+ {/* Theme Dropdown desktop */}