File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ import { useNavigate , useSubmit } from "@remix-run/react" ;
2+ import { useShortcutKeys } from "~/hooks/useShortcutKeys" ;
3+ import { useOptionalUser } from "~/hooks/useUser" ;
4+ import { adminPath } from "~/utils/pathBuilder" ;
5+
6+ /**
7+ * App-wide keyboard shortcuts, mounted once at the root so they work on every page regardless of
8+ * which side menu (if any) is rendered. Add new global shortcuts here.
9+ *
10+ * Renders nothing. Reads the user from the root loader via `useOptionalUser`, so on unauthenticated
11+ * pages there is simply no admin and nothing is registered.
12+ */
13+ export function GlobalShortcuts ( ) {
14+ const user = useOptionalUser ( ) ;
15+ const navigate = useNavigate ( ) ;
16+ const submit = useSubmit ( ) ;
17+
18+ const isImpersonating = Boolean ( user ?. isImpersonating ) ;
19+ const isAdmin = Boolean ( user ?. admin ) || isImpersonating ;
20+
21+ // ⌘/Ctrl+Esc: admins jump to the admin dashboard; while impersonating the same shortcut stops
22+ // impersonating instead. `enabledOnInputElements` so it still fires while a field is focused.
23+ useShortcutKeys ( {
24+ shortcut : isAdmin
25+ ? { modifiers : [ "mod" ] , key : "esc" , enabledOnInputElements : true }
26+ : undefined ,
27+ action : ( ) => {
28+ if ( isImpersonating ) {
29+ submit ( null , { action : "/resources/impersonation" , method : "delete" } ) ;
30+ } else {
31+ navigate ( adminPath ( ) ) ;
32+ }
33+ } ,
34+ } ) ;
35+
36+ return null ;
37+ }
Original file line number Diff line number Diff line change 33 ChevronRightIcon ,
44 ExclamationTriangleIcon ,
55} from "@heroicons/react/24/outline" ;
6- import { useFetcher , useNavigate , useNavigation , useSubmit } from "@remix-run/react" ;
6+ import { useFetcher , useNavigation , useSubmit } from "@remix-run/react" ;
77import { LayoutGroup , motion } from "framer-motion" ;
88import {
99 type CSSProperties ,
@@ -1490,29 +1490,13 @@ function AccountMenuItems({
14901490function AccountMenu ( { isAdmin, isImpersonating } : { isAdmin : boolean ; isImpersonating : boolean } ) {
14911491 const [ isOpen , setIsOpen ] = useState ( false ) ;
14921492 const navigation = useNavigation ( ) ;
1493- const navigate = useNavigate ( ) ;
1494- const submit = useSubmit ( ) ;
14951493
14961494 useEffect ( ( ) => {
14971495 setIsOpen ( false ) ;
14981496 } , [ navigation . location ?. pathname ] ) ;
14991497
1500- const stopImpersonating = ( ) =>
1501- submit ( null , { action : "/resources/impersonation" , method : "delete" } ) ;
1502-
1503- useShortcutKeys ( {
1504- shortcut : isAdmin
1505- ? { modifiers : [ "mod" ] , key : "esc" , enabledOnInputElements : true }
1506- : undefined ,
1507- action : ( ) => {
1508- if ( isImpersonating ) {
1509- stopImpersonating ( ) ;
1510- } else {
1511- navigate ( adminPath ( ) ) ;
1512- }
1513- } ,
1514- } ) ;
1515-
1498+ // The ⌘/Ctrl+Esc admin shortcut lives in <GlobalShortcuts> so it works everywhere, not only where
1499+ // this menu is mounted.
15161500 return (
15171501 < Popover onOpenChange = { ( open ) => setIsOpen ( open ) } open = { isOpen } >
15181502 < SimpleTooltip
Original file line number Diff line number Diff line change @@ -7,6 +7,7 @@ import type { ToastMessage } from "~/models/message.server";
77import { commitSession , getSession } from "~/models/message.server" ;
88import tailwindStylesheetUrl from "~/tailwind.css" ;
99import { RouteErrorDisplay } from "./components/ErrorDisplay" ;
10+ import { GlobalShortcuts } from "./components/GlobalShortcuts" ;
1011import { AppContainer , MainCenteredContainer } from "./components/layout/AppLayout" ;
1112import { ShortcutsProvider } from "./components/primitives/ShortcutsProvider" ;
1213import { Toast } from "./components/primitives/Toast" ;
@@ -131,6 +132,7 @@ export default function App() {
131132 < body className = "h-full overflow-hidden bg-background-dimmed antialiased" >
132133 < ShortcutsProvider >
133134 < TimezoneSetter />
135+ < GlobalShortcuts />
134136 < Outlet />
135137 < Toast />
136138 </ ShortcutsProvider >
You can’t perform that action at this time.
0 commit comments