fix(settings): align host switcher with sidebar rows
The host picker reused the composer trigger's content-width pill, so its label sat 6px left of the section rows and the chevron hugged the label instead of the trailing edge. Add a `block` mode to ComboboxTrigger that fills the width and uses the sidebar-row gap, and size the status dot to the icon footprint so the label and chevron line up with the rows below.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { forwardRef, useCallback, type ReactElement, type ReactNode } from "react";
|
import { forwardRef, useCallback, useMemo, type ReactElement, type ReactNode } from "react";
|
||||||
import {
|
import {
|
||||||
Pressable,
|
Pressable,
|
||||||
View,
|
View,
|
||||||
@@ -28,10 +28,15 @@ interface ComboboxTriggerProps extends Omit<PressableProps, "style" | "children"
|
|||||||
style?: TriggerStyleProp;
|
style?: TriggerStyleProp;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
chevron?: ReactNode | null;
|
chevron?: ReactNode | null;
|
||||||
|
// Fill the Pressable's width and use the standard sidebar-row gap, so the
|
||||||
|
// trigger reads as a full-width row: the label expands and the chevron pins to
|
||||||
|
// the trailing edge. Default (false) keeps the content-width pill used by the
|
||||||
|
// composer triggers.
|
||||||
|
block?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ComboboxTrigger = forwardRef<View, ComboboxTriggerProps>(function ComboboxTrigger(
|
export const ComboboxTrigger = forwardRef<View, ComboboxTriggerProps>(function ComboboxTrigger(
|
||||||
{ children, chevron, style, ...props },
|
{ children, chevron, style, block = false, ...props },
|
||||||
ref,
|
ref,
|
||||||
): ReactElement {
|
): ReactElement {
|
||||||
const pressableStyle = useCallback(
|
const pressableStyle = useCallback(
|
||||||
@@ -44,9 +49,11 @@ export const ComboboxTrigger = forwardRef<View, ComboboxTriggerProps>(function C
|
|||||||
[style],
|
[style],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const rowStyle = useMemo(() => [styles.row, block && styles.rowBlock], [block]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable ref={ref} collapsable={false} style={pressableStyle} {...props}>
|
<Pressable ref={ref} collapsable={false} style={pressableStyle} {...props}>
|
||||||
<View style={styles.row}>
|
<View style={rowStyle}>
|
||||||
{children}
|
{children}
|
||||||
{chevron !== null &&
|
{chevron !== null &&
|
||||||
(chevron ?? (
|
(chevron ?? (
|
||||||
@@ -68,6 +75,10 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: theme.spacing[1],
|
gap: theme.spacing[1],
|
||||||
},
|
},
|
||||||
|
rowBlock: {
|
||||||
|
flexGrow: 1,
|
||||||
|
gap: theme.spacing[2],
|
||||||
|
},
|
||||||
chevronContainer: {
|
chevronContainer: {
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
transform: [{ translateY: 1 }],
|
transform: [{ translateY: 1 }],
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ import { AppDiagnosticSheet } from "@/components/app-diagnostic-sheet";
|
|||||||
import { ComboboxTrigger } from "@/components/ui/combobox-trigger";
|
import { ComboboxTrigger } from "@/components/ui/combobox-trigger";
|
||||||
import { SidebarHeaderRow } from "@/components/sidebar/sidebar-header-row";
|
import { SidebarHeaderRow } from "@/components/sidebar/sidebar-header-row";
|
||||||
import { SidebarSeparator } from "@/components/sidebar/sidebar-separator";
|
import { SidebarSeparator } from "@/components/sidebar/sidebar-separator";
|
||||||
import { HostPicker as SharedHostPicker, HostStatusDotSlot } from "@/components/hosts/host-picker";
|
import { HostPicker as SharedHostPicker } from "@/components/hosts/host-picker";
|
||||||
|
import { HostStatusDot } from "@/components/host-status-dot";
|
||||||
import { ScreenTitle } from "@/components/headers/screen-title";
|
import { ScreenTitle } from "@/components/headers/screen-title";
|
||||||
import { HeaderIconBadge } from "@/components/headers/header-icon-badge";
|
import { HeaderIconBadge } from "@/components/headers/header-icon-badge";
|
||||||
import { SettingsSection } from "@/screens/settings/settings-section";
|
import { SettingsSection } from "@/screens/settings/settings-section";
|
||||||
@@ -938,13 +939,18 @@ function HostPicker({ activeServerId, sortedHosts, onSelectHost, onAddHost }: Ho
|
|||||||
>
|
>
|
||||||
<ComboboxTrigger
|
<ComboboxTrigger
|
||||||
ref={triggerRef}
|
ref={triggerRef}
|
||||||
|
block
|
||||||
style={triggerStyle}
|
style={triggerStyle}
|
||||||
onPress={handleOpen}
|
onPress={handleOpen}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={t("settings.hostPicker.switchHost")}
|
accessibilityLabel={t("settings.hostPicker.switchHost")}
|
||||||
testID="settings-host-picker"
|
testID="settings-host-picker"
|
||||||
>
|
>
|
||||||
{activeHost ? <HostStatusDotSlot serverId={activeHost.serverId} /> : null}
|
{activeHost ? (
|
||||||
|
<View style={sidebarStyles.pickerTriggerDot}>
|
||||||
|
<HostStatusDot serverId={activeHost.serverId} />
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
<Text style={sidebarStyles.pickerTriggerLabel} numberOfLines={1}>
|
<Text style={sidebarStyles.pickerTriggerLabel} numberOfLines={1}>
|
||||||
{activeHost?.label ?? t("settings.groups.host")}
|
{activeHost?.label ?? t("settings.groups.host")}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -1708,4 +1714,11 @@ const sidebarStyles = StyleSheet.create((theme) => ({
|
|||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
fontWeight: theme.fontWeight.normal,
|
fontWeight: theme.fontWeight.normal,
|
||||||
},
|
},
|
||||||
|
// Match the setting items' icon footprint so the host label aligns with them.
|
||||||
|
pickerTriggerDot: {
|
||||||
|
width: theme.iconSize.md,
|
||||||
|
height: theme.iconSize.md,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user