"use client";
import { useI18n } from "@/components/i18n";
/**
* Thin settings primitives (settings-app wave): the control kit the
* settings dialog needs. Sections → groups → rows; everything SSRs clean
* (render tests pin the sections' markup).
*
* The dependency graying (owner, 2026-09-20) follows the graph viewer's
* render-panel convention: the WHOLE row dims (opacity-40, label and
* control together) and the control itself locks — the row owns the dim.
*/
import { useState, type ComponentPropsWithRef, type ReactNode } from "react";
import { cn } from "@/lib/utils";
/** A section block: pronounced mono heading + content. */
export function SettingsSection({
title,
hint,
children,
testid,
}: {
title: string;
/** One quiet line under the header — only where it earns its place. */
hint?: string;
children: React.ReactNode;
testid?: string;
}) {
const { t } = useI18n();
return (
{t(title)}
{hint &&
{t(hint)}
}
{children}
);
}
/** A labeled sub-group inside a section (owner, 2026-09-20: clear
* separation — Models / Tools / Prompts read as three blocks). */
export function SettingsGroup({
label,
children,
testid,
}: {
label: string;
children: React.ReactNode;
testid?: string;
}) {
const { t } = useI18n();
return (
{t(label)}
{children}
);
}
/** One label + one control. Label left (with optional muted hint), control
* right — the settings row shape. */
export function SettingsRow({
label,
hint,
children,
testid,
dimmed,
className,
}: {
label: string;
hint?: ReactNode;
children: React.ReactNode;
testid?: string;
/** Dependency graying, graph-view style: the whole row dims when the
* control is inert (parent off, no file yet, …). */
dimmed?: boolean;
className?: string;
}) {
const { t } = useI18n();
return (