From 069269e69cb0e9683ee702bfb9810e21eebbf530 Mon Sep 17 00:00:00 2001 From: Maurice Date: Tue, 21 Apr 2026 22:03:20 +0200 Subject: [PATCH] fix: integrations settings squish on mobile (#812) + polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PhotoProvidersSection: - Replace raw with TREK's ToggleSwitch so the 'spiegeln zu Immich'-style options match the rest of the app. - Wrap action row in flex-wrap so the connected/disconnected badge drops to its own line on mobile instead of clipping. - Add a short 'Test' translation (memories.testShort) shown on mobile in place of 'Test connection' — 14 languages kept in sync. ToggleSwitch: - Explicit type='button' (never a form submitter), minWidth + flex- shrink:0 so the toggle doesn't get squished next to long labels, padding:0 so no inherited UA margin warps the inner circle. MapSettingsTab: - 'Mapbox' instead of 'Mapbox GL' on narrow screens — the provider card is too cramped on mobile for the full name. - Drop the 'Experimental' badge on mobile entirely; it overlapped the title at that width. Still shown on >=sm. DisplaySettingsTab: - Time format buttons show just '24h' / '12h' on mobile; the '(14:30)' / '(2:30 PM)' hint stays on >=sm. Test updated to match the role query since the label is now split across nodes. --- .../Settings/DisplaySettingsTab.test.tsx | 4 ++- .../Settings/DisplaySettingsTab.tsx | 7 +++--- .../components/Settings/MapSettingsTab.tsx | 14 +++++++---- .../Settings/PhotoProvidersSection.tsx | 25 +++++++++++-------- .../src/components/Settings/ToggleSwitch.tsx | 5 ++-- client/src/i18n/translations/ar.ts | 1 + client/src/i18n/translations/br.ts | 1 + client/src/i18n/translations/cs.ts | 1 + client/src/i18n/translations/de.ts | 1 + client/src/i18n/translations/en.ts | 1 + client/src/i18n/translations/es.ts | 1 + client/src/i18n/translations/fr.ts | 1 + client/src/i18n/translations/hu.ts | 1 + client/src/i18n/translations/id.ts | 1 + client/src/i18n/translations/it.ts | 1 + client/src/i18n/translations/nl.ts | 1 + client/src/i18n/translations/pl.ts | 1 + client/src/i18n/translations/ru.ts | 1 + client/src/i18n/translations/zh.ts | 1 + client/src/i18n/translations/zhTw.ts | 1 + 20 files changed, 48 insertions(+), 22 deletions(-) diff --git a/client/src/components/Settings/DisplaySettingsTab.test.tsx b/client/src/components/Settings/DisplaySettingsTab.test.tsx index 4c770e6c..d0ff467e 100644 --- a/client/src/components/Settings/DisplaySettingsTab.test.tsx +++ b/client/src/components/Settings/DisplaySettingsTab.test.tsx @@ -155,7 +155,9 @@ describe('DisplaySettingsTab', () => { const updateSetting = vi.fn().mockResolvedValue(undefined); seedStore(useSettingsStore, { settings: buildSettings({ time_format: '12h' }), updateSetting }); render(); - await user.click(screen.getByText('24h (14:30)')); + // The label is split across a text node ('24h') and a responsive span (' (14:30)'). + // Click the button that contains the 24h text instead of matching the full string. + await user.click(screen.getByRole('button', { name: /24h/ })); expect(updateSetting).toHaveBeenCalledWith('time_format', '24h'); }); diff --git a/client/src/components/Settings/DisplaySettingsTab.tsx b/client/src/components/Settings/DisplaySettingsTab.tsx index 0eaec1ca..575041f9 100644 --- a/client/src/components/Settings/DisplaySettingsTab.tsx +++ b/client/src/components/Settings/DisplaySettingsTab.tsx @@ -188,8 +188,8 @@ export default function DisplaySettingsTab(): React.ReactElement {
{[ - { value: '24h', label: '24h (14:30)' }, - { value: '12h', label: '12h (2:30 PM)' }, + { value: '24h', short: '24h', example: '14:30' }, + { value: '12h', short: '12h', example: '2:30 PM' }, ].map(opt => ( ))}
diff --git a/client/src/components/Settings/MapSettingsTab.tsx b/client/src/components/Settings/MapSettingsTab.tsx index 579973ae..d1bea396 100644 --- a/client/src/components/Settings/MapSettingsTab.tsx +++ b/client/src/components/Settings/MapSettingsTab.tsx @@ -240,14 +240,18 @@ export default function MapSettingsTab(): React.ReactElement { : 'border-slate-200 hover:border-slate-400 dark:border-slate-700' }`} > - - {t('settings.mapExperimental')} - -
-
Mapbox GL
+
+
+ Mapbox + Mapbox GL +
{t('settings.mapMapboxSubtitle')}
+ {/* Experimental badge only on ≥sm; on mobile there's no room next to the title. */} + + {t('settings.mapExperimental')} +

diff --git a/client/src/components/Settings/PhotoProvidersSection.tsx b/client/src/components/Settings/PhotoProvidersSection.tsx index 042d5e6a..bd1659a7 100644 --- a/client/src/components/Settings/PhotoProvidersSection.tsx +++ b/client/src/components/Settings/PhotoProvidersSection.tsx @@ -5,6 +5,7 @@ import { useToast } from '../../components/shared/Toast' import apiClient from '../../api/client' import { useAddonStore } from '../../store/addonStore' import Section from './Section' +import ToggleSwitch from './ToggleSwitch' interface ProviderField { key: string @@ -222,15 +223,13 @@ export default function PhotoProvidersSection(): React.ReactElement { {fields.map(field => (

{field.input_type === 'checkbox' ? ( -
))} -
+ {/* Wraps on mobile so the connection badge drops to its own row + instead of clipping off the side of the card. */} +
+ {/* On mobile the badge sits on its own row thanks to flex-wrap, so force a line break via basis-full. */} {connected ? ( - + {t('memories.connected')} ) : ( - + {t('memories.disconnected')} diff --git a/client/src/components/Settings/ToggleSwitch.tsx b/client/src/components/Settings/ToggleSwitch.tsx index 562d7238..b74e5513 100644 --- a/client/src/components/Settings/ToggleSwitch.tsx +++ b/client/src/components/Settings/ToggleSwitch.tsx @@ -2,9 +2,10 @@ import React from 'react' export default function ToggleSwitch({ on, onToggle }: { on: boolean; onToggle: () => void }) { return ( -