From 44d653ffbdae1e843f55104994b45396c00ad85a Mon Sep 17 00:00:00 2001 From: Khalid Abdi Date: Tue, 14 Jul 2026 21:10:19 +0300 Subject: [PATCH] frontend: compose settings frames from CardFrame primitives SettingsFrame used a hand-rolled
body and SettingsCard was a plain div (no data-slot=card), so the frame's card styling never applied. - Add CardFramePanel (data-slot="card-frame-panel") as the padded frame body, mirroring the other CardFrame* subcomponents. - SettingsFrame now composes CardFrameHeader + CardFramePanel (same p-5 padding as before) instead of a raw div. - SettingsCard renders a real COSS Card (data-slot=card). Since Card is flex flex-col, the horizontal-row call sites (ToggleRow, billing and preferences rows) now pass flex-row. Co-Authored-By: Claude Opus 4.8 --- .../components/settings/settings-billing.tsx | 4 ++-- .../components/settings/settings-parts.tsx | 17 ++++++++-------- .../settings/settings-preferences.tsx | 2 +- frontend/components/ui/card.tsx | 20 +++++++++++++++++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/frontend/components/settings/settings-billing.tsx b/frontend/components/settings/settings-billing.tsx index e7aa4a7..41dec4b 100644 --- a/frontend/components/settings/settings-billing.tsx +++ b/frontend/components/settings/settings-billing.tsx @@ -176,7 +176,7 @@ export function SigningPanel() { description={t("settings.network.description")} title={t("settings.network.title")} > - +

@@ -251,7 +251,7 @@ export function SigningPanel() { description={t("settings.signing.backupDescription")} title={t("settings.signing.backupTitle")} > - +

{t("settings.signing.backupLabel")} diff --git a/frontend/components/settings/settings-parts.tsx b/frontend/components/settings/settings-parts.tsx index c349276..970ed96 100644 --- a/frontend/components/settings/settings-parts.tsx +++ b/frontend/components/settings/settings-parts.tsx @@ -5,12 +5,13 @@ import { useState } from "react"; import { Check, Copy } from "lucide-react"; import { useTranslation } from "react-i18next"; -import { cn } from "@/lib/utils"; import { + Card, CardFrame, CardFrameAction, CardFrameDescription, CardFrameHeader, + CardFramePanel, CardFrameTitle, } from "@/components/ui/card"; import { Switch } from "@/components/ui/switch"; @@ -43,7 +44,7 @@ export function SettingsFrame({ ) : null} {action ? {action} : null} -

{children}
+ {children} ); } @@ -74,6 +75,10 @@ export function SettingsSection({ ); } +// A card surface used inside settings panels. Rendering a real COSS `Card` (with +// `data-slot="card"`) keeps settings cards consistent with the rest of the app +// and lets them pick up the frame's card treatment. `Card` is `flex flex-col`, +// so row layouts must pass `flex-row` in their className. export function SettingsCard({ className, children, @@ -81,11 +86,7 @@ export function SettingsCard({ className?: string; children: ReactNode; }) { - return ( -
- {children} -
- ); + return {children}; } export function ToggleRow({ @@ -103,7 +104,7 @@ export function ToggleRow({ onCheckedChange?: (checked: boolean) => void; }) { return ( - +

{title}

{description ? ( diff --git a/frontend/components/settings/settings-preferences.tsx b/frontend/components/settings/settings-preferences.tsx index cb4d94b..8fc8b85 100644 --- a/frontend/components/settings/settings-preferences.tsx +++ b/frontend/components/settings/settings-preferences.tsx @@ -375,7 +375,7 @@ export function ProfilePanel() { description={t("settings.profile.dangerZoneDescription")} title={t("settings.profile.dangerZone")} > - +

{t("settings.profile.deleteAccount")} diff --git a/frontend/components/ui/card.tsx b/frontend/components/ui/card.tsx index 260be33..e0b9be7 100644 --- a/frontend/components/ui/card.tsx +++ b/frontend/components/ui/card.tsx @@ -136,6 +136,26 @@ export function CardFrameFooter({ }); } +// The padded body of a frame: content that sits between the frame header and +// footer. Mirrors the other CardFrame* subcomponents (useRender + data-slot) so +// a frame can be composed entirely from primitives instead of a raw

. +export function CardFramePanel({ + className, + render, + ...props +}: useRender.ComponentProps<"div">): React.ReactElement { + const defaultProps = { + className: cn("p-5", className), + "data-slot": "card-frame-panel", + }; + + return useRender({ + defaultTagName: "div", + props: mergeProps<"div">(defaultProps, props), + render, + }); +} + export function CardHeader({ className, render,