From 262332887258f9137420da9025f1f90a59324191 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 3 Feb 2026 09:32:42 +0700 Subject: [PATCH] refactor: redesign permission request UI with improved spacing and icons --- .../app/src/components/agent-stream-view.tsx | 165 ++++++++++++------ packages/app/src/components/message.tsx | 12 +- 2 files changed, 114 insertions(+), 63 deletions(-) diff --git a/packages/app/src/components/agent-stream-view.tsx b/packages/app/src/components/agent-stream-view.tsx index ba9d7db14..35e3c9163 100644 --- a/packages/app/src/components/agent-stream-view.tsx +++ b/packages/app/src/components/agent-stream-view.tsx @@ -14,7 +14,7 @@ import { } from "react-native"; import Markdown from "react-native-markdown-display"; import { useSafeAreaInsets } from "react-native-safe-area-context"; -import { StyleSheet, useUnistyles } from "react-native-unistyles"; +import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles"; import { useMutation } from "@tanstack/react-query"; import Animated, { FadeIn, @@ -27,7 +27,7 @@ import Animated, { withSequence, withTiming, } from "react-native-reanimated"; -import { ChevronDown } from "lucide-react-native"; +import { Check, ChevronDown, X } from "lucide-react-native"; import { usePanelStore } from "@/stores/panel-store"; import { AssistantMessage, @@ -242,6 +242,11 @@ export function AgentStreamView({ return tightGap; } + // And keep assistant messages visually connected to tool sequences (symmetry). + if (item.kind === "assistant_message" && isToolSequenceItem(aboveItem)) { + return tightGap; + } + // Different types get loose gap (16px) return looseGap; }, @@ -765,6 +770,8 @@ function PermissionRequestCard({ client: DaemonClientV2 | null; }) { const { theme } = useUnistyles(); + const isMobile = + UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm"; const { request } = permission; const isPlanRequest = request.kind === "plan"; @@ -987,14 +994,16 @@ function PermissionRequestCard({ {planMarkdown ? ( - - {isPlanRequest ? "Plan" : "Proposed Plan"} - + {!isPlanRequest ? ( + + Proposed plan + + ) : null} - + handleResponse({ behavior: "allow" })} - disabled={isResponding} - > - {isResponding ? ( - - ) : ( - - Allow - - )} - - { + const hovered = Boolean((state as any).hovered); + const pressed = Boolean(state.pressed); + return [ + permissionStyles.optionButton, + { + backgroundColor: hovered + ? theme.colors.surface1 + : theme.colors.surface2, + borderColor: theme.colors.borderAccent, + }, + pressed ? permissionStyles.optionButtonPressed : null, + ]; + }} onPress={() => handleResponse({ behavior: "deny", @@ -1063,19 +1063,54 @@ function PermissionRequestCard({ disabled={isResponding} > {isResponding ? ( - + ) : ( - - Deny - + + + + Deny + + + )} + + + { + const hovered = Boolean((state as any).hovered); + const pressed = Boolean(state.pressed); + return [ + permissionStyles.optionButton, + { + backgroundColor: hovered + ? theme.colors.surface1 + : theme.colors.surface2, + borderColor: theme.colors.primary, + }, + pressed ? permissionStyles.optionButtonPressed : null, + ]; + }} + onPress={() => handleResponse({ behavior: "allow" })} + disabled={isResponding} + > + {isResponding ? ( + + ) : ( + + + + Accept + + )} @@ -1190,7 +1225,7 @@ const stylesheet = StyleSheet.create((theme) => ({ const permissionStyles = StyleSheet.create((theme) => ({ container: { marginVertical: theme.spacing[3], - padding: theme.spacing[4], + padding: theme.spacing[3], borderRadius: theme.spacing[2], borderWidth: 1, gap: theme.spacing[2], @@ -1208,8 +1243,6 @@ const permissionStyles = StyleSheet.create((theme) => ({ }, sectionTitle: { fontSize: theme.fontSize.xs, - textTransform: "uppercase" as const, - letterSpacing: 0.5, }, contentCard: { padding: theme.spacing[3], @@ -1220,19 +1253,35 @@ const permissionStyles = StyleSheet.create((theme) => ({ }, question: { fontSize: theme.fontSize.sm, - marginTop: theme.spacing[2], - marginBottom: theme.spacing[2], + marginTop: theme.spacing[1], + marginBottom: theme.spacing[1], }, optionsContainer: { gap: theme.spacing[2], }, + optionsContainerDesktop: { + flexDirection: "row", + justifyContent: "flex-end", + alignItems: "center", + width: "100%", + }, optionButton: { - padding: theme.spacing[3], + paddingVertical: theme.spacing[2], + paddingHorizontal: theme.spacing[3], borderRadius: theme.borderRadius.md, alignItems: "center", + borderWidth: theme.borderWidth[1], + }, + optionButtonPressed: { + opacity: 0.9, + }, + optionContent: { + flexDirection: "row", + alignItems: "center", + gap: theme.spacing[2], }, optionText: { fontSize: theme.fontSize.sm, - fontWeight: theme.fontWeight.semibold, + fontWeight: theme.fontWeight.normal, }, })); diff --git a/packages/app/src/components/message.tsx b/packages/app/src/components/message.tsx index 1b86d9d3b..1512c455b 100644 --- a/packages/app/src/components/message.tsx +++ b/packages/app/src/components/message.tsx @@ -180,11 +180,13 @@ export const UserMessage = memo(function UserMessage({