Files
paseo/packages/app/src/app/agent/[id].tsx
T
Mohamed BoudraandClaude 13f59102b9 fix: remove excessive bottom padding causing gap between status bar and controls
The animated keyboard style was adding FOOTER_HEIGHT + insets.bottom as padding,
creating a massive gap. Removed footer height from padding calculation - keyboard
padding only needs to account for keyboard height, not footer.

Fixed by Codex.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 11:41:52 +02:00

116 lines
3.6 KiB
TypeScript

import { useEffect, useMemo } from "react";
import { View, Text } from "react-native";
import { useLocalSearchParams } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useReanimatedKeyboardAnimation } from "react-native-keyboard-controller";
import ReanimatedAnimated, { useAnimatedStyle } from "react-native-reanimated";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { BackHeader } from "@/components/headers/back-header";
import { AgentStreamView } from "@/components/agent-stream-view";
import { AgentInputArea } from "@/components/agent-input-area";
import { AgentStatusBar } from "@/components/agent-status-bar";
import { useSession } from "@/contexts/session-context";
import { useFooterControls } from "@/contexts/footer-controls-context";
export default function AgentScreen() {
const { theme } = useUnistyles();
const insets = useSafeAreaInsets();
const { id } = useLocalSearchParams<{ id: string }>();
const { agents, agentStreamState, pendingPermissions, respondToPermission } = useSession();
const { registerFooterControls, unregisterFooterControls } = useFooterControls();
// Keyboard animation
const { height: keyboardHeight } = useReanimatedKeyboardAnimation();
const bottomInset = insets.bottom;
const animatedKeyboardStyle = useAnimatedStyle(() => {
"worklet";
const absoluteHeight = Math.abs(keyboardHeight.value);
const padding = Math.max(0, absoluteHeight - bottomInset);
return {
paddingBottom: padding,
};
});
const agent = id ? agents.get(id) : undefined;
const streamItems = id ? agentStreamState.get(id) || [] : [];
const agentPermissions = new Map(
Array.from(pendingPermissions.entries()).filter(([_, perm]) => perm.agentId === id)
);
const agentControls = useMemo(() => {
if (!id) return null;
return <AgentInputArea agentId={id} />;
}, [id]);
useEffect(() => {
if (!agentControls || !agent) {
unregisterFooterControls();
return;
}
registerFooterControls(agentControls);
return () => {
unregisterFooterControls();
};
}, [agentControls, agent, registerFooterControls, unregisterFooterControls]);
if (!agent) {
return (
<View style={styles.container}>
<BackHeader />
<View style={styles.errorContainer}>
<Text style={styles.errorText}>Agent not found</Text>
</View>
</View>
);
}
return (
<View style={styles.container}>
{/* Header */}
<BackHeader title={agent.title || "Agent"} />
{/* Content Area with Keyboard Animation */}
<ReanimatedAnimated.View style={[styles.content, animatedKeyboardStyle]}>
<AgentStreamView
agentId={id!}
agent={agent}
streamItems={streamItems}
pendingPermissions={agentPermissions}
onPermissionResponse={(requestId, optionId) =>
respondToPermission(requestId, id!, agent.sessionId || "", [optionId])
}
/>
{/* Footer area - status bar pinned within screen */}
<View style={styles.footerContainer}>
<AgentStatusBar agentId={id!} />
</View>
</ReanimatedAnimated.View>
</View>
);
}
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
content: {
flex: 1,
},
footerContainer: {
backgroundColor: theme.colors.background,
},
errorContainer: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
errorText: {
fontSize: theme.fontSize.lg,
color: theme.colors.mutedForeground,
},
}));