feat: add notes feature and keyboard shortcuts
- Introduced a new Note model in the Prisma schema to support note-taking functionality. - Updated the HeaderNavigation component to include a link to the new Notes page. - Implemented keyboard shortcuts for note actions, enhancing user experience and productivity. - Added dependencies for markdown rendering and formatting tools to support note content.
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useEffect,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
export interface KeyboardShortcut {
|
||||
@@ -20,130 +26,264 @@ const PAGE_SHORTCUTS: PageShortcuts = {
|
||||
{
|
||||
keys: ['Cmd', '?'],
|
||||
description: 'Afficher les raccourcis clavier',
|
||||
category: 'Navigation'
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'Q'],
|
||||
description: 'Basculer le thème',
|
||||
category: 'Apparence'
|
||||
category: 'Apparence',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'W'],
|
||||
description: 'Faire tourner les thèmes dark',
|
||||
category: 'Apparence'
|
||||
category: 'Apparence',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'B'],
|
||||
description: 'Changer le background',
|
||||
category: 'Apparence'
|
||||
category: 'Apparence',
|
||||
},
|
||||
{
|
||||
keys: ['Esc'],
|
||||
description: 'Fermer les modales/annuler',
|
||||
category: 'Navigation'
|
||||
}
|
||||
category: 'Navigation',
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
// Dashboard
|
||||
'/': [
|
||||
{
|
||||
keys: ['Shift', 'K'],
|
||||
description: 'Vers Kanban',
|
||||
category: 'Navigation'
|
||||
}
|
||||
category: 'Navigation',
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
// Kanban
|
||||
'/kanban': [
|
||||
{
|
||||
keys: ['Shift', 'N'],
|
||||
description: 'Créer une nouvelle tâche',
|
||||
category: 'Actions'
|
||||
category: 'Actions',
|
||||
},
|
||||
{
|
||||
keys: ['Space'],
|
||||
description: 'Basculer la vue compacte',
|
||||
category: 'Vue'
|
||||
category: 'Vue',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'F'],
|
||||
description: 'Ouvrir les filtres',
|
||||
category: 'Filtres'
|
||||
category: 'Filtres',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'S'],
|
||||
description: 'Basculer les swimlanes',
|
||||
category: 'Vue'
|
||||
category: 'Vue',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'O'],
|
||||
description: 'Basculer les objectifs',
|
||||
category: 'Vue'
|
||||
category: 'Vue',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'D'],
|
||||
description: 'Filtrer par date de fin',
|
||||
category: 'Filtres'
|
||||
category: 'Filtres',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'Z'],
|
||||
description: 'Basculer la taille de police',
|
||||
category: 'Vue'
|
||||
category: 'Vue',
|
||||
},
|
||||
{
|
||||
keys: ['Tab'],
|
||||
description: 'Navigation entre colonnes',
|
||||
category: 'Navigation'
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Enter'],
|
||||
description: 'Valider une tâche',
|
||||
category: 'Actions'
|
||||
category: 'Actions',
|
||||
},
|
||||
{
|
||||
keys: ['Esc'],
|
||||
description: 'Annuler la création de tâche',
|
||||
category: 'Actions'
|
||||
}
|
||||
category: 'Actions',
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
// Daily
|
||||
'/daily': [
|
||||
{
|
||||
keys: ['←', '→'],
|
||||
description: 'Navigation jour précédent/suivant',
|
||||
category: 'Navigation'
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Shift', 'H'],
|
||||
description: 'Aller à aujourd\'hui',
|
||||
category: 'Navigation'
|
||||
description: "Aller à aujourd'hui",
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Enter'],
|
||||
description: 'Valider un élément',
|
||||
category: 'Actions'
|
||||
}
|
||||
category: 'Actions',
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
// Manager
|
||||
'/weekly-manager': [
|
||||
{
|
||||
keys: ['Cmd', 'Ctrl', 'N'],
|
||||
description: 'Créer un objectif',
|
||||
category: 'Actions'
|
||||
category: 'Actions',
|
||||
},
|
||||
{
|
||||
keys: ['←', '→'],
|
||||
description: 'Navigation semaine précédente/suivante',
|
||||
category: 'Navigation'
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Ctrl', 'T'],
|
||||
description: 'Aller à cette semaine',
|
||||
category: 'Navigation'
|
||||
}
|
||||
]
|
||||
category: 'Navigation',
|
||||
},
|
||||
],
|
||||
|
||||
// Notes
|
||||
'/notes': [
|
||||
{
|
||||
keys: ['Cmd', 'N'],
|
||||
description: 'Créer une nouvelle note',
|
||||
category: 'Actions',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'S'],
|
||||
description: 'Sauvegarder la note',
|
||||
category: 'Actions',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'E'],
|
||||
description: 'Basculer mode édition/aperçu',
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'P'],
|
||||
description: 'Basculer aperçu',
|
||||
category: 'Navigation',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'B'],
|
||||
description: 'Texte en gras',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'I'],
|
||||
description: 'Texte en italique',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'K'],
|
||||
description: 'Créer un lien',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'K'],
|
||||
description: 'Code inline',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'C'],
|
||||
description: 'Bloc de code',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'X'],
|
||||
description: 'Texte barré',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'H'],
|
||||
description: 'Titre niveau 1',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', '2'],
|
||||
description: 'Titre niveau 2',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', '3'],
|
||||
description: 'Titre niveau 3',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'L'],
|
||||
description: 'Liste à puces',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'O'],
|
||||
description: 'Liste numérotée',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'Q'],
|
||||
description: 'Citation',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Z'],
|
||||
description: 'Annuler',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'Z'],
|
||||
description: 'Rétablir',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'A'],
|
||||
description: 'Tout sélectionner',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'C'],
|
||||
description: 'Copier',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'V'],
|
||||
description: 'Coller',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'X'],
|
||||
description: 'Couper',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'F'],
|
||||
description: 'Rechercher',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'G'],
|
||||
description: 'Rechercher suivant',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'G'],
|
||||
description: 'Rechercher précédent',
|
||||
category: 'Édition',
|
||||
},
|
||||
{
|
||||
keys: ['Cmd', 'Shift', 'S'],
|
||||
description: 'Basculer la barre latérale',
|
||||
category: 'Navigation',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
interface KeyboardShortcutsContextType {
|
||||
@@ -154,36 +294,40 @@ interface KeyboardShortcutsContextType {
|
||||
toggleModal: () => void;
|
||||
}
|
||||
|
||||
const KeyboardShortcutsContext = createContext<KeyboardShortcutsContextType | undefined>(undefined);
|
||||
const KeyboardShortcutsContext = createContext<
|
||||
KeyboardShortcutsContextType | undefined
|
||||
>(undefined);
|
||||
|
||||
interface KeyboardShortcutsProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function KeyboardShortcutsProvider({ children }: KeyboardShortcutsProviderProps) {
|
||||
export function KeyboardShortcutsProvider({
|
||||
children,
|
||||
}: KeyboardShortcutsProviderProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
|
||||
// Obtenir les raccourcis pour la page actuelle
|
||||
const getCurrentPageShortcuts = (): KeyboardShortcut[] => {
|
||||
const shortcuts: KeyboardShortcut[] = [];
|
||||
|
||||
|
||||
// Ajouter les raccourcis globaux
|
||||
if (PAGE_SHORTCUTS['*']) {
|
||||
shortcuts.push(...PAGE_SHORTCUTS['*']);
|
||||
}
|
||||
|
||||
|
||||
// Ajouter les raccourcis spécifiques à la page
|
||||
const pageShortcuts = PAGE_SHORTCUTS[pathname];
|
||||
if (pageShortcuts) {
|
||||
shortcuts.push(...pageShortcuts);
|
||||
}
|
||||
|
||||
|
||||
return shortcuts;
|
||||
};
|
||||
|
||||
|
||||
const shortcuts = getCurrentPageShortcuts();
|
||||
|
||||
|
||||
// Gérer le raccourci Cmd+? pour ouvrir la popup
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
@@ -192,28 +336,28 @@ export function KeyboardShortcutsProvider({ children }: KeyboardShortcutsProvide
|
||||
event.preventDefault();
|
||||
setIsOpen(true);
|
||||
}
|
||||
|
||||
|
||||
// Esc pour fermer
|
||||
if (event.key === 'Escape' && isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
|
||||
const contextValue: KeyboardShortcutsContextType = {
|
||||
isOpen,
|
||||
shortcuts,
|
||||
openModal: () => setIsOpen(true),
|
||||
closeModal: () => setIsOpen(false),
|
||||
toggleModal: () => setIsOpen(prev => !prev)
|
||||
toggleModal: () => setIsOpen((prev) => !prev),
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<KeyboardShortcutsContext.Provider value={contextValue}>
|
||||
{children}
|
||||
@@ -224,7 +368,9 @@ export function KeyboardShortcutsProvider({ children }: KeyboardShortcutsProvide
|
||||
export function useKeyboardShortcutsModal() {
|
||||
const context = useContext(KeyboardShortcutsContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useKeyboardShortcutsModal must be used within a KeyboardShortcutsProvider');
|
||||
throw new Error(
|
||||
'useKeyboardShortcutsModal must be used within a KeyboardShortcutsProvider'
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user