feat(app): add line numbers, wrap toggle, and icon sizing improvements
This commit is contained in:
@@ -97,6 +97,7 @@ export function AgentInputArea({
|
|||||||
}: AgentInputAreaProps) {
|
}: AgentInputAreaProps) {
|
||||||
markScrollInvestigationRender(`AgentInputArea:${serverId}:${agentId}`)
|
markScrollInvestigationRender(`AgentInputArea:${serverId}:${agentId}`)
|
||||||
const { theme } = useUnistyles()
|
const { theme } = useUnistyles()
|
||||||
|
const buttonIconSize = Platform.OS === 'web' ? theme.iconSize.md : theme.iconSize.lg
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const isScreenFocused = useIsFocused()
|
const isScreenFocused = useIsFocused()
|
||||||
|
|
||||||
@@ -701,7 +702,7 @@ export function AgentInputArea({
|
|||||||
{isCancellingAgent ? (
|
{isCancellingAgent ? (
|
||||||
<ActivityIndicator size="small" color="white" />
|
<ActivityIndicator size="small" color="white" />
|
||||||
) : (
|
) : (
|
||||||
<Square size={theme.iconSize.md} color="white" fill="white" />
|
<Square size={buttonIconSize} color="white" fill="white" />
|
||||||
)}
|
)}
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
@@ -731,7 +732,7 @@ export function AgentInputArea({
|
|||||||
{voice?.isVoiceSwitching ? (
|
{voice?.isVoiceSwitching ? (
|
||||||
<ActivityIndicator size="small" color="white" />
|
<ActivityIndicator size="small" color="white" />
|
||||||
) : (
|
) : (
|
||||||
<AudioLines size={theme.iconSize.md} color={theme.colors.foreground} />
|
<AudioLines size={buttonIconSize} color={theme.colors.foreground} />
|
||||||
)}
|
)}
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import { useCallback, useMemo, useRef, useState } from 'react'
|
|||||||
import { View, Text, Platform, Pressable } from 'react-native'
|
import { View, Text, Platform, Pressable } from 'react-native'
|
||||||
import { StyleSheet, useUnistyles } from 'react-native-unistyles'
|
import { StyleSheet, useUnistyles } from 'react-native-unistyles'
|
||||||
import {
|
import {
|
||||||
Bot,
|
|
||||||
Brain,
|
Brain,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ShieldAlert,
|
ShieldAlert,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
ShieldOff,
|
ShieldOff,
|
||||||
SlidersHorizontal,
|
|
||||||
} from 'lucide-react-native'
|
} from 'lucide-react-native'
|
||||||
import { getProviderIcon } from '@/components/provider-icons'
|
import { getProviderIcon } from '@/components/provider-icons'
|
||||||
import { CombinedModelSelector } from '@/components/combined-model-selector'
|
import { CombinedModelSelector } from '@/components/combined-model-selector'
|
||||||
@@ -424,7 +423,8 @@ function ControlledStatusBar({
|
|||||||
accessibilityLabel="Agent preferences"
|
accessibilityLabel="Agent preferences"
|
||||||
testID="agent-preferences-button"
|
testID="agent-preferences-button"
|
||||||
>
|
>
|
||||||
<SlidersHorizontal size={theme.iconSize.md} color={theme.colors.foreground} />
|
<ProviderIcon size={theme.iconSize.lg} color={theme.colors.foregroundMuted} />
|
||||||
|
<Text style={styles.prefsButtonText} numberOfLines={1}>{displayModel}</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|
||||||
<AdaptiveModalSheet
|
<AdaptiveModalSheet
|
||||||
@@ -830,15 +830,22 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
lineHeight: theme.fontSize.sm * 1.4,
|
lineHeight: theme.fontSize.sm * 1.4,
|
||||||
},
|
},
|
||||||
prefsButton: {
|
prefsButton: {
|
||||||
width: 28,
|
|
||||||
height: 28,
|
height: 28,
|
||||||
borderRadius: theme.borderRadius.full,
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
gap: theme.spacing[1],
|
||||||
|
paddingHorizontal: theme.spacing[2],
|
||||||
|
borderRadius: theme.borderRadius['2xl'],
|
||||||
},
|
},
|
||||||
prefsButtonPressed: {
|
prefsButtonPressed: {
|
||||||
backgroundColor: theme.colors.surface0,
|
backgroundColor: theme.colors.surface0,
|
||||||
},
|
},
|
||||||
|
prefsButtonText: {
|
||||||
|
color: theme.colors.foregroundMuted,
|
||||||
|
fontSize: theme.fontSize.sm,
|
||||||
|
fontWeight: theme.fontWeight.normal,
|
||||||
|
flexShrink: 1,
|
||||||
|
},
|
||||||
sheetSection: {
|
sheetSection: {
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
ListChevronsUpDown,
|
ListChevronsUpDown,
|
||||||
RefreshCcw,
|
RefreshCcw,
|
||||||
Upload,
|
Upload,
|
||||||
|
WrapText,
|
||||||
} from "lucide-react-native";
|
} from "lucide-react-native";
|
||||||
import { useCheckoutGitActionsStore } from "@/stores/checkout-git-actions-store";
|
import { useCheckoutGitActionsStore } from "@/stores/checkout-git-actions-store";
|
||||||
import {
|
import {
|
||||||
@@ -47,6 +48,7 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||||
import { GitHubIcon } from "@/components/icons/github-icon";
|
import { GitHubIcon } from "@/components/icons/github-icon";
|
||||||
import {
|
import {
|
||||||
buildGitActions,
|
buildGitActions,
|
||||||
@@ -153,7 +155,7 @@ interface DiffFileSectionProps {
|
|||||||
testID?: string;
|
testID?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DiffLineView({ line }: { line: DiffLine }) {
|
function DiffLineView({ line, lineNumber, gutterWidth }: { line: DiffLine; lineNumber: number | null; gutterWidth: number }) {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
@@ -164,6 +166,15 @@ function DiffLineView({ line }: { line: DiffLine }) {
|
|||||||
line.type === "context" && styles.contextLineContainer,
|
line.type === "context" && styles.contextLineContainer,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
<View style={[styles.lineNumberGutter, { width: gutterWidth }]}>
|
||||||
|
<Text style={[
|
||||||
|
styles.lineNumberText,
|
||||||
|
line.type === "add" && styles.addLineNumberText,
|
||||||
|
line.type === "remove" && styles.removeLineNumberText,
|
||||||
|
]}>
|
||||||
|
{lineNumber != null ? String(lineNumber) : ""}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
{line.tokens && line.type !== "header" ? (
|
{line.tokens && line.type !== "header" ? (
|
||||||
<HighlightedText
|
<HighlightedText
|
||||||
tokens={line.tokens}
|
tokens={line.tokens}
|
||||||
@@ -280,10 +291,12 @@ const DiffFileHeader = memo(function DiffFileHeader({
|
|||||||
|
|
||||||
function DiffFileBody({
|
function DiffFileBody({
|
||||||
file,
|
file,
|
||||||
|
wrapLines,
|
||||||
onBodyHeightChange,
|
onBodyHeightChange,
|
||||||
testID,
|
testID,
|
||||||
}: {
|
}: {
|
||||||
file: ParsedDiffFile;
|
file: ParsedDiffFile;
|
||||||
|
wrapLines: boolean;
|
||||||
onBodyHeightChange?: (path: string, height: number) => void;
|
onBodyHeightChange?: (path: string, height: number) => void;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
}) {
|
}) {
|
||||||
@@ -332,39 +345,86 @@ function DiffFileBody({
|
|||||||
}}
|
}}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
>
|
>
|
||||||
{file.status === "too_large" || file.status === "binary" ? (
|
{(() => {
|
||||||
<View style={styles.statusMessageContainer}>
|
if (file.status === "too_large" || file.status === "binary") {
|
||||||
<Text style={styles.statusMessageText}>
|
return (
|
||||||
{file.status === "binary" ? "Binary file" : "Diff too large to display"}
|
<View style={styles.statusMessageContainer}>
|
||||||
</Text>
|
<Text style={styles.statusMessageText}>
|
||||||
</View>
|
{file.status === "binary" ? "Binary file" : "Diff too large to display"}
|
||||||
) : (
|
</Text>
|
||||||
<ScrollView
|
</View>
|
||||||
ref={scrollViewRef}
|
);
|
||||||
horizontal
|
}
|
||||||
nestedScrollEnabled
|
|
||||||
showsHorizontalScrollIndicator
|
const linesContent = (() => {
|
||||||
bounces={false}
|
let maxLineNo = 0;
|
||||||
style={styles.diffContent}
|
for (const hunk of file.hunks) {
|
||||||
contentContainerStyle={styles.diffContentInner}
|
maxLineNo = Math.max(maxLineNo, hunk.oldStart + hunk.oldCount, hunk.newStart + hunk.newCount);
|
||||||
onScroll={handleScroll}
|
}
|
||||||
scrollEventThrottle={16}
|
const digitCount = Math.max(1, String(maxLineNo).length);
|
||||||
onLayout={(e) => setScrollViewWidth(e.nativeEvent.layout.width)}
|
const gutterWidth = digitCount * 8 + 12;
|
||||||
// When at left edge, wait for close gesture to fail before scrolling.
|
return file.hunks.map((hunk, hunkIndex) => {
|
||||||
// The close gesture fails quickly on leftward swipes (failOffsetX=-10),
|
let oldLineNo = hunk.oldStart;
|
||||||
// so scrolling left works normally. On rightward swipes, close gesture
|
let newLineNo = hunk.newStart;
|
||||||
// activates and closes the sidebar.
|
return hunk.lines.map((line, lineIndex) => {
|
||||||
waitFor={isAtLeftEdge && closeGestureRef?.current ? closeGestureRef : undefined}
|
let lineNumber: number | null = null;
|
||||||
>
|
if (line.type === "remove") {
|
||||||
<View style={[styles.linesContainer, scrollViewWidth > 0 && { minWidth: scrollViewWidth }]}>
|
lineNumber = oldLineNo;
|
||||||
{file.hunks.map((hunk, hunkIndex) =>
|
oldLineNo++;
|
||||||
hunk.lines.map((line, lineIndex) => (
|
} else if (line.type === "add") {
|
||||||
<DiffLineView key={`${hunkIndex}-${lineIndex}`} line={line} />
|
lineNumber = newLineNo;
|
||||||
))
|
newLineNo++;
|
||||||
)}
|
} else if (line.type === "context") {
|
||||||
</View>
|
lineNumber = newLineNo;
|
||||||
</ScrollView>
|
oldLineNo++;
|
||||||
)}
|
newLineNo++;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<DiffLineView
|
||||||
|
key={`${hunkIndex}-${lineIndex}`}
|
||||||
|
line={line}
|
||||||
|
lineNumber={lineNumber}
|
||||||
|
gutterWidth={gutterWidth}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (wrapLines) {
|
||||||
|
return (
|
||||||
|
<View style={styles.diffContent}>
|
||||||
|
<View style={styles.linesContainer}>
|
||||||
|
{linesContent}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView
|
||||||
|
ref={scrollViewRef}
|
||||||
|
horizontal
|
||||||
|
nestedScrollEnabled
|
||||||
|
showsHorizontalScrollIndicator
|
||||||
|
bounces={false}
|
||||||
|
style={styles.diffContent}
|
||||||
|
contentContainerStyle={styles.diffContentInner}
|
||||||
|
onScroll={handleScroll}
|
||||||
|
scrollEventThrottle={16}
|
||||||
|
onLayout={(e) => setScrollViewWidth(e.nativeEvent.layout.width)}
|
||||||
|
// When at left edge, wait for close gesture to fail before scrolling.
|
||||||
|
// The close gesture fails quickly on leftward swipes (failOffsetX=-10),
|
||||||
|
// so scrolling left works normally. On rightward swipes, close gesture
|
||||||
|
// activates and closes the sidebar.
|
||||||
|
waitFor={isAtLeftEdge && closeGestureRef?.current ? closeGestureRef : undefined}
|
||||||
|
>
|
||||||
|
<View style={[styles.linesContainer, scrollViewWidth > 0 && { minWidth: scrollViewWidth }]}>
|
||||||
|
{linesContent}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -390,6 +450,22 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
|||||||
const [actionError, setActionError] = useState<string | null>(null);
|
const [actionError, setActionError] = useState<string | null>(null);
|
||||||
const [postShipArchiveSuggested, setPostShipArchiveSuggested] = useState(false);
|
const [postShipArchiveSuggested, setPostShipArchiveSuggested] = useState(false);
|
||||||
const [shipDefault, setShipDefault] = useState<"merge" | "pr">("merge");
|
const [shipDefault, setShipDefault] = useState<"merge" | "pr">("merge");
|
||||||
|
const [wrapLines, setWrapLines] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
AsyncStorage.getItem("diff-wrap-lines").then((value) => {
|
||||||
|
if (value === "true") setWrapLines(true);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleToggleWrapLines = useCallback(() => {
|
||||||
|
setWrapLines((prev) => {
|
||||||
|
const next = !prev;
|
||||||
|
AsyncStorage.setItem("diff-wrap-lines", String(next));
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const { status, isLoading: isStatusLoading, isFetching: isStatusFetching, isError: isStatusError, error: statusError, refresh: refreshStatus } =
|
const { status, isLoading: isStatusLoading, isFetching: isStatusFetching, isError: isStatusError, error: statusError, refresh: refreshStatus } =
|
||||||
useCheckoutStatusQuery({ serverId, cwd });
|
useCheckoutStatusQuery({ serverId, cwd });
|
||||||
const gitStatus = status && status.isGit ? status : null;
|
const gitStatus = status && status.isGit ? status : null;
|
||||||
@@ -736,12 +812,13 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
|||||||
return (
|
return (
|
||||||
<DiffFileBody
|
<DiffFileBody
|
||||||
file={item.file}
|
file={item.file}
|
||||||
|
wrapLines={wrapLines}
|
||||||
onBodyHeightChange={handleBodyHeightChange}
|
onBodyHeightChange={handleBodyHeightChange}
|
||||||
testID={`diff-file-${item.fileIndex}-body`}
|
testID={`diff-file-${item.fileIndex}-body`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[handleBodyHeightChange, handleHeaderHeightChange, handleToggleExpanded]
|
[handleBodyHeightChange, handleHeaderHeightChange, handleToggleExpanded, wrapLines]
|
||||||
);
|
);
|
||||||
|
|
||||||
const flatKeyExtractor = useCallback(
|
const flatKeyExtractor = useCallback(
|
||||||
@@ -1018,19 +1095,48 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
|||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
{files.length > 0 ? (
|
{files.length > 0 ? (
|
||||||
<Pressable
|
<View style={styles.diffStatusButtons}>
|
||||||
style={({ hovered, pressed }) => [
|
<Tooltip delayDuration={300}>
|
||||||
styles.expandAllButton,
|
<TooltipTrigger asChild>
|
||||||
(hovered || pressed) && styles.diffStatusRowHovered,
|
<Pressable
|
||||||
]}
|
style={({ hovered, pressed }) => [
|
||||||
onPress={handleToggleExpandAll}
|
styles.expandAllButton,
|
||||||
>
|
(hovered || pressed) && styles.diffStatusRowHovered,
|
||||||
{allExpanded ? (
|
]}
|
||||||
<ListChevronsDownUp size={14} color={theme.colors.foregroundMuted} />
|
onPress={handleToggleWrapLines}
|
||||||
) : (
|
>
|
||||||
<ListChevronsUpDown size={14} color={theme.colors.foregroundMuted} />
|
<WrapText size={isMobile ? 18 : 14} color={theme.colors.foregroundMuted} />
|
||||||
)}
|
</Pressable>
|
||||||
</Pressable>
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="bottom">
|
||||||
|
<Text style={styles.tooltipText}>
|
||||||
|
{wrapLines ? "Scroll long lines" : "Wrap long lines"}
|
||||||
|
</Text>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip delayDuration={300}>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Pressable
|
||||||
|
style={({ hovered, pressed }) => [
|
||||||
|
styles.expandAllButton,
|
||||||
|
(hovered || pressed) && styles.diffStatusRowHovered,
|
||||||
|
]}
|
||||||
|
onPress={handleToggleExpandAll}
|
||||||
|
>
|
||||||
|
{allExpanded ? (
|
||||||
|
<ListChevronsDownUp size={isMobile ? 18 : 14} color={theme.colors.foregroundMuted} />
|
||||||
|
) : (
|
||||||
|
<ListChevronsUpDown size={isMobile ? 18 : 14} color={theme.colors.foregroundMuted} />
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="bottom">
|
||||||
|
<Text style={styles.tooltipText}>
|
||||||
|
{allExpanded ? "Collapse all files" : "Expand all files"}
|
||||||
|
</Text>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -1125,13 +1231,30 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
diffStatusIconHidden: {
|
diffStatusIconHidden: {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
},
|
},
|
||||||
|
diffStatusButtons: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: {
|
||||||
|
xs: theme.spacing[1],
|
||||||
|
sm: theme.spacing[1],
|
||||||
|
md: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
expandAllButton: {
|
expandAllButton: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: theme.spacing[1],
|
gap: theme.spacing[1],
|
||||||
marginVertical: theme.spacing[2],
|
marginVertical: theme.spacing[2],
|
||||||
paddingHorizontal: theme.spacing[1],
|
paddingHorizontal: {
|
||||||
paddingVertical: theme.spacing[1],
|
xs: theme.spacing[2],
|
||||||
|
sm: theme.spacing[2],
|
||||||
|
md: theme.spacing[1],
|
||||||
|
},
|
||||||
|
paddingVertical: {
|
||||||
|
xs: theme.spacing[2],
|
||||||
|
sm: theme.spacing[2],
|
||||||
|
md: theme.spacing[1],
|
||||||
|
},
|
||||||
borderRadius: theme.borderRadius.base,
|
borderRadius: theme.borderRadius.base,
|
||||||
},
|
},
|
||||||
actionErrorText: {
|
actionErrorText: {
|
||||||
@@ -1289,10 +1412,34 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
backgroundColor: theme.colors.surface1,
|
backgroundColor: theme.colors.surface1,
|
||||||
},
|
},
|
||||||
diffLineContainer: {
|
diffLineContainer: {
|
||||||
paddingHorizontal: theme.spacing[3],
|
flexDirection: "row",
|
||||||
|
alignItems: "stretch",
|
||||||
|
},
|
||||||
|
lineNumberGutter: {
|
||||||
|
borderRightWidth: theme.borderWidth[1],
|
||||||
|
borderRightColor: theme.colors.border,
|
||||||
|
marginRight: theme.spacing[2],
|
||||||
|
alignSelf: "stretch",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
lineNumberText: {
|
||||||
|
textAlign: "right",
|
||||||
|
paddingRight: theme.spacing[2],
|
||||||
paddingVertical: theme.spacing[1],
|
paddingVertical: theme.spacing[1],
|
||||||
|
fontSize: theme.fontSize.xs,
|
||||||
|
fontFamily: Fonts.mono,
|
||||||
|
color: theme.colors.foregroundMuted,
|
||||||
|
},
|
||||||
|
addLineNumberText: {
|
||||||
|
color: theme.colors.palette.green[400],
|
||||||
|
},
|
||||||
|
removeLineNumberText: {
|
||||||
|
color: theme.colors.palette.red[500],
|
||||||
},
|
},
|
||||||
diffLineText: {
|
diffLineText: {
|
||||||
|
flex: 1,
|
||||||
|
paddingRight: theme.spacing[3],
|
||||||
|
paddingVertical: theme.spacing[1],
|
||||||
fontSize: theme.fontSize.xs,
|
fontSize: theme.fontSize.xs,
|
||||||
fontFamily: Fonts.mono,
|
fontFamily: Fonts.mono,
|
||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
@@ -1333,4 +1480,8 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
color: theme.colors.foregroundMuted,
|
color: theme.colors.foregroundMuted,
|
||||||
fontStyle: "italic",
|
fontStyle: "italic",
|
||||||
},
|
},
|
||||||
|
tooltipText: {
|
||||||
|
fontSize: theme.fontSize.xs,
|
||||||
|
color: theme.colors.foreground,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
ref
|
ref
|
||||||
) {
|
) {
|
||||||
const { theme } = useUnistyles()
|
const { theme } = useUnistyles()
|
||||||
|
const buttonIconSize = IS_WEB ? theme.iconSize.md : theme.iconSize.lg
|
||||||
const investigationComponentId = `MessageInput:${voiceServerId ?? 'unknown-server'}:${voiceAgentId ?? 'unknown-agent'}`
|
const investigationComponentId = `MessageInput:${voiceServerId ?? 'unknown-server'}:${voiceAgentId ?? 'unknown-agent'}`
|
||||||
markScrollInvestigationRender(investigationComponentId)
|
markScrollInvestigationRender(investigationComponentId)
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
@@ -950,7 +951,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
(!isConnected || disabled) && styles.buttonDisabled,
|
(!isConnected || disabled) && styles.buttonDisabled,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Paperclip size={theme.iconSize.md} color={theme.colors.foreground} />
|
<Paperclip size={buttonIconSize} color={theme.colors.foreground} />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
<Text style={styles.tooltipText}>Attach images</Text>
|
<Text style={styles.tooltipText}>Attach images</Text>
|
||||||
@@ -984,11 +985,11 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{isDictating ? (
|
{isDictating ? (
|
||||||
<Square size={theme.iconSize.md} color="white" fill="white" />
|
<Square size={buttonIconSize} color="white" fill="white" />
|
||||||
) : isRealtimeVoiceForCurrentAgent && voice?.isMuted ? (
|
) : isRealtimeVoiceForCurrentAgent && voice?.isMuted ? (
|
||||||
<MicOff size={theme.iconSize.md} color={theme.colors.foreground} />
|
<MicOff size={buttonIconSize} color={theme.colors.foreground} />
|
||||||
) : (
|
) : (
|
||||||
<Mic size={theme.iconSize.md} color={theme.colors.foreground} />
|
<Mic size={buttonIconSize} color={theme.colors.foreground} />
|
||||||
)}
|
)}
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
@@ -1021,7 +1022,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
(!isConnected || disabled) && styles.buttonDisabled,
|
(!isConnected || disabled) && styles.buttonDisabled,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Plus size={theme.iconSize.md} color="white" />
|
<Plus size={buttonIconSize} color="white" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
<View style={styles.tooltipRow}>
|
<View style={styles.tooltipRow}>
|
||||||
@@ -1043,7 +1044,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
{isSubmitLoading ? (
|
{isSubmitLoading ? (
|
||||||
<ActivityIndicator size="small" color="white" />
|
<ActivityIndicator size="small" color="white" />
|
||||||
) : (
|
) : (
|
||||||
<ArrowUp size={theme.iconSize.md} color="white" />
|
<ArrowUp size={buttonIconSize} color="white" />
|
||||||
)}
|
)}
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
@@ -1184,12 +1185,12 @@ const styles = StyleSheet.create(((theme: any) => ({
|
|||||||
leftButtonGroup: {
|
leftButtonGroup: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'flex-end',
|
alignItems: 'flex-end',
|
||||||
gap: theme.spacing[2],
|
gap: Platform.OS === 'web' ? theme.spacing[2] : theme.spacing[1],
|
||||||
},
|
},
|
||||||
rightButtonGroup: {
|
rightButtonGroup: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: theme.spacing[2],
|
gap: Platform.OS === 'web' ? theme.spacing[2] : theme.spacing[1],
|
||||||
},
|
},
|
||||||
attachButton: {
|
attachButton: {
|
||||||
width: 28,
|
width: 28,
|
||||||
|
|||||||
Reference in New Issue
Block a user