diff --git a/packages/app/src/components/left-sidebar.tsx b/packages/app/src/components/left-sidebar.tsx
index f054668347..943c1edd27 100644
--- a/packages/app/src/components/left-sidebar.tsx
+++ b/packages/app/src/components/left-sidebar.tsx
@@ -32,6 +32,7 @@ import { HostPicker } from "@/components/hosts/host-picker";
import { SidebarDisplayPreferencesMenu } from "@/components/sidebar/display-preferences/menu";
import { SidebarSeparator } from "@/components/sidebar/sidebar-separator";
import { SidebarNavRows } from "@/components/sidebar/sidebar-nav-rows";
+import { SidebarFooterIconHighlight } from "@/components/sidebar/sidebar-footer-icon-highlight";
import { SidebarHelpMenu } from "@/components/sidebar/sidebar-help-menu";
import { SidebarResizeHandle } from "@/components/sidebar-resize-handle";
import { DensityIcon } from "@/components/ui/density-icon";
@@ -317,13 +318,16 @@ function FooterIconButton({
accessibilityRole="button"
onPress={onPress}
>
- {({ hovered }) => (
-
+ {({ hovered, pressed }) => (
+ <>
+
+
+ >
)}
diff --git a/packages/app/src/components/sidebar/sidebar-footer-icon-highlight.tsx b/packages/app/src/components/sidebar/sidebar-footer-icon-highlight.tsx
new file mode 100644
index 0000000000..7b901693fa
--- /dev/null
+++ b/packages/app/src/components/sidebar/sidebar-footer-icon-highlight.tsx
@@ -0,0 +1,25 @@
+import { View } from "react-native";
+import { StyleSheet } from "react-native-unistyles";
+
+/**
+ * The round highlight behind a sidebar footer icon. It is a layer inside the button rather than a
+ * radius on it: web hit-testing follows `border-radius`, so a round button would stop taking taps
+ * near the corners of its square finger-sized target.
+ */
+export function SidebarFooterIconHighlight({ visible }: { visible: boolean }) {
+ return ;
+}
+
+const styles = StyleSheet.create((theme) => ({
+ highlight: {
+ position: "absolute",
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ borderRadius: theme.borderRadius.full,
+ },
+ visible: {
+ backgroundColor: theme.colors.interactionHighlight,
+ },
+}));
diff --git a/packages/app/src/components/sidebar/sidebar-header-row.tsx b/packages/app/src/components/sidebar/sidebar-header-row.tsx
index 2eeded947d..f38d27c65c 100644
--- a/packages/app/src/components/sidebar/sidebar-header-row.tsx
+++ b/packages/app/src/components/sidebar/sidebar-header-row.tsx
@@ -54,6 +54,10 @@ export function SidebarHeaderRow({
const [isHovered, setIsHovered] = useState(false);
const handlePointerEnter = useCallback(() => setIsHovered(true), []);
const handlePointerLeave = useCallback(() => setIsHovered(false), []);
+ // The button and its trailing slot are siblings, so the row owns the pressed fill for both.
+ const [isPressed, setIsPressed] = useState(false);
+ const handlePressIn = useCallback(() => setIsPressed(true), []);
+ const handlePressOut = useCallback(() => setIsPressed(false), []);
const isHighlighted = isHovered || isActive;
const iconSize = variant === "header" ? "md" : "sm";
@@ -65,12 +69,14 @@ export function SidebarHeaderRow({
return (
{label}
{right === null ? null : (
-
+
{right}
)}
@@ -136,6 +149,10 @@ const styles = StyleSheet.create((theme) => ({
rowHighlighted: {
backgroundColor: theme.colors.surfaceSidebarHover,
},
+ // The workspace rows' pressed fill.
+ rowPressed: {
+ backgroundColor: theme.colors.surface2,
+ },
button: {
flex: 1,
minWidth: 0,
diff --git a/packages/app/src/components/sidebar/sidebar-help-menu.tsx b/packages/app/src/components/sidebar/sidebar-help-menu.tsx
index 97ff3d2772..0eefa77468 100644
--- a/packages/app/src/components/sidebar/sidebar-help-menu.tsx
+++ b/packages/app/src/components/sidebar/sidebar-help-menu.tsx
@@ -15,6 +15,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { DensityIcon } from "@/components/ui/density-icon";
+import { SidebarFooterIconHighlight } from "./sidebar-footer-icon-highlight";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useAppDiagnosticStore } from "@/diagnostics/store";
import { useKeyboardShortcutsAvailable } from "@/keyboard/availability";
@@ -108,12 +109,15 @@ export function SidebarHelpMenu() {
accessibilityRole="button"
accessibilityLabel={t("sidebar.help.trigger")}
>
- {({ hovered }) => (
-
+ {({ hovered, pressed, open: menuOpen }) => (
+ <>
+
+
+ >
)}
diff --git a/packages/app/src/screens/settings-screen.tsx b/packages/app/src/screens/settings-screen.tsx
index 3950c0778e..31f5058940 100644
--- a/packages/app/src/screens/settings-screen.tsx
+++ b/packages/app/src/screens/settings-screen.tsx
@@ -275,15 +275,26 @@ function renderHostSettingsContent(
// Trigger + sidebar style helpers
// ---------------------------------------------------------------------------
-function sidebarItemStyle({ hovered }: PressableStateCallbackType & { hovered?: boolean }) {
- return [sidebarStyles.item, Boolean(hovered) && sidebarStyles.itemHovered];
+function sidebarItemStyle({
+ hovered,
+ pressed,
+}: PressableStateCallbackType & { hovered?: boolean }) {
+ return [
+ sidebarStyles.item,
+ Boolean(hovered) && sidebarStyles.itemHovered,
+ pressed && sidebarStyles.itemPressed,
+ ];
}
-function selectedSidebarItemStyle({ hovered }: PressableStateCallbackType & { hovered?: boolean }) {
+function selectedSidebarItemStyle({
+ hovered,
+ pressed,
+}: PressableStateCallbackType & { hovered?: boolean }) {
return [
sidebarStyles.item,
Boolean(hovered) && sidebarStyles.itemHovered,
sidebarStyles.itemSelected,
+ pressed && sidebarStyles.itemPressed,
];
}
@@ -865,9 +876,10 @@ function HostPicker({
[],
);
const triggerStyle = useCallback(
- ({ hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => [
+ ({ hovered = false, pressed }: PressableStateCallbackType & { hovered?: boolean }) => [
sidebarStyles.pickerTrigger,
hovered && sidebarStyles.pickerTriggerHovered,
+ pressed && sidebarStyles.itemPressed,
],
[],
);
@@ -1615,6 +1627,10 @@ const sidebarStyles = StyleSheet.create((theme) => ({
itemSelected: {
backgroundColor: theme.colors.surfaceSidebarHover,
},
+ // The workspace rows' pressed fill.
+ itemPressed: {
+ backgroundColor: theme.colors.surface2,
+ },
label: {
fontSize: { xs: theme.fontSize.lg, md: theme.fontSize.base },
color: theme.colors.foregroundMuted,