Overview
What Ryno does, and where to start if you have never opened it.
What Ryno does
Ryno sends Android and iOS deep links to a device from your machine. On an Android phone or an iOS simulator, it tells you what came back — the verdict, the logs, a screenshot. Android goes through ADB, iOS through the Xcode tools.
There is no server, no database and no account. Your workspace is a folder you own: every request in it is a file you can read, diff and review with the rest of your project, and your team gets the same ones when you commit it.
On a physical iPhone, Ryno can send a link but cannot check what the device did with it. It says the link was sent, and claims nothing more.
Where to start
Open a folder as your workspace, then send your first deep link. The pages are meant to be read in that order, and each one ends with the one that follows it.
Live components
The components below are the ones the app ships. Each one runs on this page — open the dialog and it really opens — and the code under it is the file that runs, read from the repository when the page is built. There is no second copy of it to keep in step.
import { Button } from '@ryno/design-system';
export default function ButtonExample(): React.JSX.Element {
return (
<div className="flex flex-wrap items-center gap-3">
<Button>Run request</Button>
<Button variant="outline">Open workspace folder…</Button>
<Button variant="ghost">Cancel</Button>
</div>
);
}import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
Input,
} from '@ryno/design-system';
export default function DialogExample(): React.JSX.Element {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Rename request</Button>
</DialogTrigger>
<DialogContent closeLabel="Close">
<DialogHeader>
<DialogTitle>Rename request</DialogTitle>
<DialogDescription>
The request is a file in your workspace, so renaming it renames that file
too.
</DialogDescription>
</DialogHeader>
<Input aria-label="Request name" defaultValue="open-product" />
<DialogFooter>
<DialogClose asChild>
<Button variant="ghost">Cancel</Button>
</DialogClose>
<DialogClose asChild>
<Button>Rename</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}import { Kbd, KeyLanguage, KeyToken } from '@ryno/design-system';
export default function KeyBadgeExample(): React.JSX.Element {
return (
<div className="flex flex-wrap items-center gap-3">
<Kbd keys={[KeyToken.Mod, KeyToken.Enter]} lang={KeyLanguage.English} />
<Kbd keys={[KeyToken.Mod, 'O']} lang={KeyLanguage.English} />
<Kbd keys={[KeyToken.Shift, KeyToken.Tab]} lang={KeyLanguage.English} />
<Kbd keys={['/']} lang={KeyLanguage.English} />
</div>
);
}Surfaces
Switch the theme in the header and these surfaces change with it. They are the ones the app paints, down to the value, because this page names them and never sets a colour of its own.
Card
bg-card
Muted
bg-muted
Surface
bg-surface