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.sm} />
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  backgroundColor: theme.background.default,
49  width: '20vw',
50  minWidth: 240,
51  maxWidth: 320,
52  padding: `0 ${spacing[3]}px`,
53  borderColor: theme.border.default,
54  boxShadow: shadows.xs,
55  marginRight: spacing[3],
56
57  '&:focus': {
58    boxShadow: shadows.xs,
59  },
60
61  '> div': {
62    width: '100%',
63    gap: spacing[2.5],
64  },
65
66  kbd: {
67    height: 20,
68    lineHeight: '19px',
69  },
70
71  [`@media screen and (max-width: ${breakpoints.medium}px)`]: {
72    minWidth: 42,
73    width: 42,
74    marginRight: 0,
75  },
76});
77
78const labelStyle = css({
79  color: theme.icon.secondary,
80});
81
82const keysWrapperStyle = css({
83  marginLeft: 'auto',
84});
85
86const hideOnMobileStyle = css({
87  [`@media screen and (max-width: ${breakpoints.medium}px)`]: {
88    display: 'none',
89  },
90});
91