From f616d116fcd1ae4900b833b9d6f7f1be7fe67844 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 11 Jan 2026 16:07:53 -0500 Subject: [PATCH 01/17] feat(sidebar): shortcut key bindings and hints Signed-off-by: Adam Setch --- src/renderer/components/Sidebar.tsx | 66 ++- .../__snapshots__/Sidebar.test.tsx.snap | 408 +++++++++++++++++- 2 files changed, 449 insertions(+), 25 deletions(-) diff --git a/src/renderer/components/Sidebar.tsx b/src/renderer/components/Sidebar.tsx index 0be792987..c4985565d 100644 --- a/src/renderer/components/Sidebar.tsx +++ b/src/renderer/components/Sidebar.tsx @@ -1,4 +1,4 @@ -import type { FC } from 'react'; +import { type FC, useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { @@ -41,6 +41,10 @@ export const Sidebar: FC = () => { const primaryAccountHostname = getPrimaryAccountHostname(auth); + const goHome = () => { + navigate('/', { replace: true }); + }; + const toggleFilters = () => { if (location.pathname.startsWith('/filters')) { navigate('/', { replace: true }); @@ -59,10 +63,61 @@ export const Sidebar: FC = () => { }; const refreshNotifications = () => { - navigate('/', { replace: true }); + goHome(); fetchNotifications(); }; + useEffect(() => { + const sidebarShortcutHandler = (event: KeyboardEvent) => { + // Ignore if user is typing in an input, textarea, or with modifiers + if ( + event.target instanceof HTMLInputElement || + event.target instanceof HTMLTextAreaElement || + event.metaKey || + event.ctrlKey || + event.altKey + ) { + return; + } + + const key = event.key.toLowerCase(); + + switch (key) { + case 'h': + event.preventDefault(); + goHome(); + break; + case 'r': + if (status !== 'loading') { + event.preventDefault(); + refreshNotifications(); + } + break; + case 's': + if (isLoggedIn) { + event.preventDefault(); + toggleSettings(); + } + break; + case 'f': + if (isLoggedIn) { + event.preventDefault(); + toggleFilters(); + } + break; + default: + // No action for other keys + break; + } + }; + + document.addEventListener('keydown', sidebarShortcutHandler); + + return () => { + document.removeEventListener('keydown', sidebarShortcutHandler); + }; + }, [isLoggedIn, status]); + return ( { data-testid="sidebar-home" description="Home" icon={LogoIcon} - onClick={() => navigate('/', { replace: true })} + keybindingHint="H" + onClick={() => goHome()} size="small" tooltipDirection="e" variant="invisible" @@ -103,6 +159,7 @@ export const Sidebar: FC = () => { data-testid="sidebar-filter-notifications" description="Filter notifications" icon={FilterIcon} + keybindingHint="F" onClick={() => toggleFilters()} size="small" tooltipDirection="e" @@ -146,6 +203,7 @@ export const Sidebar: FC = () => { description="Refresh notifications" disabled={status === 'loading'} icon={SyncIcon} + keybindingHint="R" // loading={status === 'loading'} onClick={() => refreshNotifications()} size="small" @@ -156,7 +214,9 @@ export const Sidebar: FC = () => { toggleSettings()} size="small" tooltipDirection="e" diff --git a/src/renderer/components/__snapshots__/Sidebar.test.tsx.snap b/src/renderer/components/__snapshots__/Sidebar.test.tsx.snap index 58b56b976..52d7c628a 100644 --- a/src/renderer/components/__snapshots__/Sidebar.test.tsx.snap +++ b/src/renderer/components/__snapshots__/Sidebar.test.tsx.snap @@ -188,11 +188,47 @@ exports[`renderer/components/Sidebar.tsx should render itself & its children (lo aria-hidden="true" class="prc-TooltipV2-Tooltip-tLeuB" data-direction="e" - id="_r_1_" popover="auto" role="tooltip" > - Home + + Home + + ( + h + ) + + +