chore(settings,admin): consolidate Withings credentials, SettingsToggle stacking, and feedback tabs

v1.4.27 MB7 — four settings/admin polish items in one commit:

- CF-53: the Withings credentials grid drops from a 3-column row
  (client-id / secret / save) to a 2-column row of inputs with the
  Save button lifted into its own row below. The previous invisible-
  label hack collided on Galaxy Fold; the new row places the Save
  button at `justify-end` on every viewport and fills the column
  on `<sm`.
- CF-55: the feedback-inbox TabsList wraps in an `overflow-x-auto`
  strip so the 4 status pills + count badges scroll horizontally on
  Pixel 5 instead of squashing below the legibility floor.
- CF-56: the shared `SettingsToggle` row stacks vertically on `<sm`
  so the German description copy doesn't compete with the switch for
  horizontal space. The inline duplicate in
  `general-settings-section.tsx` (default-language row) picks up
  the same contract.
- CF-57: the integrations action row floors each button to a
  `min-w-[10rem]` on `<sm` so the four AlertDialog + test-connection
  triggers stack two per row at most and fill their column cleanly.
This commit is contained in:
Marc-André Bombeck committed 2026-05-15 19:19:14 +02:00
1 parent e1451f840f
commit ab4529fcb3
4 files changed
+74 -42

No files matched your search

+12 -4
View File
@@ -195,11 +195,18 @@ export function SettingsToggle({
onCheckedChange: (checked: boolean) => void;
disabled: boolean;
}) {
// v1.4.27 MB7 / CF-56 — stack the toggle row vertically on `<sm` so
// the label + description don't have to compete with the switch for
// horizontal space on Pixel 5 (the German "Registration enabled — …"
// description used to wrap to 4 lines while the switch ate ~52 px on
// the right). At `sm:` the original side-by-side layout returns.
// The switch self-aligns to the right via `self-end` on the stacked
// branch so it stays a familiar tap target.
return (
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
{Icon && <Icon className="text-muted-foreground h-4 w-4" />}
<div>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
<div className="flex min-w-0 items-center gap-2">
{Icon && <Icon className="text-muted-foreground h-4 w-4 shrink-0" />}
<div className="min-w-0">
<p className="text-sm font-medium">{label}</p>
{description && (
<p className="text-muted-foreground text-xs">{description}</p>
@@ -210,6 +217,7 @@ export function SettingsToggle({
checked={checked}
onCheckedChange={onCheckedChange}
disabled={disabled}
className="self-end sm:self-auto"
/>
</div>
);
+22 -14
View File
@@ -85,20 +85,28 @@ export function FeedbackInboxSection() {
onValueChange={(v) => setActiveStatus(v as FeedbackStatusType)}
className="mt-4"
>
<TabsList>
{FEEDBACK_STATUS_TABS.map((s) => (
<TabsTrigger key={s} value={s}>
<span>
{t(
`admin.feedback.tab${s.charAt(0) + s.slice(1).toLowerCase()}`,
)}
</span>
<Badge variant="secondary" className="ml-1.5 text-xs">
{counts[s] ?? 0}
</Badge>
</TabsTrigger>
))}
</TabsList>
{/* v1.4.27 MB7 / CF-55 — wrap the TabsList in an
overflow-x-auto strip so the 4 status pills + their count
badges scroll horizontally on Pixel 5 / Galaxy Fold
instead of squashing the badge text below the legibility
floor. Hide the scrollbar visually but keep the gesture
working (matches the Insights tab-strip pattern). */}
<div className="-mx-1 overflow-x-auto px-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
<TabsList>
{FEEDBACK_STATUS_TABS.map((s) => (
<TabsTrigger key={s} value={s}>
<span>
{t(
`admin.feedback.tab${s.charAt(0) + s.slice(1).toLowerCase()}`,
)}
</span>
<Badge variant="secondary" className="ml-1.5 text-xs">
{counts[s] ?? 0}
</Badge>
</TabsTrigger>
))}
</TabsList>
</div>
{FEEDBACK_STATUS_TABS.map((s) => (
<TabsContent key={s} value={s} className="mt-4">
@@ -41,8 +41,10 @@ export function GeneralSettingsSection() {
disabled={updateSettings.isPending}
/>
<div className="flex items-center justify-between">
<div>
{/* v1.4.27 MB7 / CF-56 — match the SettingsToggle stacking
contract: stack on `<sm`, side-by-side on `sm+`. */}
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0">
<p className="text-sm font-medium">{t("admin.defaultLanguage")}</p>
<p className="text-muted-foreground text-xs">
{t("admin.defaultLanguageDescription")}
@@ -54,7 +56,7 @@ export function GeneralSettingsSection() {
updateSettings.mutate({ defaultLocale: e.target.value })
}
disabled={updateSettings.isPending}
className="w-auto"
className="self-end sm:w-auto sm:self-auto"
>
<option value="de">Deutsch</option>
<option value="en">English</option>