mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Merge branch 'fix/diff-padding'
This commit is contained in:
9
packages/app/src/components/code-insets.ts
Normal file
9
packages/app/src/components/code-insets.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export function getCodeInsets(theme: any) {
|
||||
const paddingX = theme.spacing[3] + theme.spacing[2];
|
||||
const paddingY = theme.spacing[1];
|
||||
const extraRight = theme.spacing[4];
|
||||
const extraBottom = theme.spacing[3];
|
||||
|
||||
return { paddingX, paddingY, extraRight, extraBottom };
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ScrollView } from "react-native-gesture-handler";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { Fonts } from "@/constants/theme";
|
||||
import type { DiffLine, DiffSegment } from "@/utils/tool-call-parsers";
|
||||
import { getCodeInsets } from "./code-insets";
|
||||
|
||||
interface DiffViewerProps {
|
||||
diffLines: DiffLine[];
|
||||
@@ -86,64 +87,70 @@ export function DiffViewer({ diffLines, maxHeight = 280, emptyLabel = "No change
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
verticalScroll: {},
|
||||
verticalContent: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
horizontalContent: {
|
||||
flexDirection: "column" as const,
|
||||
},
|
||||
linesContainer: {
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
line: {
|
||||
minWidth: "100%",
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[1],
|
||||
},
|
||||
lineText: {
|
||||
fontFamily: Fonts.mono,
|
||||
fontSize: theme.fontSize.xs,
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
headerLine: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
headerText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
addLine: {
|
||||
backgroundColor: "rgba(46, 160, 67, 0.15)",
|
||||
},
|
||||
addText: {
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
removeLine: {
|
||||
backgroundColor: "rgba(248, 81, 73, 0.1)",
|
||||
},
|
||||
removeText: {
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
addHighlight: {
|
||||
backgroundColor: "rgba(46, 160, 67, 0.4)",
|
||||
},
|
||||
removeHighlight: {
|
||||
backgroundColor: "rgba(248, 81, 73, 0.35)",
|
||||
},
|
||||
contextLine: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
contextText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
emptyState: {
|
||||
padding: theme.spacing[4],
|
||||
alignItems: "center" as const,
|
||||
justifyContent: "center" as const,
|
||||
},
|
||||
emptyText: {
|
||||
fontSize: theme.fontSize.sm,
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
}));
|
||||
const styles = StyleSheet.create((theme) => {
|
||||
const insets = getCodeInsets(theme);
|
||||
|
||||
return {
|
||||
verticalScroll: {},
|
||||
verticalContent: {
|
||||
flexGrow: 1,
|
||||
paddingBottom: insets.extraBottom,
|
||||
},
|
||||
horizontalContent: {
|
||||
flexDirection: "column" as const,
|
||||
paddingRight: insets.extraRight,
|
||||
},
|
||||
linesContainer: {
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
line: {
|
||||
minWidth: "100%",
|
||||
paddingHorizontal: insets.paddingX,
|
||||
paddingVertical: insets.paddingY,
|
||||
},
|
||||
lineText: {
|
||||
fontFamily: Fonts.mono,
|
||||
fontSize: theme.fontSize.xs,
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
headerLine: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
headerText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
addLine: {
|
||||
backgroundColor: "rgba(46, 160, 67, 0.15)",
|
||||
},
|
||||
addText: {
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
removeLine: {
|
||||
backgroundColor: "rgba(248, 81, 73, 0.1)",
|
||||
},
|
||||
removeText: {
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
addHighlight: {
|
||||
backgroundColor: "rgba(46, 160, 67, 0.4)",
|
||||
},
|
||||
removeHighlight: {
|
||||
backgroundColor: "rgba(248, 81, 73, 0.35)",
|
||||
},
|
||||
contextLine: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
contextText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
emptyState: {
|
||||
padding: theme.spacing[4],
|
||||
alignItems: "center" as const,
|
||||
justifyContent: "center" as const,
|
||||
},
|
||||
emptyText: {
|
||||
fontSize: theme.fontSize.sm,
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -389,8 +389,8 @@ const expandableBadgeStylesheet = StyleSheet.create((theme) => ({
|
||||
borderTopWidth: 0,
|
||||
borderColor: theme.colors.borderAccent,
|
||||
backgroundColor: theme.colors.surface0,
|
||||
padding: theme.spacing[2],
|
||||
gap: theme.spacing[2],
|
||||
padding: 0,
|
||||
gap: 0,
|
||||
flexShrink: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
@@ -781,6 +781,9 @@ interface TodoListCardProps {
|
||||
}
|
||||
|
||||
const todoListCardStylesheet = StyleSheet.create((theme) => ({
|
||||
detailsWrapper: {
|
||||
padding: theme.spacing[2],
|
||||
},
|
||||
list: {
|
||||
gap: theme.spacing[1],
|
||||
},
|
||||
@@ -832,26 +835,28 @@ export const TodoListCard = memo(function TodoListCard({
|
||||
|
||||
const renderDetails = useCallback(() => {
|
||||
return (
|
||||
<View style={todoListCardStylesheet.list}>
|
||||
{items.length === 0 ? (
|
||||
<Text style={todoListCardStylesheet.emptyText}>No tasks yet.</Text>
|
||||
) : (
|
||||
items.map((item, idx) => (
|
||||
<View key={`${item.text}-${idx}`} style={todoListCardStylesheet.itemRow}>
|
||||
<View style={todoListCardStylesheet.radioOuter}>
|
||||
{item.completed ? <View style={todoListCardStylesheet.radioInner} /> : null}
|
||||
<View style={todoListCardStylesheet.detailsWrapper}>
|
||||
<View style={todoListCardStylesheet.list}>
|
||||
{items.length === 0 ? (
|
||||
<Text style={todoListCardStylesheet.emptyText}>No tasks yet.</Text>
|
||||
) : (
|
||||
items.map((item, idx) => (
|
||||
<View key={`${item.text}-${idx}`} style={todoListCardStylesheet.itemRow}>
|
||||
<View style={todoListCardStylesheet.radioOuter}>
|
||||
{item.completed ? <View style={todoListCardStylesheet.radioInner} /> : null}
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
todoListCardStylesheet.itemText,
|
||||
item.completed && todoListCardStylesheet.itemTextCompleted,
|
||||
]}
|
||||
>
|
||||
{item.text}
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
todoListCardStylesheet.itemText,
|
||||
item.completed && todoListCardStylesheet.itemTextCompleted,
|
||||
]}
|
||||
>
|
||||
{item.text}
|
||||
</Text>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
))
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}, [items]);
|
||||
@@ -1099,12 +1104,13 @@ export const ToolCall = memo(function ToolCall({
|
||||
args,
|
||||
result,
|
||||
error,
|
||||
cwd,
|
||||
});
|
||||
} else {
|
||||
// Desktop: toggle inline expansion
|
||||
setIsExpanded((prev) => !prev);
|
||||
}
|
||||
}, [isMobile, openToolCall, toolName, kind, status, args, result, error]);
|
||||
}, [isMobile, openToolCall, toolName, kind, status, args, result, error, cwd]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isMobile || !isPerfLoggingEnabled()) {
|
||||
@@ -1136,15 +1142,7 @@ export const ToolCall = memo(function ToolCall({
|
||||
// Render inline details for desktop
|
||||
const renderDetails = useCallback(() => {
|
||||
if (isMobile) return null;
|
||||
return (
|
||||
<View style={toolCallInlineStyles.detailsContainer}>
|
||||
<ToolCallDetailsContent
|
||||
display={display}
|
||||
errorText={errorText}
|
||||
maxHeight={400}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
return <ToolCallDetailsContent display={display} errorText={errorText} maxHeight={400} />;
|
||||
}, [isMobile, display, errorText]);
|
||||
|
||||
return (
|
||||
@@ -1169,10 +1167,3 @@ export const ToolCall = memo(function ToolCall({
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const toolCallInlineStyles = StyleSheet.create((theme) => ({
|
||||
detailsContainer: {
|
||||
paddingTop: theme.spacing[3],
|
||||
paddingBottom: theme.spacing[2],
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
type ToolCallDisplay,
|
||||
} from "@/utils/tool-call-parsers";
|
||||
import { DiffViewer } from "./diff-viewer";
|
||||
import { getCodeInsets } from "./code-insets";
|
||||
|
||||
// ---- Types ----
|
||||
|
||||
@@ -157,46 +158,37 @@ export function ToolCallDetailsContent({
|
||||
}, [display]);
|
||||
|
||||
const sections: ReactNode[] = [];
|
||||
const isFullBleed = display.type === "edit" || display.type === "shell";
|
||||
|
||||
if (display.type === "shell") {
|
||||
const combinedText = `$ ${display.command}${display.output ? `\n${display.output}` : ""}`;
|
||||
sections.push(
|
||||
<View key="shell" style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Command</Text>
|
||||
<ScrollView
|
||||
horizontal
|
||||
nestedScrollEnabled
|
||||
style={styles.jsonScroll}
|
||||
contentContainerStyle={styles.jsonContent}
|
||||
showsHorizontalScrollIndicator={true}
|
||||
>
|
||||
<Text selectable style={styles.scrollText}>{display.command}</Text>
|
||||
</ScrollView>
|
||||
{display.output ? (
|
||||
<View style={styles.diffContainer}>
|
||||
<ScrollView
|
||||
style={[styles.scrollArea, { maxHeight }]}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
style={[styles.codeVerticalScroll, { maxHeight }]}
|
||||
contentContainerStyle={styles.codeVerticalContent}
|
||||
nestedScrollEnabled
|
||||
showsVerticalScrollIndicator={true}
|
||||
showsVerticalScrollIndicator
|
||||
>
|
||||
<ScrollView
|
||||
horizontal
|
||||
nestedScrollEnabled
|
||||
showsHorizontalScrollIndicator={true}
|
||||
showsHorizontalScrollIndicator
|
||||
contentContainerStyle={styles.codeHorizontalContent}
|
||||
>
|
||||
<Text selectable style={styles.scrollText}>{display.output}</Text>
|
||||
<View style={styles.codeLine}>
|
||||
<Text selectable style={styles.scrollText}>{combinedText}</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
} else if (display.type === "edit") {
|
||||
sections.push(
|
||||
<View key="edit" style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>File</Text>
|
||||
<View style={styles.fileBadge}>
|
||||
<Text style={styles.fileBadgeText}>{display.filePath}</Text>
|
||||
</View>
|
||||
{diffLines && diffLines.length > 0 ? (
|
||||
{diffLines ? (
|
||||
<View style={styles.diffContainer}>
|
||||
<DiffViewer diffLines={diffLines} maxHeight={maxHeight} />
|
||||
</View>
|
||||
@@ -206,10 +198,6 @@ export function ToolCallDetailsContent({
|
||||
} else if (display.type === "read") {
|
||||
sections.push(
|
||||
<View key="read" style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>File</Text>
|
||||
<View style={styles.fileBadge}>
|
||||
<Text style={styles.fileBadgeText}>{display.filePath}</Text>
|
||||
</View>
|
||||
{(display.offset !== undefined || display.limit !== undefined) ? (
|
||||
<Text style={styles.rangeText}>
|
||||
{display.offset !== undefined ? `Offset: ${display.offset}` : ""}
|
||||
@@ -326,7 +314,11 @@ export function ToolCallDetailsContent({
|
||||
);
|
||||
}
|
||||
|
||||
return <View style={styles.container}>{sections}</View>;
|
||||
return (
|
||||
<View style={isFullBleed ? styles.fullBleedContainer : styles.paddedContainer}>
|
||||
{sections}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// ---- Hook for parsing tool call data ----
|
||||
@@ -362,10 +354,18 @@ export function useToolCallDetails(data: ToolCallDetailsData) {
|
||||
|
||||
// ---- Styles ----
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
container: {
|
||||
gap: theme.spacing[4],
|
||||
},
|
||||
const styles = StyleSheet.create((theme) => {
|
||||
const insets = getCodeInsets(theme);
|
||||
|
||||
return {
|
||||
paddedContainer: {
|
||||
gap: theme.spacing[4],
|
||||
padding: theme.spacing[2],
|
||||
},
|
||||
fullBleedContainer: {
|
||||
gap: theme.spacing[2],
|
||||
padding: 0,
|
||||
},
|
||||
groupHeader: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
@@ -391,20 +391,6 @@ const styles = StyleSheet.create((theme) => ({
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
fileBadge: {
|
||||
alignSelf: "flex-start",
|
||||
paddingHorizontal: theme.spacing[2],
|
||||
paddingVertical: theme.spacing[1],
|
||||
borderRadius: theme.borderRadius.base,
|
||||
borderWidth: theme.borderWidth[1],
|
||||
borderColor: theme.colors.border,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
fileBadgeText: {
|
||||
color: theme.colors.foreground,
|
||||
fontFamily: Fonts.mono,
|
||||
fontSize: theme.fontSize.xs,
|
||||
},
|
||||
rangeText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.xs,
|
||||
@@ -416,6 +402,19 @@ const styles = StyleSheet.create((theme) => ({
|
||||
overflow: "hidden",
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
codeVerticalScroll: {},
|
||||
codeVerticalContent: {
|
||||
flexGrow: 1,
|
||||
paddingBottom: insets.extraBottom,
|
||||
},
|
||||
codeHorizontalContent: {
|
||||
paddingRight: insets.extraRight,
|
||||
},
|
||||
codeLine: {
|
||||
minWidth: "100%",
|
||||
paddingHorizontal: insets.paddingX,
|
||||
paddingVertical: insets.paddingY,
|
||||
},
|
||||
scrollArea: {
|
||||
borderWidth: theme.borderWidth[1],
|
||||
borderColor: theme.colors.border,
|
||||
@@ -451,4 +450,5 @@ const styles = StyleSheet.create((theme) => ({
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontStyle: "italic",
|
||||
},
|
||||
}));
|
||||
};
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
BottomSheetBackgroundProps,
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import { Pencil, Eye, SquareTerminal, Search, Wrench, X } from "lucide-react-native";
|
||||
import { extractPrincipalParam } from "@/utils/tool-call-parsers";
|
||||
import { ToolCallDetailsContent, useToolCallDetails } from "./tool-call-details";
|
||||
|
||||
// ----- Types -----
|
||||
@@ -24,6 +25,7 @@ export interface ToolCallSheetData {
|
||||
toolName: string;
|
||||
kind?: string;
|
||||
status?: "executing" | "completed" | "failed";
|
||||
cwd?: string;
|
||||
args?: unknown;
|
||||
result?: unknown;
|
||||
error?: unknown;
|
||||
@@ -138,13 +140,14 @@ interface ToolCallSheetContentProps {
|
||||
}
|
||||
|
||||
function ToolCallSheetContent({ data, onClose }: ToolCallSheetContentProps) {
|
||||
const { toolName, kind, args, result, error } = data;
|
||||
const { toolName, kind, cwd, args, result, error } = data;
|
||||
|
||||
const IconComponent = kind
|
||||
? toolKindIcons[kind.toLowerCase()] || Wrench
|
||||
: Wrench;
|
||||
|
||||
const { display, errorText } = useToolCallDetails({ toolName, args, result, error });
|
||||
const principalParam = useMemo(() => extractPrincipalParam(args, cwd), [args, cwd]);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@@ -152,9 +155,16 @@ function ToolCallSheetContent({ data, onClose }: ToolCallSheetContentProps) {
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerLeft}>
|
||||
<IconComponent size={20} color={styles.headerIcon.color} />
|
||||
<Text style={styles.headerTitle} numberOfLines={1}>
|
||||
{display.toolName}
|
||||
</Text>
|
||||
<View style={styles.headerTextColumn}>
|
||||
<Text style={styles.headerTitle} numberOfLines={1}>
|
||||
{display.toolName}
|
||||
</Text>
|
||||
{principalParam ? (
|
||||
<Text style={styles.headerSubtitle} numberOfLines={1}>
|
||||
{principalParam}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
<Pressable onPress={onClose} style={styles.closeButton}>
|
||||
<X size={20} color={styles.closeIcon.color} />
|
||||
@@ -200,6 +210,10 @@ const styles = StyleSheet.create((theme) => ({
|
||||
gap: theme.spacing[2],
|
||||
flex: 1,
|
||||
},
|
||||
headerTextColumn: {
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
headerIcon: {
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
@@ -209,6 +223,11 @@ const styles = StyleSheet.create((theme) => ({
|
||||
color: theme.colors.foreground,
|
||||
flex: 1,
|
||||
},
|
||||
headerSubtitle: {
|
||||
marginTop: theme.spacing[1],
|
||||
fontSize: theme.fontSize.sm,
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
closeButton: {
|
||||
padding: theme.spacing[2],
|
||||
},
|
||||
@@ -220,8 +239,6 @@ const styles = StyleSheet.create((theme) => ({
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
contentContainer: {
|
||||
paddingHorizontal: theme.spacing[4],
|
||||
paddingTop: theme.spacing[4],
|
||||
paddingBottom: theme.spacing[8],
|
||||
padding: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user