use-calendar-hotkey-items.ts2.8 KBView on GitHub
import {
  useSeeAllActionsShortcut,
  type WelcomeShortcut,
} from '@/modules/cedar-os/src/cedar-os-components/chatComponents/welcomeShortcuts';
import { formatDisplayKeys } from '@/lib/hotkeys/use-hotkey-utils';
import { pressShortcutKeys } from '@/components/ui/hotkey-bar';
import { keyboardShortcuts } from '@/config/shortcuts';

/**
 * The order the calendar's keys are TAUGHT in: move around the grid first, then act on what
 * you're pointing at. (The bar's scope-derived mode can't express this — it takes whatever the
 * first three entries of the active scope happen to be, which is how /calendar ended up
 * advertising a near-arbitrary subset.) Anything in the `calendar` scope but absent here still
 * shows, after these.
 */
const TEACHING_ORDER = [
  'calendarGoToDate',
  'calendarFollowUp',
  'calendarNoShowEmail',
  'calendarRescheduleEmail',
];

/**
 * Bound and working, but not worth a slot in the bar: ←/→ already have visible chevrons beside
 * "Today" that say the same thing, and `c` duplicates click-an-empty-slot, which is how an
 * event actually gets created. All three still fire, and still appear in the ⌘K catalogue.
 */
const NOT_TAUGHT_HERE = new Set(['calendarPreviousWeek', 'calendarNextWeek', 'newCalendarEvent']);

/**
 * Every shortcut the calendar grid actually binds, as HotkeyBar rows — derived from
 * `config/shortcuts.ts` so the bar under the grid cannot drift from the keys the grid listens
 * for (CalendarView's `useHotkeys`, scope `calendar`). This is the list that used to be spelled
 * out as a legend in the empty chat; the chat column now holds the calendar rail instead.
 */
export function useCalendarHotkeyItems(): WelcomeShortcut[] {
  // An explicit `items` list replaces the bar's own trailing "⌘K more commands" / "?" rows, so
  // the way out to the full catalogue has to be carried here — same row the home bar ends on.
  const seeAllActions = useSeeAllActionsShortcut();

  const calendarShortcuts = keyboardShortcuts.filter(
    (shortcut) =>
      shortcut.scope === 'calendar' && !shortcut.ignore && !NOT_TAUGHT_HERE.has(shortcut.action),
  );

  const rows: WelcomeShortcut[] = [...calendarShortcuts]
    .sort((a, b) => {
      const rank = (action: string) => {
        const index = TEACHING_ORDER.indexOf(action);
        return index === -1 ? TEACHING_ORDER.length : index;
      };
      return rank(a.action) - rank(b.action);
    })
    .map((shortcut) => ({
      // Always formatted as SINGLE keys — the bar's `items` renderer joins them with `+`
      // ("n + s"), which is what a combination means here. Passing the shortcut's own
      // 'combination' type would concatenate them into one illegible kbd ("ns").
      keys: formatDisplayKeys(shortcut.keys, 'single'),
      label: shortcut.description,
      onClick: () => pressShortcutKeys(shortcut.keys),
    }));

  return [...rows, seeAllActions];
}