1import { css } from '@emotion/react'; 2import { breakpoints, iconSize, SearchIcon, shadows, spacing, theme } from '@expo/styleguide'; 3import { Dispatch, SetStateAction, useEffect, useState } from 'react'; 4 5import { isAppleDevice } from './utils'; 6 7import { Button } from '~/ui/components/Button'; 8import { CALLOUT, KBD } from '~/ui/components/Text'; 9 10type Props = { 11 setOpen: Dispatch<SetStateAction<boolean>>; 12}; 13 14export const CommandMenuTrigger = ({ setOpen }: Props) => { 15 const [isMac, setIsMac] = useState<boolean | null>(null); 16 17 useEffect(() => { 18 setIsMac(typeof navigator !== 'undefined' && isAppleDevice()); 19 }, []); 20 21 useEffect(() => { 22 if (isMac !== null) { 23 const keyDownListener = (e: KeyboardEvent) => { 24 if (e.key === 'k' && (isMac ? e.metaKey : e.ctrlKey)) { 25 e.preventDefault(); 26 setOpen(open => !open); 27 } 28 }; 29 document.addEventListener('keydown', keyDownListener, false); 30 return () => document.removeEventListener('keydown', keyDownListener); 31 } 32 }, [isMac]); 33 34 return ( 35 <Button theme="ghost" css={buttonStyle} onClick={() => setOpen(true)}> 36 <SearchIcon size={iconSize.small} /> 37 <CALLOUT css={[labelStyle, hideOnMobileStyle]}>Search</CALLOUT> 38 {isMac !== null && ( 39 <div css={[keysWrapperStyle, hideOnMobileStyle]}> 40 <KBD>{isMac ? '⌘' : 'Ctrl'}</KBD> <KBD>K</KBD> 41 </div> 42 )} 43 </Button> 44 ); 45}; 46 47const buttonStyle = css({ 48 width: '20vw', 49 minWidth: 240, 50 maxWidth: 320, 51 padding: `0 ${spacing[3]}px`, 52 borderColor: theme.border.default, 53 boxShadow: shadows.input, 54 marginRight: spacing[3], 55 56 '&:focus': { 57 boxShadow: shadows.button, 58 }, 59 60 '> div': { 61 width: '100%', 62 gap: spacing[2.5], 63 }, 64 65 kbd: { 66 height: 20, 67 lineHeight: '19px', 68 }, 69 70 [`@media screen and (max-width: ${breakpoints.medium}px)`]: { 71 minWidth: 42, 72 width: 42, 73 marginRight: 0, 74 }, 75}); 76 77const labelStyle = css({ 78 color: theme.icon.secondary, 79}); 80 81const keysWrapperStyle = css({ 82 marginLeft: 'auto', 83}); 84 85const hideOnMobileStyle = css({ 86 [`@media screen and (max-width: ${breakpoints.medium}px)`]: { 87 display: 'none', 88 }, 89}); 90