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/ui/switch.tsx

66 lines2,546 bytesCodeBlame
1import { Switch as Primitive } from "radix-ui";
2import { type ComponentProps, type ReactNode, useId } from "react";
3
4import { cn } from "../../lib/cn";
5
6// shadcn/ui's switch, styled with g1t's tokens. Like a checkbox, inside a
7// <Form> a `name` posts `value` (default "on") when on and nothing when off.
8
9export function Switch({
10 className,
11 size = "default",
12 ...props
13}: ComponentProps<typeof Primitive.Root> & { size?: "sm" | "default" }) {
14 return (
15 <Primitive.Root
16 data-size={size}
17 className={cn(
18 "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent p-px outline-none transition-colors",
19 "data-[size=default]:h-5 data-[size=default]:w-9 data-[size=sm]:h-4 data-[size=sm]:w-7",
20 "bg-line-strong data-[state=checked]:bg-accent",
21 "focus-visible:ring-2 focus-visible:ring-accent/40 focus-visible:ring-offset-1 focus-visible:ring-offset-bg focus-visible:outline-none",
22 "disabled:cursor-not-allowed disabled:opacity-50",
23 className,
24 )}
25 {...props}
26 >
27 <Primitive.Thumb
28 className={cn(
29 "pointer-events-none block rounded-full bg-fg shadow-sm ring-0 transition-transform duration-200",
30 "group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3",
31 "data-[state=unchecked]:translate-x-0 group-data-[size=default]/switch:data-[state=checked]:translate-x-4 group-data-[size=sm]/switch:data-[state=checked]:translate-x-3",
32 )}
33 />
34 </Primitive.Root>
35 );
36}
37
38/**
39 * A setting that is on or off, as a card: a title, what it means, and the
40 * switch. The whole card toggles it.
41 */
42export function SwitchCard({
43 title,
44 children,
45 className,
46 ...props
47}: ComponentProps<typeof Primitive.Root> & { title: ReactNode; children?: ReactNode }) {
48 const generated = useId();
49 const id = props.id ?? generated;
50 return (
51 <label
52 htmlFor={id}
53 className={cn(
54 "flex cursor-pointer items-start justify-between gap-4 rounded-xl border border-line bg-surface p-4 transition-colors hover:border-line-strong",
55 "has-[[data-state=checked]]:border-accent/40 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-60",
56 className,
57 )}
58 >
59 <span className="min-w-0">
60 <span className="block text-sm font-medium text-fg">{title}</span>
61 {children && <span className="mt-1 block text-sm text-muted">{children}</span>}
62 </span>
63 <Switch id={id} className="mt-0.5" {...props} />
64 </label>
65 );
66}