fix(app): preserve host badge identity
Keep host badges visible under row pressure and apply the selected host color consistently to the icon, label, and tinted background.
This commit is contained in:
@@ -1,13 +1,32 @@
|
||||
import { Text, View } from "react-native";
|
||||
import { Text, View, type TextStyle, type ViewStyle } from "react-native";
|
||||
import { StyleSheet, withUnistyles } from "react-native-unistyles";
|
||||
import { Server } from "lucide-react-native";
|
||||
import { HOST_COLORS, type HostColor } from "@/hosts/appearance";
|
||||
import { identityColor } from "@/styles/identity-colors";
|
||||
import { identityColor, identityTint } from "@/styles/identity-colors";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
|
||||
const ThemedServer = withUnistyles(Server);
|
||||
const MAX_NAMED_BADGE_WIDTH = 96;
|
||||
|
||||
interface HostBadgeColorOverride {
|
||||
badge: ViewStyle | null;
|
||||
text: TextStyle | null;
|
||||
}
|
||||
|
||||
function buildColorOverrides(): Record<HostColor, HostBadgeColorOverride> {
|
||||
const byColor = {} as Record<HostColor, HostBadgeColorOverride>;
|
||||
for (const color of HOST_COLORS) {
|
||||
byColor[color] =
|
||||
color === "none"
|
||||
? { badge: null, text: null }
|
||||
: {
|
||||
badge: { backgroundColor: identityTint(color) },
|
||||
text: { color: identityColor(color) },
|
||||
};
|
||||
}
|
||||
return byColor;
|
||||
}
|
||||
|
||||
// The identity table is theme-independent, so its icon mapping is fixed for the life of the
|
||||
// module. It must not be rebuilt per render: a fresh `uniProps` identity makes withUnistyles
|
||||
// re-subscribe every pass.
|
||||
@@ -22,6 +41,7 @@ function buildIconMappings(): Record<HostColor, (theme: Theme) => { color: strin
|
||||
return byColor;
|
||||
}
|
||||
|
||||
const COLOR_OVERRIDES = buildColorOverrides();
|
||||
const ICON_MAPPINGS = buildIconMappings();
|
||||
|
||||
/**
|
||||
@@ -41,14 +61,19 @@ export function HostBadge({
|
||||
color: HostColor;
|
||||
showLabel: boolean;
|
||||
}) {
|
||||
const override = COLOR_OVERRIDES[color];
|
||||
return (
|
||||
<View
|
||||
style={[hostBadgeStyles.badge, showLabel ? null : hostBadgeStyles.badgeIconOnly]}
|
||||
style={[
|
||||
hostBadgeStyles.badge,
|
||||
showLabel ? null : hostBadgeStyles.badgeIconOnly,
|
||||
override.badge,
|
||||
]}
|
||||
testID={`sidebar-host-badge-${serverId}`}
|
||||
>
|
||||
<ThemedServer size={9} uniProps={ICON_MAPPINGS[color]} />
|
||||
{showLabel ? (
|
||||
<Text style={hostBadgeStyles.text} numberOfLines={1}>
|
||||
<Text style={[hostBadgeStyles.text, override.text]} numberOfLines={1}>
|
||||
{label}
|
||||
</Text>
|
||||
) : null}
|
||||
@@ -71,7 +96,7 @@ const hostBadgeStyles = StyleSheet.create((theme) => ({
|
||||
backgroundColor: theme.colors.surface2,
|
||||
maxWidth: MAX_NAMED_BADGE_WIDTH,
|
||||
minWidth: 0,
|
||||
flexShrink: 1,
|
||||
flexShrink: 0,
|
||||
},
|
||||
// Icon-only drops the label, so the asymmetric padding that made room for text leaves a
|
||||
// lopsided pill. Symmetric padding recenters the icon.
|
||||
|
||||
Reference in New Issue
Block a user