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