import React from "react"; import * as SelectPrimitive from "@radix-ui/react-select"; import { Check, ChevronDown, ChevronUp } from "lucide-react"; import { settingsAnchorDomId } from "../../domain/settingsSearchCatalog"; import { cn } from "../../lib/utils"; import { TabsContent } from "../ui/tabs"; interface ToggleProps { checked: boolean; onChange: (checked: boolean) => void; disabled?: boolean; ariaLabel?: string; } export const Toggle: React.FC = ({ checked, onChange, disabled, ariaLabel }) => ( ); interface SelectProps { value: string; options: { value: string; label: string; icon?: React.ReactNode }[]; onChange: (value: string) => void; className?: string; disabled?: boolean; placeholder?: string; } export const Select: React.FC = ({ value, options, onChange, className, disabled, placeholder, }) => { const selectedOption = options.find((opt) => opt.value === value); const fitSelectedText = typeof className !== "string" || !className.includes("w-full"); return ( span]:min-w-0 [&>span]:truncate [&>span]:whitespace-nowrap", fitSelectedText && "min-w-max", className, )} > {selectedOption?.icon} {selectedOption?.label} {options.map((opt) => ( {opt.icon} {opt.label} ))} ); }; export const SectionHeader: React.FC<{ title: string; className?: string; anchorId?: string; }> = ({ title, className, anchorId }) => (

{title}

); /** Section title row → content gap (shared across settings pages). */ export const settingsSectionGapClassName = "gap-2"; /** Groups a section title (optional icon/actions) with its content at a uniform gap. */ export const SettingsSection: React.FC<{ title?: string; leading?: React.ReactNode; actions?: React.ReactNode; children: React.ReactNode; className?: string; anchorId?: string; }> = ({ title, leading, actions, children, className, anchorId }) => (
{(title || leading || actions) && (
{leading} {title ?

{title}

: null}
{actions ?
{actions}
: null}
)} {children}
); /** Footer note under a SettingCard. Keep a gap so it does not kiss the card. */ export const settingHintClassName = "mt-3 text-xs text-muted-foreground"; export const SettingHint: React.FC<{ children: React.ReactNode; className?: string; }> = ({ children, className }) => (

{children}

); export const settingCardClassName = "rounded-lg border bg-card"; interface SettingCardProps { children: React.ReactNode; className?: string; /** Row list with dividers; vertical spacing comes from SettingRow. */ divided?: boolean; /** Free-form content; apply even padding on all sides. */ padded?: boolean; } export const SettingCard: React.FC = ({ children, className, divided = false, padded = false, }) => (
{children}
); interface SettingRowProps { label?: string; description?: string; children: React.ReactNode; align?: "center" | "start"; /** Stable catalog id for settings search jump targets. */ anchorId?: string; } export const SettingRow: React.FC = ({ label, description, children, align = "center", anchorId, }) => (
{label &&
{label}
} {description && (
{description}
)}
{children}
); /** Lightweight wrapper for non-SettingRow search targets. */ export const SettingsAnchor: React.FC<{ anchorId: string; className?: string; children: React.ReactNode; }> = ({ anchorId, className, children }) => (
{children}
); export const SettingsTabContent: React.FC<{ value: string; children: React.ReactNode; }> = ({ value, children }) => ( {/* data-settings-scroll-pane: search jump scrolls only this pane, not the window */}
{children}
);