Skip to content

Commit 44c9001

Browse files
feat(mobile): align task detail with desktop
Generated-By: PostHog Code Task-Id: 11daf8d3-7830-436a-ab8f-99123586070d
1 parent c7a1231 commit 44c9001

3 files changed

Lines changed: 29 additions & 113 deletions

File tree

apps/mobile/src/app/task/[id].tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,7 @@ export default function TaskDetailScreen() {
849849
/>
850850
) : null}
851851
<TaskChatComposer
852+
key={taskId}
852853
adapter={composerAdapter}
853854
canChangeAdapter={!!session?.terminalStatus}
854855
onSend={handleSendPrompt}

apps/mobile/src/features/tasks/components/FloatingTaskHeader.tsx

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { Text } from "@components/text";
2-
import { LinearGradient } from "expo-linear-gradient";
32
import { useRouter } from "expo-router";
43
import { CaretLeft } from "phosphor-react-native";
54
import type { ReactNode } from "react";
65
import { Platform, Pressable, View } from "react-native";
76
import { useSafeAreaInsets } from "react-native-safe-area-context";
8-
import { toRgba, useThemeColors } from "@/lib/theme";
7+
import { useThemeColors } from "@/lib/theme";
98

109
interface FloatingTaskHeaderProps {
1110
title: string;
@@ -14,12 +13,7 @@ interface FloatingTaskHeaderProps {
1413
rightSlot?: ReactNode;
1514
}
1615

17-
/**
18-
* Floating header for the task detail screen — back arrow on the left,
19-
* centered title + repo subtitle, optional right slot for actions. Sits over
20-
* the content with a top-to-bottom fade so the scroll list disappears
21-
* gracefully behind it rather than getting clipped by a hard edge.
22-
*/
16+
/** Task detail toolbar with navigation, task identity, and run actions. */
2317
export function FloatingTaskHeader({
2418
title,
2519
subtitle,
@@ -38,30 +32,14 @@ export function FloatingTaskHeader({
3832
// on iOS and fall back to the real inset on Android.
3933
const topInset = Platform.OS === "ios" ? 6 : insets.top;
4034

41-
// Fade height extends well past the title row so content scrolling up
42-
// behind the header gets a long, gentle transition instead of crashing
43-
// into the subtitle. Header row content sits in roughly the first
44-
// (topInset + 44)pt; the rest is pure fade.
45-
const fadeHeight = topInset + 96;
35+
const headerHeight = topInset + 52;
4636

4737
return (
4838
<View
4939
pointerEvents="box-none"
50-
className="absolute inset-x-0 top-0 z-10"
51-
style={{ height: fadeHeight }}
40+
className="absolute inset-x-0 top-0 z-10 border-gray-4 border-b bg-background"
41+
style={{ height: headerHeight }}
5242
>
53-
<LinearGradient
54-
pointerEvents="none"
55-
colors={[
56-
toRgba(themeColors.background, 1),
57-
toRgba(themeColors.background, 1),
58-
toRgba(themeColors.background, 0.85),
59-
toRgba(themeColors.background, 0),
60-
]}
61-
locations={[0, 0.5, 0.75, 1]}
62-
style={{ position: "absolute", top: 0, left: 0, right: 0, bottom: 0 }}
63-
/>
64-
6543
<View
6644
className="flex-row items-center px-3"
6745
style={{ paddingTop: topInset, paddingBottom: 4 }}
@@ -74,7 +52,7 @@ export function FloatingTaskHeader({
7452
<CaretLeft size={22} color={themeColors.gray[12]} weight="bold" />
7553
</Pressable>
7654

77-
<View className="min-w-0 flex-1 items-center px-2">
55+
<View className="min-w-0 flex-1 items-start px-2">
7856
<Text
7957
className="font-semibold text-[15px] text-gray-12"
8058
numberOfLines={1}

apps/mobile/src/features/tasks/composer/TaskChatComposer.tsx

Lines changed: 22 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,9 @@ import {
3434
Stack,
3535
Stop,
3636
} from "phosphor-react-native";
37-
import {
38-
type ReactNode,
39-
useCallback,
40-
useEffect,
41-
useRef,
42-
useState,
43-
} from "react";
37+
import { type ReactNode, useCallback, useEffect, useState } from "react";
4438
import {
4539
ActivityIndicator,
46-
Animated,
47-
Easing,
4840
Keyboard,
4941
Pressable,
5042
ScrollView,
@@ -115,60 +107,6 @@ function modeIcon(mode: ExecutionMode, color: string, size = 14): ReactNode {
115107
}
116108
}
117109

118-
function PulsingBorder({ active, color }: { active: boolean; color: string }) {
119-
const opacity = useRef(new Animated.Value(0)).current;
120-
const animRef = useRef<Animated.CompositeAnimation | null>(null);
121-
122-
useEffect(() => {
123-
if (active) {
124-
opacity.setValue(0);
125-
animRef.current = Animated.loop(
126-
Animated.sequence([
127-
Animated.timing(opacity, {
128-
toValue: 1,
129-
duration: 1500,
130-
easing: Easing.inOut(Easing.ease),
131-
useNativeDriver: true,
132-
}),
133-
Animated.timing(opacity, {
134-
toValue: 0,
135-
duration: 1500,
136-
easing: Easing.inOut(Easing.ease),
137-
useNativeDriver: true,
138-
}),
139-
]),
140-
);
141-
animRef.current.start();
142-
} else {
143-
animRef.current?.stop();
144-
animRef.current = null;
145-
opacity.setValue(0);
146-
}
147-
return () => {
148-
animRef.current?.stop();
149-
};
150-
}, [active, opacity]);
151-
152-
if (!active) return null;
153-
154-
return (
155-
<Animated.View
156-
pointerEvents="none"
157-
style={{
158-
position: "absolute",
159-
top: 0,
160-
left: 0,
161-
right: 0,
162-
bottom: 0,
163-
opacity,
164-
borderWidth: 2,
165-
borderColor: color,
166-
borderRadius: 16,
167-
}}
168-
/>
169-
);
170-
}
171-
172110
export function TaskChatComposer({
173111
onSend,
174112
onStop,
@@ -318,10 +256,9 @@ export function TaskChatComposer({
318256

319257
return (
320258
<>
321-
<View className="px-3">
322-
<View className="relative">
323-
<PulsingBorder active={isUserTurn} color={themeColors.accent[9]} />
324-
<View className="overflow-hidden rounded-2xl border border-gray-6 bg-card">
259+
<View className="px-4">
260+
<View style={{ width: "100%", maxWidth: 600, alignSelf: "center" }}>
261+
<View className="overflow-hidden rounded-lg border border-gray-6 bg-card">
325262
{editing ? (
326263
<View className="flex-row items-center gap-2 border-gray-6 border-b bg-accent-2 px-3 py-2">
327264
<PencilIcon size={14} color={themeColors.accent[11]} />
@@ -347,7 +284,7 @@ export function TaskChatComposer({
347284
/>
348285
<TextInput
349286
className="px-4 pt-3.5 pb-3 text-[15px] text-gray-12"
350-
style={{ minHeight: 56, maxHeight: 200 }}
287+
style={{ minHeight: 64, maxHeight: 200 }}
351288
placeholder={
352289
isRecording
353290
? "Recording..."
@@ -394,23 +331,6 @@ export function TaskChatComposer({
394331
paddingRight: 4,
395332
}}
396333
>
397-
<Pill
398-
icon={
399-
isSteer ? (
400-
<Lightning
401-
size={14}
402-
color={themeColors.accent[11]}
403-
weight="fill"
404-
/>
405-
) : (
406-
<Stack size={14} color={themeColors.gray[11]} />
407-
)
408-
}
409-
label={messagingModeLabel}
410-
accent={isSteer}
411-
onPress={handleToggleMessagingMode}
412-
/>
413-
414334
<Pill
415335
icon={modeIcon(
416336
mode,
@@ -452,6 +372,23 @@ export function TaskChatComposer({
452372
onPress={() => setReasoningSheetOpen(true)}
453373
/>
454374
) : null}
375+
376+
<Pill
377+
icon={
378+
isSteer ? (
379+
<Lightning
380+
size={14}
381+
color={themeColors.accent[11]}
382+
weight="fill"
383+
/>
384+
) : (
385+
<Stack size={14} color={themeColors.gray[11]} />
386+
)
387+
}
388+
label={messagingModeLabel}
389+
accent={isSteer}
390+
onPress={handleToggleMessagingMode}
391+
/>
455392
</ScrollView>
456393

457394
<Pressable

0 commit comments

Comments
 (0)