Use Cases

Implémentation d'une palette de commandes avec Claude Code

Découvrez l'implémentation d'une palette de commandes avec Claude Code. Conseils pratiques et exemples de code inclus.

Améliorer radicalement l’expérience utilisateur avec une palette de commandes

La palette de commandes, que l’on retrouve dans VSCode ou Slack, est un élément d’interface destiné aux utilisateurs avancés permettant des opérations rapides au clavier. Avec Claude Code, vous pouvez implémenter efficacement une palette de commandes dotée de recherche, filtrage et navigation clavier.

Composant de palette de commandes de base

> Implémente une palette de commandes qui s'ouvre avec Cmd+K (Mac) / Ctrl+K (Windows).
> Avec recherche, navigation clavier et affichage par catégorie.
// components/CommandPalette.tsx
import { useState, useEffect, useRef, useCallback } from 'react';

interface Command {
  id: string;
  label: string;
  category: string;
  icon?: string;
  shortcut?: string;
  action: () => void;
}

interface CommandPaletteProps {
  commands: Command[];
}

export function CommandPalette({ commands }: CommandPaletteProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [query, setQuery] = useState('');
  const [selectedIndex, setSelectedIndex] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);

  const filtered = commands.filter(cmd =>
    cmd.label.toLowerCase().includes(query.toLowerCase()) ||
    cmd.category.toLowerCase().includes(query.toLowerCase())
  );

  // Raccourci global
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault();
        setIsOpen(prev => !prev);
      }
      if (e.key === 'Escape') setIsOpen(false);
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, []);

  // Gestion du focus
  useEffect(() => {
    if (isOpen) {
      inputRef.current?.focus();
      setQuery('');
      setSelectedIndex(0);
    }
  }, [isOpen]);

  const handleKeyNav = useCallback((e: React.KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setSelectedIndex(i => Math.min(i + 1, filtered.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setSelectedIndex(i => Math.max(i - 1, 0));
        break;
      case 'Enter':
        e.preventDefault();
        if (filtered[selectedIndex]) {
          filtered[selectedIndex].action();
          setIsOpen(false);
        }
        break;
    }
  }, [filtered, selectedIndex]);

  if (!isOpen) return null;

  return (
    <div className="fixed inset-0 z-50 flex items-start justify-center pt-[20vh]">
      <div className="fixed inset-0 bg-black/50" onClick={() => setIsOpen(false)} />
      <div className="relative w-full max-w-lg rounded-xl bg-white shadow-2xl dark:bg-gray-800">
        <input
          ref={inputRef}
          type="text"
          value={query}
          onChange={e => { setQuery(e.target.value); setSelectedIndex(0); }}
          onKeyDown={handleKeyNav}
          placeholder="Rechercher une commande..."
          className="w-full border-b px-4 py-3 text-lg outline-none dark:bg-gray-800"
        />
        <ul className="max-h-80 overflow-y-auto p-2" role="listbox">
          {filtered.map((cmd, index) => (
            <li
              key={cmd.id}
              role="option"
              aria-selected={index === selectedIndex}
              onClick={() => { cmd.action(); setIsOpen(false); }}
              className={`flex cursor-pointer items-center justify-between rounded-lg px-3 py-2
                ${index === selectedIndex ? 'bg-blue-50 dark:bg-blue-900/30' : 'hover:bg-gray-50'}`}
            >
              <div className="flex items-center gap-3">
                {cmd.icon && <span className="text-lg">{cmd.icon}</span>}
                <div>
                  <div className="font-medium">{cmd.label}</div>
                  <div className="text-xs text-gray-500">{cmd.category}</div>
                </div>
              </div>
              {cmd.shortcut && (
                <kbd className="rounded bg-gray-100 px-2 py-1 text-xs dark:bg-gray-700">
                  {cmd.shortcut}
                </kbd>
              )}
            </li>
          ))}
          {filtered.length === 0 && (
            <li className="px-3 py-8 text-center text-gray-500">
              Aucune commande correspondante
            </li>
          )}
        </ul>
      </div>
    </div>
  );
}

Définition et enregistrement des commandes

// hooks/useCommands.ts
import { useRouter } from 'next/navigation';

export function useCommands(): Command[] {
  const router = useRouter();

  return [
    {
      id: 'home', label: 'Aller à l\'accueil', category: 'Navigation',
      icon: '🏠', shortcut: 'G H',
      action: () => router.push('/'),
    },
    {
      id: 'blog', label: 'Liste des articles', category: 'Navigation',
      icon: '📝', shortcut: 'G B',
      action: () => router.push('/blog'),
    },
    {
      id: 'theme', label: 'Changer de thème', category: 'Paramètres',
      icon: '🌙', shortcut: 'T T',
      action: () => document.documentElement.classList.toggle('dark'),
    },
    {
      id: 'search', label: 'Rechercher un article', category: 'Recherche',
      icon: '🔍', shortcut: '/',
      action: () => router.push('/search'),
    },
  ];
}

Support de l’accessibilité

// Application WAI-ARIA
<div
  role="dialog"
  aria-modal="true"
  aria-label="Palette de commandes"
>
  <input
    role="combobox"
    aria-expanded="true"
    aria-controls="command-list"
    aria-activedescendant={`command-${filtered[selectedIndex]?.id}`}
  />
  <ul id="command-list" role="listbox">
    {/* ... */}
  </ul>
</div>

Résumé

La palette de commandes, combinée aux raccourcis clavier, améliore considérablement la productivité des utilisateurs avancés. Avec Claude Code, vous pouvez implémenter en peu de temps une palette de commandes complète avec recherche, filtrage et navigation clavier. Pensez aussi à l’accessibilité pour viser une interface utilisable par tous. Comme référence d’implémentation, envisagez aussi la bibliothèque cmdk.

#Claude Code #palette de commandes #UI #navigation clavier #React