File size: 2,101 Bytes
5f40163 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import { cn } from "#/utils/utils";
export type ToggleSwitchSize = "md" | "sm";
interface ToggleSwitchVisualProps {
enabled: boolean;
/** `sm` is the compact menu-row pill; `md` is the settings/automation switch. */
size?: ToggleSwitchSize;
className?: string;
}
/** Shared toggle track + thumb used by settings labels and automation controls. */
export function ToggleSwitchVisual({
enabled,
size = "md",
className,
}: ToggleSwitchVisualProps) {
const compact = size === "sm";
return (
<span
aria-hidden="true"
className={cn(
"relative inline-flex shrink-0 items-center rounded-full",
"transition-colors duration-200 ease-in-out motion-reduce:transition-none",
compact ? "h-3.5 w-6 p-[3px]" : "h-[22px] w-[40px] border",
enabled
? compact
? "bg-white"
: "border-white bg-white"
: compact
? "bg-[var(--oh-border)]"
: "border-[var(--oh-border)] bg-surface-raised",
className,
)}
>
<span
className={cn(
"inline-block rounded-full",
"transition-transform duration-200 ease-in-out motion-reduce:transition-none",
compact ? "size-2" : "size-4",
enabled
? compact
? "translate-x-[10px] bg-base-secondary"
: "translate-x-[21px] bg-base-secondary"
: compact
? "translate-x-0 bg-[var(--oh-muted)]"
: "translate-x-[2px] bg-[var(--oh-muted)]",
)}
/>
</span>
);
}
interface ToggleSwitchProps {
enabled: boolean;
label: string;
onToggle: () => void;
className?: string;
}
export function ToggleSwitch({
enabled,
label,
onToggle,
className,
}: ToggleSwitchProps) {
return (
<button
type="button"
role="switch"
aria-checked={enabled}
aria-label={label}
onClick={(e) => {
e.stopPropagation();
onToggle();
}}
className={cn("cursor-pointer", className)}
>
<ToggleSwitchVisual enabled={enabled} />
</button>
);
}
|