authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-17 20:19:07-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-17 20:19:07-07:00
loga1390ac655927cda10cfab3e4678d456db7b54b8
tree992ae8dbd0ab666c9ba91c6072667d62c194580c
parent05a8c6016a4070b92f5d51e7a79b9c76814947df
signature Signed by PGP key B5690EEEBB952194

fix(mobile): share settings control row layout (#12356)


3 files changed, 61 insertions(+), 49 deletions(-)

apps/mobile/src/features/settings/SettingsServerControlsRouteScreen.tsx+9-8
......@@ -22,6 +22,7 @@ import {
2222 SettingsEnvironmentFilterHeader,
2323} from "./components/SettingsEnvironmentFilterHeader";
2424import { SettingsSection } from "./components/SettingsSection";
25import { SettingsControlRow } from "./components/SettingsControlRow";
2526import { SettingsSwitchRow } from "./components/SettingsSwitchRow";
2627import { SettingsProjectOverridesSection } from "./components/SettingsProjectOverridesSection";
2728import { useSettingsEnvironmentFilter } from "./settings-environment-filter";
......@@ -454,21 +455,21 @@ function FanoutSwitchRow(props: {
454455 }
455456
456457 return (
457 <View className="flex-row items-center gap-4 p-4">
458 <SymbolView name={props.icon} size={22} tintColorClassName="accent-icon" />
459 <View className="min-w-0 flex-1 gap-1">
460 <Text className="text-lg text-foreground">{props.label}</Text>
461 <Text className="text-sm text-foreground-muted">{props.subtitle}</Text>
462 </View>
458 <SettingsControlRow
459 disabled={props.disabled}
460 icon={props.icon}
461 label={props.label}
462 subtitle={props.subtitle}
463 >
463464 <Pressable
464465 accessibilityLabel={`Set ${props.label} on for selected environments`}
465466 accessibilityRole="button"
466467 disabled={props.disabled}
467 className="rounded-full bg-subtle px-3 py-2 active:opacity-70 disabled:opacity-40"
468 className="rounded-full bg-subtle px-3 py-2 active:opacity-70"
468469 onPress={() => props.onValueChange(true)}
469470 >
470471 <Text className="text-sm font-t3-medium text-foreground">Mixed · Set on</Text>
471472 </Pressable>
472 </View>
473 </SettingsControlRow>
473474 );
474475}
apps/mobile/src/features/settings/components/SettingsControlRow.tsx created+39
......@@ -0,0 +1,39 @@
1import type { ComponentProps, ReactNode } from "react";
2import { Platform, View } from "react-native";
3
4import { SymbolView } from "../../../components/AppSymbol";
5import { AppText as Text } from "../../../components/AppText";
6import { cn } from "../../../lib/cn";
7
8export function SettingsControlRow(props: {
9 readonly disabled?: boolean;
10 readonly icon: ComponentProps<typeof SymbolView>["name"];
11 readonly label: string;
12 readonly subtitle?: string;
13 readonly children: ReactNode;
14}) {
15 return (
16 <View
17 className={cn(
18 "flex-row items-center gap-4 p-4 android:min-h-14 android:py-3",
19 props.subtitle && "android:min-h-18",
20 props.disabled && "opacity-[0.45]",
21 )}
22 >
23 <SymbolView
24 name={props.icon}
25 size={Platform.OS === "android" ? 24 : 22}
26 tintColorClassName="accent-icon"
27 type="monochrome"
28 weight="regular"
29 />
30 <View className="min-w-0 flex-1 android:gap-1">
31 <Text className="text-lg text-foreground android:text-base">{props.label}</Text>
32 {props.subtitle ? (
33 <Text className="text-sm text-foreground-muted">{props.subtitle}</Text>
34 ) : null}
35 </View>
36 {props.children}
37 </View>
38 );
39}
apps/mobile/src/features/settings/components/SettingsSwitchRow.tsx+13-41
......@@ -1,55 +1,27 @@
1import { cn } from "../../../lib/cn";
21import type { ComponentProps } from "react";
3import { Platform, View } from "react-native";
42
5import { SymbolView } from "../../../components/AppSymbol";
6import { AppText as Text } from "../../../components/AppText";
73import { ThemedSwitch } from "../../../components/ThemedSwitch";
4import { SettingsControlRow } from "./SettingsControlRow";
85
9type SymbolName = ComponentProps<typeof SymbolView>["name"];
10
11export function SettingsSwitchRow(props: {
12 readonly disabled?: boolean;
13 readonly icon: SymbolName;
14 readonly label: string;
15 readonly subtitle?: string;
16 readonly value: boolean;
17 readonly onValueChange: (value: boolean) => void;
18}) {
6export function SettingsSwitchRow(
7 props: Omit<ComponentProps<typeof SettingsControlRow>, "children"> & {
8 readonly value: boolean;
9 readonly onValueChange: (value: boolean) => void;
10 },
11) {
1912 return (
20 <View
21 className={cn(
22 "flex-row items-center gap-4",
23 Platform.OS === "android" ? "min-h-14 px-4 py-3" : "p-4",
24 Platform.OS === "android" && props.subtitle && "min-h-18",
25 props.disabled && "opacity-[0.45]",
26 )}
13 <SettingsControlRow
14 disabled={props.disabled}
15 icon={props.icon}
16 label={props.label}
17 subtitle={props.subtitle}
2718 >
28 <SymbolView
29 name={props.icon}
30 size={Platform.OS === "android" ? 24 : 22}
31 tintColorClassName="accent-icon"
32 type="monochrome"
33 weight="regular"
34 />
35 <View className={cn("min-w-0 flex-1", Platform.OS === "android" && "gap-1")}>
36 <Text
37 className={
38 Platform.OS === "android" ? "text-base text-foreground" : "text-lg text-foreground"
39 }
40 >
41 {props.label}
42 </Text>
43 {props.subtitle ? (
44 <Text className="text-sm text-foreground-muted">{props.subtitle}</Text>
45 ) : null}
46 </View>
4719 <ThemedSwitch
4820 accessibilityLabel={props.label}
4921 disabled={props.disabled}
5022 onValueChange={props.onValueChange}
5123 value={props.value}
5224 />
53 </View>
25 </SettingsControlRow>
5426 );
5527}