refactor: unify layout widths and font sizes

- Add MAX_CONTENT_WIDTH (820px) constant for consistent chat/form widths
- Bump theme font sizes (base now 16px) for better readability
- Apply max width to stream view, input area, and new agent form
- Position new agent form at bottom of scroll area
- Remove working directory helper text
- Add cmd+b sidebar toggle when textarea is focused
This commit is contained in:
Mohamed Boudra
2026-01-09 19:11:35 +07:00
parent 2d03e86bcb
commit 584b0413a5
8 changed files with 33 additions and 23 deletions

View File

@@ -26,6 +26,7 @@ import { useDaemonConnections } from "@/contexts/daemon-connections-context";
import { formatConnectionStatus } from "@/utils/daemons";
import { useSessionStore } from "@/stores/session-store";
import { generateMessageId } from "@/types/stream";
import { MAX_CONTENT_WIDTH } from "@/constants/layout";
import type {
AgentProvider,
AgentSessionConfig,
@@ -843,12 +844,16 @@ const styles = StyleSheet.create((theme) => ({
},
configScrollContent: {
flexGrow: 1,
justifyContent: "flex-end",
},
configSection: {
paddingHorizontal: theme.spacing[4],
paddingTop: theme.spacing[3],
paddingBottom: theme.spacing[4],
gap: theme.spacing[2],
maxWidth: MAX_CONTENT_WIDTH,
alignSelf: "center",
width: "100%",
},
configRow: {
flexDirection: "row",

View File

@@ -619,11 +619,6 @@ export function WorkingDirectoryDropdown({
onPress={handleOpen}
disabled={disabled}
errorMessage={errorMessage || undefined}
helperText={
hasSuggestedPaths
? "Search directories from existing agents or paste a new path."
: "No agent directories yet - search to add one."
}
controlRef={anchorRef}
/>
<AdaptiveSelect

View File

@@ -16,7 +16,7 @@ import Animated, {
import { useReanimatedKeyboardAnimation } from "react-native-keyboard-controller";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useRealtime } from "@/contexts/realtime-context";
import { FOOTER_HEIGHT } from "@/constants/layout";
import { FOOTER_HEIGHT, MAX_CONTENT_WIDTH } from "@/constants/layout";
import { generateMessageId } from "@/types/stream";
import { AgentStatusBar } from "./agent-status-bar";
import { RealtimeControls } from "./realtime-controls";
@@ -52,7 +52,6 @@ interface AgentInputAreaProps {
}
const EMPTY_ARRAY: readonly QueuedMessage[] = [];
const MAX_INPUT_WIDTH = 960;
// Android currently crashes inside ViewGroup.dispatchDraw when running Reanimated
// entering/exiting animations (see react-native-reanimated#8422), so guard them.
const SHOULD_DISABLE_ENTRY_EXIT_ANIMATIONS = Platform.OS === "android";
@@ -525,7 +524,7 @@ const styles = StyleSheet.create(((theme: Theme) => ({
},
inputAreaContent: {
width: "100%",
maxWidth: MAX_INPUT_WIDTH,
maxWidth: MAX_CONTENT_WIDTH,
gap: theme.spacing[3],
},
realtimeButton: {

View File

@@ -43,8 +43,7 @@ import {
} from "@/utils/tool-call-parsers";
import { ToolCallSheetProvider } from "./tool-call-sheet";
import { createMarkdownStyles } from "@/styles/markdown-styles";
const MAX_CHAT_WIDTH = 960;
import { MAX_CONTENT_WIDTH } from "@/constants/layout";
type PermissionResolvedMessage = Extract<
SessionOutboundMessage,
{ type: "agent_permission_resolved" }
@@ -1024,7 +1023,7 @@ const stylesheet = StyleSheet.create((theme) => ({
},
contentWrapper: {
width: "100%",
maxWidth: MAX_CHAT_WIDTH,
maxWidth: MAX_CONTENT_WIDTH,
alignSelf: "center",
},
list: {
@@ -1033,7 +1032,7 @@ const stylesheet = StyleSheet.create((theme) => ({
},
streamItemWrapper: {
width: "100%",
maxWidth: MAX_CHAT_WIDTH,
maxWidth: MAX_CONTENT_WIDTH,
alignSelf: "center",
},
emptyState: {
@@ -1096,7 +1095,7 @@ const stylesheet = StyleSheet.create((theme) => ({
},
scrollToBottomInner: {
width: "100%",
maxWidth: MAX_CHAT_WIDTH,
maxWidth: MAX_CONTENT_WIDTH,
alignSelf: "center",
alignItems: "center",
},

View File

@@ -28,6 +28,7 @@ import { useDictation } from "@/hooks/use-dictation";
import { DictationOverlay } from "./dictation-controls";
import type { UseWebSocketReturn } from "@/hooks/use-websocket";
import type { SessionContextValue } from "@/contexts/session-context";
import { useSidebarStore } from "@/stores/sidebar-store";
export interface ImageAttachment {
uri: string;
@@ -113,6 +114,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
ref
) {
const { theme } = useUnistyles();
const toggleSidebar = useSidebarStore((state) => state.toggle);
const [inputHeight, setInputHeight] = useState(MIN_INPUT_HEIGHT);
const textInputRef = useRef<
TextInput | (TextInput & { getNativeRef?: () => unknown }) | null
@@ -383,6 +385,13 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
if (!shouldHandleDesktopSubmit) return;
const { shiftKey, metaKey, ctrlKey } = event.nativeEvent;
// Cmd+B or Ctrl+B: toggle sidebar
if ((metaKey || ctrlKey) && event.nativeEvent.key === "b") {
event.preventDefault();
toggleSidebar();
return;
}
// Cmd+D or Ctrl+D: start dictation or submit if already dictating
if ((metaKey || ctrlKey) && event.nativeEvent.key === "d") {
event.preventDefault();

View File

@@ -56,8 +56,8 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
},
text: {
color: theme.colors.foreground,
fontSize: theme.fontSize.lg,
lineHeight: 24,
fontSize: theme.fontSize.base,
lineHeight: 22,
},
bubblePressed: {
opacity: 0.85,

View File

@@ -4,3 +4,6 @@ export const FOOTER_HEIGHT = 75;
// Used by both agent header (ScreenHeader) and explorer sidebar header
// This ensures both headers have the same visual height
export const HEADER_INNER_HEIGHT = 48;
// Max width for chat content (stream view, input area, new agent form)
export const MAX_CONTENT_WIDTH = 820;

View File

@@ -167,14 +167,14 @@ const commonTheme = {
},
fontSize: {
xs: 10,
sm: 12,
base: 14,
lg: 16,
xl: 18,
"2xl": 20,
"3xl": 24,
"4xl": 32,
xs: 12,
sm: 14,
base: 16,
lg: 18,
xl: 20,
"2xl": 22,
"3xl": 26,
"4xl": 34,
},
fontWeight: {