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:
parent
5fcd64c1e1
commit
53c75f69e2
6 changed files with 125 additions and 147 deletions
|
|
@ -6,6 +6,7 @@ import { api, type AdminUserRow, type Invite, type Me } from "../lib/api";
|
|||
import { notify } from "../lib/notifications";
|
||||
import { LS } from "../lib/storage";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { Section } from "./ui/form";
|
||||
import { useConfirm } from "./ConfirmProvider";
|
||||
import Tabs, { usePersistedTab } from "./Tabs";
|
||||
|
||||
|
|
@ -41,15 +42,6 @@ export default function AdminUsers({ me }: { me: Me }) {
|
|||
);
|
||||
}
|
||||
|
||||
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="glass rounded-2xl p-4 mb-4">
|
||||
<div className="text-xs uppercase tracking-wide text-muted mb-3">{title}</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Badge({ tone, children }: { tone: "accent" | "muted" | "warning"; children: React.ReactNode }) {
|
||||
const cls =
|
||||
tone === "accent"
|
||||
|
|
@ -138,7 +130,7 @@ function UsersRoles({ me }: { me: Me }) {
|
|||
const rows = q.data ?? [];
|
||||
|
||||
return (
|
||||
<Section title={t("users.roles.title")}>
|
||||
<Section card title={t("users.roles.title")}>
|
||||
<p className="text-xs text-muted leading-relaxed mb-3">{t("users.roles.intro")}</p>
|
||||
{rows.length === 0 ? (
|
||||
<p className="text-sm text-muted">{t("users.roles.empty")}</p>
|
||||
|
|
@ -266,7 +258,7 @@ function AdminInvites() {
|
|||
const decided = list.filter((i) => i.status !== "pending");
|
||||
|
||||
return (
|
||||
<Section title={t("settings.invites.title")}>
|
||||
<Section card title={t("settings.invites.title")}>
|
||||
{pending.length === 0 ? (
|
||||
<p className="text-sm text-muted">{t("settings.invites.noPending")}</p>
|
||||
) : (
|
||||
|
|
@ -360,7 +352,7 @@ function AdminDemo() {
|
|||
const rows = list.data ?? [];
|
||||
|
||||
return (
|
||||
<Section title={t("settings.demo.title")}>
|
||||
<Section card title={t("settings.demo.title")}>
|
||||
<p className="text-xs text-muted leading-relaxed mb-2">{t("settings.demo.intro")}</p>
|
||||
|
||||
{rows.length > 0 && (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue