CommandPalette.tsx raw

   1  import {
   2    ArrowUpDownIcon,
   3    Code2Icon,
   4    CreditCardIcon,
   5    FileSignatureIcon,
   6    FileTextIcon,
   7    HomeIcon,
   8    InfoIcon,
   9    LayoutGridIcon,
  10    LinkIcon,
  11    NetworkIcon,
  12    PlugIcon,
  13    QrCodeIcon,
  14    RefreshCwIcon,
  15    SendIcon,
  16    SettingsIcon,
  17    ShieldIcon,
  18    ShuffleIcon,
  19    SquareStackIcon,
  20    UserIcon,
  21    UserPlus2Icon,
  22    WalletIcon,
  23  } from "lucide-react";
  24  import * as React from "react";
  25  import { useNavigate } from "react-router";
  26  import AppAvatar from "src/components/AppAvatar";
  27  
  28  import {
  29    CommandDialog,
  30    CommandGroup,
  31    CommandInput,
  32    CommandItem,
  33    CommandList,
  34    CommandSeparator,
  35  } from "src/components/ui/command";
  36  import { useApps } from "src/hooks/useApps";
  37  
  38  interface CommandPaletteProps {
  39    open?: boolean;
  40    onOpenChange?: (open: boolean) => void;
  41  }
  42  
  43  export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
  44    const navigate = useNavigate();
  45    const [searchText, setSearchText] = React.useState("");
  46  
  47    const { data: connectedAppsByAppName } = useApps(
  48      undefined,
  49      undefined,
  50      {
  51        name: searchText,
  52      },
  53      undefined,
  54      !!searchText?.length
  55    );
  56  
  57    const runCommand = React.useCallback(
  58      (command: () => void) => {
  59        onOpenChange?.(false);
  60        setSearchText("");
  61        // hack: run the command after 1ms delay to fix autofocus
  62        setTimeout(command, 1);
  63      },
  64      [onOpenChange]
  65    );
  66  
  67    return (
  68      <CommandDialog open={open} onOpenChange={onOpenChange}>
  69        <CommandInput
  70          placeholder="Type a command or search..."
  71          value={searchText}
  72          onValueChange={setSearchText}
  73        />
  74  
  75        <CommandList>
  76          {/* <CommandEmpty>No results found</CommandEmpty> */}
  77          <CommandGroup heading="Navigation">
  78            <CommandItem
  79              onSelect={() => runCommand(() => navigate("/home"))}
  80              keywords={["dashboard"]}
  81            >
  82              <HomeIcon />
  83              <span>Home</span>
  84            </CommandItem>
  85            <CommandItem onSelect={() => runCommand(() => navigate("/wallet"))}>
  86              <WalletIcon />
  87              <span>Wallet</span>
  88            </CommandItem>
  89            <CommandItem
  90              onSelect={() =>
  91                runCommand(() => navigate("/apps?tab=connected-apps"))
  92              }
  93            >
  94              <PlugIcon />
  95              <span>Connected Apps</span>
  96            </CommandItem>
  97            <CommandItem
  98              onSelect={() => runCommand(() => navigate("/sub-wallets"))}
  99            >
 100              <CreditCardIcon />
 101              <span>Sub-wallets</span>
 102            </CommandItem>
 103            <CommandItem
 104              onSelect={() => runCommand(() => navigate("/channels"))}
 105              keywords={["node", "liquidity", "channels"]}
 106            >
 107              <NetworkIcon />
 108              <span>Node</span>
 109            </CommandItem>
 110            <CommandItem onSelect={() => runCommand(() => navigate("/peers"))}>
 111              <NetworkIcon />
 112              <span>Peers</span>
 113            </CommandItem>
 114            <CommandItem
 115              onSelect={() => runCommand(() => navigate("/apps?tab=app-store"))}
 116            >
 117              <LayoutGridIcon />
 118              <span>App Store</span>
 119            </CommandItem>
 120          </CommandGroup>
 121          <CommandSeparator />
 122          <CommandGroup heading="Wallet Actions">
 123            <CommandItem
 124              onSelect={() => runCommand(() => navigate("/wallet/send"))}
 125            >
 126              <SendIcon />
 127              <span>Send Payment</span>
 128            </CommandItem>
 129            <CommandItem
 130              onSelect={() => runCommand(() => navigate("/wallet/receive"))}
 131            >
 132              <QrCodeIcon />
 133              <span>Receive Payment</span>
 134            </CommandItem>
 135            <CommandItem
 136              onSelect={() => runCommand(() => navigate("/wallet/swap"))}
 137            >
 138              <ShuffleIcon />
 139              <span>Swap</span>
 140            </CommandItem>
 141            <CommandItem
 142              onSelect={() => runCommand(() => navigate("/wallet/swap/auto"))}
 143            >
 144              <RefreshCwIcon />
 145              <span>Auto Swap</span>
 146            </CommandItem>
 147            <CommandItem
 148              onSelect={() =>
 149                runCommand(() => navigate("/wallet/receive/invoice"))
 150              }
 151            >
 152              <FileTextIcon />
 153              <span>Create Invoice</span>
 154            </CommandItem>
 155            <CommandItem
 156              onSelect={() =>
 157                runCommand(() => navigate("/wallet/receive?type=onchain"))
 158              }
 159            >
 160              <LinkIcon />
 161              <span>Receive On-chain</span>
 162            </CommandItem>
 163            <CommandItem
 164              onSelect={() => runCommand(() => navigate("/wallet/sign-message"))}
 165            >
 166              <FileSignatureIcon />
 167              <span>Sign Message</span>
 168            </CommandItem>
 169          </CommandGroup>
 170          <CommandSeparator />
 171          <CommandGroup heading="Settings">
 172            <CommandItem
 173              onSelect={() => runCommand(() => navigate("/settings"))}
 174              keywords={["theme", "fiat", "currency", "dark"]}
 175            >
 176              <SettingsIcon />
 177              <span>Settings</span>
 178            </CommandItem>
 179            <CommandItem
 180              onSelect={() => runCommand(() => navigate("/settings/backup"))}
 181            >
 182              <ShieldIcon />
 183              <span>Backup</span>
 184            </CommandItem>
 185            <CommandItem
 186              onSelect={() =>
 187                runCommand(() => navigate("/settings/alby-account"))
 188              }
 189            >
 190              <UserIcon />
 191              <span>Alby Account</span>
 192            </CommandItem>
 193            <CommandItem
 194              keywords={["info"]}
 195              onSelect={() => runCommand(() => navigate("/settings/about"))}
 196            >
 197              <InfoIcon />
 198              <span>About</span>
 199            </CommandItem>
 200            <CommandItem
 201              onSelect={() => runCommand(() => navigate("/settings/developer"))}
 202            >
 203              <Code2Icon />
 204              <span>Developer Settings</span>
 205            </CommandItem>
 206          </CommandGroup>
 207          <CommandSeparator />
 208          <CommandGroup heading="Quick Actions">
 209            <CommandItem onSelect={() => runCommand(() => navigate("/apps/new"))}>
 210              <PlugIcon />
 211              <span>Connect New App</span>
 212            </CommandItem>
 213            <CommandItem
 214              keywords={["New Sub-Wallet"]}
 215              onSelect={() => runCommand(() => navigate("/sub-wallets/new"))}
 216            >
 217              <SquareStackIcon />
 218              <span>Create Sub-wallet</span>
 219            </CommandItem>
 220            <CommandItem
 221              keywords={["New Channel"]}
 222              onSelect={() => runCommand(() => navigate("/channels/incoming"))}
 223            >
 224              <ArrowUpDownIcon />
 225              <span>Open Channel</span>
 226            </CommandItem>
 227            <CommandItem
 228              onSelect={() => runCommand(() => navigate("/peers/new"))}
 229            >
 230              <UserPlus2Icon />
 231              <span>Connect Peer</span>
 232            </CommandItem>
 233          </CommandGroup>
 234          {!!connectedAppsByAppName?.apps.length && (
 235            <CommandGroup heading="Connected Apps" forceMount>
 236              {connectedAppsByAppName?.apps.map((app) => (
 237                <CommandItem
 238                  key={app.id}
 239                  onSelect={() => runCommand(() => navigate(`/apps/${app.id}`))}
 240                >
 241                  <AppAvatar app={app} className="size-4" />
 242                  <span>{app.name}</span>
 243                </CommandItem>
 244              ))}
 245            </CommandGroup>
 246          )}
 247        </CommandList>
 248      </CommandDialog>
 249    );
 250  }
 251