Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

65 linesCodeBlameRaw
1import type { ReactNode } from "react";
2
3import { Card } from "./ui/card";
4import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
5import { SwitchCard } from "./ui/switch";
6
7/** A group of settings: its name and what it is for on the left, the settings on the right. */
8export function SettingsSection({ id, title, about, children }: { id?: string; title: string; about: ReactNode; children: ReactNode }) {
9 return (
10 <section id={id} className="grid gap-x-10 gap-y-4 border-t border-line pt-8 first:border-t-0 first:pt-0 lg:grid-cols-[16rem_1fr]">
11 <div>
12 <h2 className="font-medium">{title}</h2>
13 <p className="mt-1 text-sm text-muted">{about}</p>
14 </div>
15 <div className="min-w-0 space-y-3">{children}</div>
16 </section>
17 );
18}
19
20/** A setting that is on or off, with what it means. */
21export function SettingToggle({ name, on, title, disabled, children }: { name: string; on: boolean; title: string; disabled?: boolean; children: ReactNode }) {
22 return (
23 <SwitchCard name={name} defaultChecked={on} title={title} disabled={disabled}>
24 {children}
25 </SwitchCard>
26 );
27}
28
29/** A setting chosen from a few numbers. */
30export function SettingChoice({
31 name,
32 value,
33 options,
34 title,
35 disabled,
36 children,
37}: {
38 name: string;
39 value: number;
40 options: [number, string][];
41 title: string;
42 disabled?: boolean;
43 children: ReactNode;
44}) {
45 return (
46 <Card className="flex items-start gap-4 p-4">
47 <div className="grow">
48 <p className="text-sm font-medium">{title}</p>
49 <p className="mt-1 text-sm text-muted">{children}</p>
50 </div>
51 <Select name={name} defaultValue={String(value)} disabled={disabled}>
52 <SelectTrigger size="sm" aria-label={title} className="w-auto min-w-28 shrink-0">
53 <SelectValue />
54 </SelectTrigger>
55 <SelectContent align="end">
56 {options.map(([option, label]) => (
57 <SelectItem key={option} value={String(option)}>
58 {label}
59 </SelectItem>
60 ))}
61 </SelectContent>
62 </Select>
63 </Card>
64 );
65}