All files / src/components KeyboardShortcuts.jsx

0% Statements 0/27
0% Branches 0/15
0% Functions 0/11
0% Lines 0/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                                                                                                                                                                                                                                     
/**
 * @fileoverview Keyboard Shortcuts Overlay Component
 * @description Shows all available keyboard shortcuts when pressing ?
 * @module components/KeyboardShortcuts
 */
 
import { useState, useEffect } from 'react';
import './KeyboardShortcuts.css';
 
const SHORTCUTS = [
  { category: 'Simulation', shortcuts: [
    { keys: ['Space'], description: 'Play/Pause simulation' },
    { keys: ['R'], description: 'Reset simulation' },
    { keys: ['C'], description: 'Clear all atoms' },
  ]},
  { category: 'View', shortcuts: [
    { keys: ['B'], description: 'Toggle bonds' },
    { keys: ['V'], description: 'Toggle velocity vectors' },
    { keys: ['L'], description: 'Toggle atom labels' },
    { keys: ['G'], description: 'Toggle grid' },
    { keys: ['F'], description: 'Toggle fullscreen' },
  ]},
  { category: 'Navigation', shortcuts: [
    { keys: ['↑', '↓', '←', '→'], description: 'Move player atom' },
    { keys: ['Scroll'], description: 'Zoom in/out' },
    { keys: ['Drag'], description: 'Pan canvas' },
    { keys: ['+', '-'], description: 'Zoom in/out' },
    { keys: ['0'], description: 'Reset zoom' },
  ]},
  { category: 'Edit', shortcuts: [
    { keys: ['Ctrl', 'Z'], description: 'Undo' },
    { keys: ['Ctrl', 'Y'], description: 'Redo' },
    { keys: ['Ctrl', 'A'], description: 'Select all atoms' },
    { keys: ['Delete'], description: 'Delete selected atoms' },
    { keys: ['Ctrl', 'C'], description: 'Copy selected atoms' },
    { keys: ['Ctrl', 'V'], description: 'Paste atoms' },
  ]},
  { category: 'Tools', shortcuts: [
    { keys: ['S'], description: 'Screenshot' },
    { keys: ['?'], description: 'Show/hide shortcuts' },
    { keys: ['Esc'], description: 'Close modal/Cancel' },
  ]},
];
 
/**
 * Keyboard Shortcuts Overlay Component
 */
function KeyboardShortcuts() {
  const [isVisible, setIsVisible] = useState(false);
 
  useEffect(() => {
    const handleKeyDown = (e) => {
      // Don't trigger if typing in an input field
      const isInputField = ['INPUT', 'TEXTAREA', 'SELECT'].includes(e.target.tagName);
      if (isInputField) return;
      
      // Show on ? key (Shift + / or direct ?)
      if (e.key === '?' || (e.shiftKey && e.code === 'Slash')) {
        e.preventDefault();
        e.stopPropagation();
        setIsVisible(prev => !prev);
      }
      // Close on Escape
      if (e.key === 'Escape' && isVisible) {
        e.preventDefault();
        setIsVisible(false);
      }
    };
 
    // Use capture phase to ensure we get the event first
    window.addEventListener('keydown', handleKeyDown, true);
    return () => window.removeEventListener('keydown', handleKeyDown, true);
  }, [isVisible]);
 
  if (!isVisible) return null;
 
  return (
    <div className="shortcuts-overlay" onClick={() => setIsVisible(false)}>
      <div className="shortcuts-modal" onClick={e => e.stopPropagation()}>
        <div className="shortcuts-header">
          <h2>⌨️ Keyboard Shortcuts</h2>
          <button className="shortcuts-close" onClick={() => setIsVisible(false)}>×</button>
        </div>
        <div className="shortcuts-content">
          {SHORTCUTS.map(category => (
            <div key={category.category} className="shortcuts-category">
              <h3>{category.category}</h3>
              <div className="shortcuts-list">
                {category.shortcuts.map((shortcut, idx) => (
                  <div key={idx} className="shortcut-item">
                    <div className="shortcut-keys">
                      {shortcut.keys.map((key, kidx) => (
                        <span key={kidx}>
                          <kbd>{key}</kbd>
                          {kidx < shortcut.keys.length - 1 && <span className="key-separator">+</span>}
                        </span>
                      ))}
                    </div>
                    <span className="shortcut-desc">{shortcut.description}</span>
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>
        <div className="shortcuts-footer">
          Press <kbd>?</kbd> to toggle this overlay
        </div>
      </div>
    </div>
  );
}
 
export default KeyboardShortcuts;