mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
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:
1 parent
e1451f840f
commit
ab4529fcb3
4 files changed
+74
-42
No files matched your search
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -389,7 +389,16 @@ function WithingsCard({
|
||||
{t("settings.withingsCredentials")}
|
||||
</h3>
|
||||
<form onSubmit={handleSaveCredentials} className="space-y-3">
|
||||
<div className="grid gap-3 sm:grid-cols-3">
|
||||
{/* v1.4.27 MB7 / CF-53 — the credentials grid drops from
|
||||
a 3-column row (client-id / secret / save) to a
|
||||
2-column row of inputs at `sm:`, with the Save button
|
||||
lifted out into its own row below. The previous
|
||||
"invisible Label" hack to align the button with the
|
||||
input baselines fell apart on Galaxy Fold; lifting
|
||||
the button into a dedicated `flex justify-end` row
|
||||
gives it consistent placement on every viewport and
|
||||
lets the input pair span the full width. */}
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="w-clientid">
|
||||
{t("settings.withingsClientId")}
|
||||
@@ -432,25 +441,24 @@ function WithingsCard({
|
||||
enterKeyHint="done"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label className="invisible">{t("common.save")}</Label>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-9 w-full"
|
||||
disabled={
|
||||
credsSaving || !clientId.trim() || !clientSecret.trim()
|
||||
}
|
||||
>
|
||||
{credsSaving ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<Save className="mr-1 h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("settings.withingsSaveCredentials")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-full sm:w-auto"
|
||||
disabled={
|
||||
credsSaving || !clientId.trim() || !clientSecret.trim()
|
||||
}
|
||||
>
|
||||
{credsSaving ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<Save className="mr-1 h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("settings.withingsSaveCredentials")}
|
||||
</Button>
|
||||
</div>
|
||||
{credsMsg && (
|
||||
<p
|
||||
@@ -465,7 +473,13 @@ function WithingsCard({
|
||||
|
||||
{status?.connected ? (
|
||||
<>
|
||||
<div className="flex flex-wrap items-start gap-2">
|
||||
{/* v1.4.27 MB7 / CF-57 — the action row already wraps via
|
||||
`flex-wrap`, but on Pixel 5 the four AlertDialog +
|
||||
test-connection triggers each took a fractional slot
|
||||
that read jagged. Force each button to a `min-w-[10rem]`
|
||||
on `<sm` so they stack two per row at most and fill
|
||||
their column cleanly. Tablet+ keeps the inline row. */}
|
||||
<div className="flex flex-wrap items-start gap-2 [&>*]:min-w-[10rem] sm:[&>*]:min-w-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
|
||||
Reference in new issue
Block a user