flagon-io/g1t

public

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

g1t/apps/web/app/components/settings-section.tsx

89 lines2,194 bytesCodeBlame
1import type { ReactNode } from "react";
2
3import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
4import { SwitchCard } from "./ui/switch";
5
6/** A group of settings: its name and what it is for on the left, the settings on the right. */
7export function SettingsSection({
8 id,
9 title,
10 about,
11 children,
12}: {
13 id?: string;
14 title: string;
15 about: ReactNode;
16 children: ReactNode;
17}) {
18 return (
19 <section
20 id={id}
21 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]"
22 >
23 <div>
24 <h2 className="font-medium">{title}</h2>
25 <p className="mt-1 text-sm text-muted">{about}</p>
26 </div>
27 <div className="min-w-0 space-y-3">{children}</div>
28 </section>
29 );
30}
31
32/** A setting that is on or off, with what it means. */
33export function SettingToggle({
34 name,
35 on,
36 title,
37 disabled,
38 children,
39}: {
40 name: string;
41 on: boolean;
42 title: string;
43 disabled?: boolean;
44 children: ReactNode;
45}) {
46 return (
47 <SwitchCard name={name} defaultChecked={on} title={title} disabled={disabled}>
48 {children}
49 </SwitchCard>
50 );
51}
52
53/** A setting chosen from a few numbers. */
54export function SettingChoice({
55 name,
56 value,
57 options,
58 title,
59 disabled,
60 children,
61}: {
62 name: string;
63 value: number;
64 options: [number, string][];
65 title: string;
66 disabled?: boolean;
67 children: ReactNode;
68}) {
69 return (
70 <div className="flex items-start gap-4 rounded-xl border border-line bg-surface p-4">
71 <div className="grow">
72 <p className="text-sm font-medium">{title}</p>
73 <p className="mt-1 text-sm text-muted">{children}</p>
74 </div>
75 <Select name={name} defaultValue={String(value)} disabled={disabled}>
76 <SelectTrigger size="sm" aria-label={title} className="w-auto min-w-28 shrink-0">
77 <SelectValue />
78 </SelectTrigger>
79 <SelectContent align="end">
80 {options.map(([option, label]) => (
81 <SelectItem key={option} value={String(option)}>
82 {label}
83 </SelectItem>
84 ))}
85 </SelectContent>
86 </Select>
87 </div>
88 );
89}