diff --git a/packages/website/src/components/command-dialog.tsx b/packages/website/src/components/command-dialog.tsx new file mode 100644 index 000000000..245b71d12 --- /dev/null +++ b/packages/website/src/components/command-dialog.tsx @@ -0,0 +1,122 @@ +import * as React from "react"; +import { motion, AnimatePresence } from "framer-motion"; + +interface CommandDialogProps { + trigger: React.ReactNode; + title: string; + description?: string; + command: string; + footnote?: React.ReactNode; +} + +export function CommandDialog({ + trigger, + title, + description, + command, + footnote, +}: CommandDialogProps) { + const [open, setOpen] = React.useState(false); + const ref = React.useRef(null); + + React.useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (ref.current && !ref.current.contains(e.target as Node)) { + setOpen(false); + } + } + function handleKeyDown(e: KeyboardEvent) { + if (e.key === "Escape") setOpen(false); + } + document.addEventListener("mousedown", handleClickOutside); + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); + + return ( +
+ + + {open && ( + <> + setOpen(false)} + /> + +
+

{title}

+ {description && ( +

{description}

+ )} +
+ {command} + {footnote && ( +

{footnote}

+ )} +
+ + )} +
+
+ ); +} + +function CodeBlock({ children }: { children: string }) { + const [copied, setCopied] = React.useState(false); + + function handleCopy() { + navigator.clipboard.writeText(children); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + + return ( +
+
+ $ + {children} +
+ +
+ ); +} diff --git a/packages/website/src/components/landing-page.tsx b/packages/website/src/components/landing-page.tsx index df53f9940..5b69c4a8d 100644 --- a/packages/website/src/components/landing-page.tsx +++ b/packages/website/src/components/landing-page.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import { motion, AnimatePresence } from "framer-motion"; import { CursorFieldProvider } from "~/components/butterfly"; +import { CommandDialog } from "~/components/command-dialog"; import { appStoreUrl, playStoreUrl, @@ -507,63 +508,23 @@ function DownloadButton() { } function ServerInstallButton() { - const [open, setOpen] = React.useState(false); - const ref = React.useRef(null); - - React.useEffect(() => { - function handleClickOutside(e: MouseEvent) { - if (ref.current && !ref.current.contains(e.target as Node)) { - setOpen(false); - } - } - document.addEventListener("mousedown", handleClickOutside); - return () => document.removeEventListener("mousedown", handleClickOutside); - }, []); - return ( -
- - - {open && ( - <> - setOpen(false)} - /> - -
-

Run agents on a remote machine

-

- For headless machines you want to connect to from the Paseo apps. The desktop app - already includes a built-in daemon. -

-
- npm install -g @getpaseo/cli && paseo -

- Requires Node.js 18+. Run paseo to - start the daemon. -

-
- - )} -
-
+ + + + } + title="Run agents on a remote machine" + description="For headless machines you want to connect to from the Paseo apps. The desktop app already includes a built-in daemon." + command="npm install -g @getpaseo/cli && paseo" + footnote={ + <> + Requires Node.js 18+. Run paseo to + start the daemon. + + } + /> ); } @@ -671,52 +632,6 @@ function Step({ number, children }: { number: number; children: React.ReactNode ); } -function CodeBlock({ children }: { children: React.ReactNode }) { - const [copied, setCopied] = React.useState(false); - const text = typeof children === "string" ? children : ""; - - function handleCopy() { - navigator.clipboard.writeText(text); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } - - return ( -
-
- $ - {children} -
- -
- ); -} const bashKeywords = new Set([ "while", diff --git a/packages/website/src/routes/download.tsx b/packages/website/src/routes/download.tsx index 7c2049f89..aebd3fff9 100644 --- a/packages/website/src/routes/download.tsx +++ b/packages/website/src/routes/download.tsx @@ -1,4 +1,5 @@ import { Link, createFileRoute } from "@tanstack/react-router"; +import { CommandDialog } from "~/components/command-dialog"; import { pageMeta } from "~/meta"; import { desktopVersion, @@ -109,9 +110,18 @@ function Download() { macOS -
+
+ + Homebrew + + } + title="Install via Homebrew" + command="brew install --cask paseo" + />
@@ -168,7 +178,7 @@ function Download() { external />