refactor(ui): shared form primitives (Switch, Section, SettingRow, HintLabel)

components/ui/form.tsx replaces the per-panel copies:
- Switch — was duplicated in SettingsPanel (Switch) + ConfigPanel (Toggle) +
  Sidebar (inline labeled toggle).
- Section (with a card variant) — was in SettingsPanel + Stats (plain) and
  AdminUsers (glass card).
- SettingRow + HintLabel — the label+hint+control row was identical in SettingsPanel + Stats.
No visual change intended (Sidebar's toggle gains the standard knob shadow).
This commit is contained in:
npeter83 2026-06-29 00:04:45 +02:00
parent 5fcd64c1e1
commit 53c75f69e2
6 changed files with 125 additions and 147 deletions

View file

@ -6,6 +6,7 @@ import { api, type ConfigItem } from "../lib/api";
import { notify } from "../lib/notifications";
import Tooltip from "./Tooltip";
import Tabs, { usePersistedTab } from "./Tabs";
import { Switch } from "./ui/form";
// Admin Configuration page: edit DB-overridable operational settings (registry-driven from the
// backend — adding a key there makes it appear here automatically). Edits are drafted and
@ -241,7 +242,7 @@ function Field({
<div className="flex flex-col items-end gap-1.5 shrink-0">
{isBool ? (
<Toggle checked={value === "true"} onChange={(v) => onChange(v ? "true" : "false")} />
<Switch checked={value === "true"} onChange={(v) => onChange(v ? "true" : "false")} />
) : (
<input
type={item.secret ? "password" : isNum ? "number" : "text"}
@ -272,20 +273,4 @@ function Field({
</div>
</div>
);
}
function Toggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) {
return (
<button
type="button"
onClick={() => onChange(!checked)}
className={`w-9 h-5 rounded-full transition relative shrink-0 ${checked ? "bg-accent" : "bg-border"}`}
>
<span
className={`absolute top-0.5 w-4 h-4 rounded-full bg-white shadow transition-all ${
checked ? "left-[18px]" : "left-0.5"
}`}
/>
</button>
);
}
}