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