authorgravatar for jappyjan@users.noreply.github.comJan Jaap <jappyjan@users.noreply.github.com> 2026-05-01 01:26:36+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-04-30 16:26:36-07:00
logd649ccf71598a38aac6ea0e7f2f9c034b1bc78b1
treebb27d77bee4c461133a35b0f29ce62bdbae41407
parentf54f4385e518504f87001afef51bdf3b0be2a5be
signature Signed by PGP key B5690EEEBB952194

fix(web): respect iOS safe areas across mobile chrome & other mobile layout fixes (#2392)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com>

13 files changed, 277 insertions(+), 65 deletions(-)

apps/web/index.html+4-1
......@@ -2,7 +2,10 @@
22<html lang="en">
33 <head>
44 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
5 <meta
6 name="viewport"
7 content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content"
8 />
69 <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
710 <meta name="theme-color" content="#161616" media="(prefers-color-scheme: dark)" />
811 <meta name="theme-color" content="#161616" />
apps/web/src/components/AppSidebarLayout.tsx+1-1
......@@ -54,7 +54,7 @@ export function AppSidebarLayout({ children }: { children: ReactNode }) {
5454 }, [navigate]);
5555
5656 return (
57 <SidebarProvider defaultOpen>
57 <SidebarProvider className="h-dvh! min-h-0!" defaultOpen>
5858 <Sidebar
5959 side="left"
6060 collapsible="offcanvas"
apps/web/src/components/BranchToolbar.tsx+178-18
......@@ -1,18 +1,41 @@
11import { scopeProjectRef, scopeThreadRef } from "@t3tools/client-runtime";
22import type { EnvironmentId, ThreadId } from "@t3tools/contracts";
3import {
4 ChevronDownIcon,
5 CloudIcon,
6 FolderGit2Icon,
7 FolderGitIcon,
8 FolderIcon,
9 MonitorIcon,
10} from "lucide-react";
311import { memo, useMemo } from "react";
412
513import { useComposerDraftStore, type DraftId } from "../composerDraftStore";
14import { useIsMobile } from "../hooks/useMediaQuery";
615import { useStore } from "../store";
716import { createProjectSelectorByRef, createThreadSelectorByRef } from "../storeSelectors";
817import {
918 type EnvMode,
1019 type EnvironmentOption,
20 resolveCurrentWorkspaceLabel,
21 resolveEnvModeLabel,
1122 resolveEffectiveEnvMode,
23 resolveLockedWorkspaceLabel,
1224} from "./BranchToolbar.logic";
1325import { BranchToolbarBranchSelector } from "./BranchToolbarBranchSelector";
1426import { BranchToolbarEnvironmentSelector } from "./BranchToolbarEnvironmentSelector";
1527import { BranchToolbarEnvModeSelector } from "./BranchToolbarEnvModeSelector";
28import { Button } from "./ui/button";
29import {
30 Menu,
31 MenuGroup,
32 MenuGroupLabel,
33 MenuPopup,
34 MenuRadioGroup,
35 MenuRadioItem,
36 MenuSeparator,
37 MenuTrigger,
38} from "./ui/menu";
1639import { Separator } from "./ui/separator";
1740
1841interface BranchToolbarProps {
......@@ -30,6 +53,126 @@ interface BranchToolbarProps {
3053 onEnvironmentChange?: (environmentId: EnvironmentId) => void;
3154}
3255
56interface MobileRunContextSelectorProps {
57 envLocked: boolean;
58 envModeLocked: boolean;
59 environmentId: EnvironmentId;
60 availableEnvironments: readonly EnvironmentOption[] | undefined;
61 showEnvironmentPicker: boolean;
62 onEnvironmentChange: ((environmentId: EnvironmentId) => void) | undefined;
63 effectiveEnvMode: EnvMode;
64 activeWorktreePath: string | null;
65 onEnvModeChange: (mode: EnvMode) => void;
66}
67
68const MobileRunContextSelector = memo(function MobileRunContextSelector({
69 envLocked,
70 envModeLocked,
71 environmentId,
72 availableEnvironments,
73 showEnvironmentPicker,
74 onEnvironmentChange,
75 effectiveEnvMode,
76 activeWorktreePath,
77 onEnvModeChange,
78}: MobileRunContextSelectorProps) {
79 const activeEnvironment = useMemo(
80 () => availableEnvironments?.find((env) => env.environmentId === environmentId) ?? null,
81 [availableEnvironments, environmentId],
82 );
83 const environmentLabel = activeEnvironment?.label ?? "Run on";
84 const EnvironmentIcon = activeEnvironment?.isPrimary ? MonitorIcon : CloudIcon;
85 const WorkspaceIcon =
86 effectiveEnvMode === "worktree"
87 ? FolderGit2Icon
88 : activeWorktreePath
89 ? FolderGitIcon
90 : FolderIcon;
91 const workspaceLabel = envModeLocked
92 ? resolveLockedWorkspaceLabel(activeWorktreePath)
93 : effectiveEnvMode === "worktree"
94 ? resolveEnvModeLabel("worktree")
95 : resolveCurrentWorkspaceLabel(activeWorktreePath);
96
97 return (
98 <Menu>
99 <MenuTrigger
100 render={<Button variant="ghost" size="xs" />}
101 className="min-w-0 max-w-[48%] flex-1 justify-start text-muted-foreground/70 hover:text-foreground/80 md:hidden"
102 >
103 {showEnvironmentPicker ? (
104 <>
105 <EnvironmentIcon className="size-3 shrink-0" />
106 <span className="min-w-0 truncate">{environmentLabel}</span>
107 </>
108 ) : (
109 <>
110 <WorkspaceIcon className="size-3 shrink-0" />
111 <span className="min-w-0 truncate">{workspaceLabel}</span>
112 </>
113 )}
114 <ChevronDownIcon className="size-3 shrink-0 opacity-50" />
115 </MenuTrigger>
116 <MenuPopup align="start" side="top" className="w-64">
117 {showEnvironmentPicker && availableEnvironments && onEnvironmentChange ? (
118 <>
119 <MenuGroup>
120 <MenuGroupLabel>Run on</MenuGroupLabel>
121 <MenuRadioGroup
122 value={environmentId}
123 onValueChange={(value) => onEnvironmentChange(value as EnvironmentId)}
124 >
125 {availableEnvironments.map((env) => {
126 const Icon = env.isPrimary ? MonitorIcon : CloudIcon;
127 return (
128 <MenuRadioItem
129 key={env.environmentId}
130 disabled={envLocked}
131 value={env.environmentId}
132 >
133 <span className="flex min-w-0 items-center gap-1.5">
134 <Icon className="size-3" />
135 <span className="min-w-0 truncate">{env.label}</span>
136 </span>
137 </MenuRadioItem>
138 );
139 })}
140 </MenuRadioGroup>
141 </MenuGroup>
142 <MenuSeparator />
143 </>
144 ) : null}
145 <MenuGroup>
146 <MenuGroupLabel>Workspace</MenuGroupLabel>
147 <MenuRadioGroup
148 value={effectiveEnvMode}
149 onValueChange={(value) => onEnvModeChange(value as EnvMode)}
150 >
151 <MenuRadioItem disabled={envModeLocked} value="local">
152 <span className="flex min-w-0 items-center gap-1.5">
153 {activeWorktreePath ? (
154 <FolderGitIcon className="size-3" />
155 ) : (
156 <FolderIcon className="size-3" />
157 )}
158 <span className="min-w-0 truncate">
159 {resolveCurrentWorkspaceLabel(activeWorktreePath)}
160 </span>
161 </span>
162 </MenuRadioItem>
163 <MenuRadioItem disabled={envModeLocked} value="worktree">
164 <span className="flex min-w-0 items-center gap-1.5">
165 <FolderGit2Icon className="size-3" />
166 <span className="min-w-0 truncate">{resolveEnvModeLabel("worktree")}</span>
167 </span>
168 </MenuRadioItem>
169 </MenuRadioGroup>
170 </MenuGroup>
171 </MenuPopup>
172 </Menu>
173 );
174});
175
33176export const BranchToolbar = memo(function BranchToolbar({
34177 environmentId,
35178 threadId,
......@@ -74,34 +217,51 @@ export const BranchToolbar = memo(function BranchToolbar({
74217 });
75218 const envModeLocked = envLocked || (serverThread !== undefined && activeWorktreePath !== null);
76219
77 const showEnvironmentPicker =
78 availableEnvironments && availableEnvironments.length > 1 && onEnvironmentChange;
220 const showEnvironmentPicker = Boolean(
221 availableEnvironments && availableEnvironments.length > 1 && onEnvironmentChange,
222 );
223 const isMobile = useIsMobile();
79224
80225 if (!hasActiveThread || !activeProject) return null;
81226
82227 return (
83 <div className="mx-auto flex w-full max-w-208 items-center justify-between px-2.5 pb-3 pt-1 sm:px-3">
84 <div className="flex items-center gap-1">
85 {showEnvironmentPicker && (
86 <>
87 <BranchToolbarEnvironmentSelector
88 envLocked={envLocked}
89 environmentId={environmentId}
90 availableEnvironments={availableEnvironments}
91 onEnvironmentChange={onEnvironmentChange}
92 />
93 <Separator orientation="vertical" className="mx-0.5 h-3.5!" />
94 </>
95 )}
96 <BranchToolbarEnvModeSelector
97 envLocked={envModeLocked}
228 <div className="mx-auto flex w-full max-w-208 items-center gap-2 px-2.5 pb-3 pt-1 sm:px-3">
229 {isMobile ? (
230 <MobileRunContextSelector
231 envLocked={envLocked}
232 envModeLocked={envModeLocked}
233 environmentId={environmentId}
234 availableEnvironments={availableEnvironments}
235 showEnvironmentPicker={showEnvironmentPicker}
236 onEnvironmentChange={onEnvironmentChange}
98237 effectiveEnvMode={effectiveEnvMode}
99238 activeWorktreePath={activeWorktreePath}
100239 onEnvModeChange={onEnvModeChange}
101240 />
102 </div>
241 ) : (
242 <div className="flex min-w-0 shrink-0 items-center gap-1">
243 {showEnvironmentPicker && availableEnvironments && onEnvironmentChange && (
244 <>
245 <BranchToolbarEnvironmentSelector
246 envLocked={envLocked}
247 environmentId={environmentId}
248 availableEnvironments={availableEnvironments}
249 onEnvironmentChange={onEnvironmentChange}
250 />
251 <Separator orientation="vertical" className="mx-0.5 h-3.5!" />
252 </>
253 )}
254 <BranchToolbarEnvModeSelector
255 envLocked={envModeLocked}
256 effectiveEnvMode={effectiveEnvMode}
257 activeWorktreePath={activeWorktreePath}
258 onEnvModeChange={onEnvModeChange}
259 />
260 </div>
261 )}
103262
104263 <BranchToolbarBranchSelector
264 className="min-w-0 flex-1 justify-end md:ml-auto md:flex-none"
105265 environmentId={environmentId}
106266 threadId={threadId}
107267 {...(draftId ? { draftId } : {})}
apps/web/src/components/BranchToolbarBranchSelector.tsx+6-3
......@@ -19,6 +19,7 @@ import { readEnvironmentApi } from "../environmentApi";
1919import { gitBranchSearchInfiniteQueryOptions, gitQueryKeys } from "../lib/gitReactQuery";
2020import { useGitStatus } from "../lib/gitStatusState";
2121import { newCommandId } from "../lib/utils";
22import { cn } from "../lib/utils";
2223import { parsePullRequestReference } from "../pullRequestReference";
2324import { useStore } from "../store";
2425import { createProjectSelectorByRef, createThreadSelectorByRef } from "../storeSelectors";
......@@ -45,6 +46,7 @@ import {
4546import { stackedThreadToast, toastManager } from "./ui/toast";
4647
4748interface BranchToolbarBranchSelectorProps {
49 className?: string;
4850 environmentId: EnvironmentId;
4951 threadId: ThreadId;
5052 draftId?: DraftId;
......@@ -76,6 +78,7 @@ function getBranchTriggerLabel(input: {
7678}
7779
7880export function BranchToolbarBranchSelector({
81 className,
7982 environmentId,
8083 threadId,
8184 draftId,
......@@ -577,11 +580,11 @@ export function BranchToolbarBranchSelector({
577580 >
578581 <ComboboxTrigger
579582 render={<Button variant="ghost" size="xs" />}
580 className="text-muted-foreground/70 hover:text-foreground/80"
583 className={cn("min-w-0 text-muted-foreground/70 hover:text-foreground/80", className)}
581584 disabled={(isBranchesSearchPending && branches.length === 0) || isBranchActionPending}
582585 >
583 <span className="max-w-[240px] truncate">{triggerLabel}</span>
584 <ChevronDownIcon />
586 <span className="min-w-0 max-w-[240px] truncate">{triggerLabel}</span>
587 <ChevronDownIcon className="shrink-0" />
585588 </ComboboxTrigger>
586589 <ComboboxPopup align="end" side="top" className="w-80">
587590 <div className="border-b p-1">
apps/web/src/components/BranchToolbarEnvModeSelector.tsx+1
......@@ -58,6 +58,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe
5858
5959 return (
6060 <Select
61 modal={false}
6162 value={effectiveEnvMode}
6263 onValueChange={(value) => onEnvModeChange(value as EnvMode)}
6364 items={envModeItems}
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx+1
......@@ -54,6 +54,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir
5454
5555 return (
5656 <Select
57 modal={false}
5758 value={environmentId}
5859 onValueChange={(value) => onEnvironmentChange(value as EnvironmentId)}
5960 items={environmentItems}
apps/web/src/components/ChatView.tsx+37-30
......@@ -3281,14 +3281,14 @@ export default function ChatView(props: ChatViewProps) {
32813281 {/* Top bar */}
32823282 <header
32833283 className={cn(
3284 "border-b border-border px-3 sm:px-5",
3284 "border-b border-border",
32853285 isElectron
32863286 ? cn(
3287 "drag-region flex h-[52px] items-center wco:h-[env(titlebar-area-height)]",
3287 "drag-region flex h-[52px] items-center px-3 sm:px-5 wco:h-[env(titlebar-area-height)]",
32883288 reserveTitleBarControlInset &&
32893289 "wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]",
32903290 )
3291 : "py-2 sm:py-3",
3291 : "pb-2 pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] pt-2 sm:pb-3 sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)] sm:pt-3",
32923292 )}
32933293 >
32943294 <ChatHeader
......@@ -3374,7 +3374,14 @@ export default function ChatView(props: ChatViewProps) {
33743374 </div>
33753375
33763376 {/* Input bar */}
3377 <div className={cn("px-3 pt-1.5 sm:px-5 sm:pt-2", isGitRepo ? "pb-1" : "pb-3 sm:pb-4")}>
3377 <div
3378 className={cn(
3379 "pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] pt-1.5 sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)] sm:pt-2",
3380 isGitRepo
3381 ? "pb-[calc(env(safe-area-inset-bottom)+0.25rem)]"
3382 : "pb-[calc(env(safe-area-inset-bottom)+0.75rem)] sm:pb-[calc(env(safe-area-inset-bottom)+1rem)]",
3383 )}
3384 >
33783385 <ChatComposer
33793386 ref={composerRef}
33803387 composerDraftTarget={composerDraftTarget}
......@@ -3443,34 +3450,34 @@ export default function ChatView(props: ChatViewProps) {
34433450 setThreadError={setThreadError}
34443451 onExpandImage={onExpandTimelineImage}
34453452 />
3453 {isGitRepo && (
3454 <BranchToolbar
3455 environmentId={activeThread.environmentId}
3456 threadId={activeThread.id}
3457 {...(routeKind === "draft" && draftId ? { draftId } : {})}
3458 onEnvModeChange={onEnvModeChange}
3459 {...(canOverrideServerThreadEnvMode ? { effectiveEnvModeOverride: envMode } : {})}
3460 {...(canOverrideServerThreadEnvMode
3461 ? {
3462 activeThreadBranchOverride: activeThreadBranch,
3463 onActiveThreadBranchOverrideChange: setPendingServerThreadBranch,
3464 }
3465 : {})}
3466 envLocked={envLocked}
3467 onComposerFocusRequest={scheduleComposerFocus}
3468 {...(canCheckoutPullRequestIntoThread
3469 ? { onCheckoutPullRequestRequest: openPullRequestDialog }
3470 : {})}
3471 {...(hasMultipleEnvironments
3472 ? {
3473 availableEnvironments: logicalProjectEnvironments,
3474 onEnvironmentChange,
3475 }
3476 : {})}
3477 />
3478 )}
34463479 </div>
34473480
3448 {isGitRepo && (
3449 <BranchToolbar
3450 environmentId={activeThread.environmentId}
3451 threadId={activeThread.id}
3452 {...(routeKind === "draft" && draftId ? { draftId } : {})}
3453 onEnvModeChange={onEnvModeChange}
3454 {...(canOverrideServerThreadEnvMode ? { effectiveEnvModeOverride: envMode } : {})}
3455 {...(canOverrideServerThreadEnvMode
3456 ? {
3457 activeThreadBranchOverride: activeThreadBranch,
3458 onActiveThreadBranchOverrideChange: setPendingServerThreadBranch,
3459 }
3460 : {})}
3461 envLocked={envLocked}
3462 onComposerFocusRequest={scheduleComposerFocus}
3463 {...(canCheckoutPullRequestIntoThread
3464 ? { onCheckoutPullRequestRequest: openPullRequestDialog }
3465 : {})}
3466 {...(hasMultipleEnvironments
3467 ? {
3468 availableEnvironments: logicalProjectEnvironments,
3469 onEnvironmentChange,
3470 }
3471 : {})}
3472 />
3473 )}
34743481 {pullRequestDialogState ? (
34753482 <PullRequestThreadDialog
34763483 key={pullRequestDialogState.key}
apps/web/src/components/ComposerPromptEditor.tsx+3-3
......@@ -1490,7 +1490,7 @@ function ComposerPromptEditorInner({
14901490 const rootElement = editor.getRootElement();
14911491 if (!rootElement) return;
14921492 const boundedCursor = clampCollapsedComposerCursor(snapshotRef.current.value, nextCursor);
1493 rootElement.focus();
1493 rootElement.focus({ preventScroll: true });
14941494 editor.update(() => {
14951495 $setSelectionAtComposerOffset(boundedCursor);
14961496 });
......@@ -1621,7 +1621,7 @@ function ComposerPromptEditorInner({
16211621 contentEditable={
16221622 <ContentEditable
16231623 className={cn(
1624 "block max-h-[200px] min-h-17.5 w-full overflow-y-auto whitespace-pre-wrap wrap-break-word bg-transparent text-base sm:text-[14px] leading-relaxed text-foreground focus:outline-none",
1624 "block max-h-[200px] min-h-17.5 w-full overflow-y-auto whitespace-pre-wrap wrap-break-word bg-transparent text-[16px] leading-relaxed text-foreground focus:outline-none sm:text-[14px]",
16251625 className,
16261626 )}
16271627 data-testid="composer-editor"
......@@ -1632,7 +1632,7 @@ function ComposerPromptEditorInner({
16321632 }
16331633 placeholder={
16341634 terminalContexts.length > 0 ? null : (
1635 <div className="pointer-events-none absolute inset-0 text-base sm:text-[14px] leading-relaxed text-muted-foreground/35">
1635 <div className="pointer-events-none absolute inset-0 text-[16px] leading-relaxed text-muted-foreground/35 sm:text-[14px]">
16361636 {placeholder}
16371637 </div>
16381638 )
apps/web/src/components/chat/ChatHeader.tsx+6-1
......@@ -16,6 +16,7 @@ import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScr
1616import { Toggle } from "../ui/toggle";
1717import { SidebarTrigger } from "../ui/sidebar";
1818import { OpenInPicker } from "./OpenInPicker";
19import { usePrimaryEnvironmentId } from "../../environments/primary";
1920
2021interface ChatHeaderProps {
2122 activeThreadEnvironmentId: EnvironmentId;
......@@ -68,6 +69,10 @@ export const ChatHeader = memo(function ChatHeader({
6869 onToggleTerminal,
6970 onToggleDiff,
7071}: ChatHeaderProps) {
72 const primaryEnvironmentId = usePrimaryEnvironmentId();
73 const isRemoteEnvironment =
74 primaryEnvironmentId !== null && activeThreadEnvironmentId !== primaryEnvironmentId;
75
7176 return (
7277 <div className="@container/header-actions flex min-w-0 flex-1 items-center gap-2">
7378 <div className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden sm:gap-3">
......@@ -101,7 +106,7 @@ export const ChatHeader = memo(function ChatHeader({
101106 onDeleteScript={onDeleteProjectScript}
102107 />
103108 )}
104 {activeProjectName && (
109 {activeProjectName && !isRemoteEnvironment && (
105110 <OpenInPicker
106111 keybindings={keybindings}
107112 availableEditors={availableEditors}
apps/web/src/components/ui/sidebar.tsx+8-1
......@@ -245,7 +245,14 @@ function Sidebar({
245245 <SheetTitle>Sidebar</SheetTitle>
246246 <SheetDescription>Displays the mobile sidebar.</SheetDescription>
247247 </SheetHeader>
248 <div className="flex h-full w-full flex-col">{children}</div>
248 <div
249 className={cn(
250 "flex h-full w-full flex-col pb-safe pt-safe",
251 side === "left" ? "pl-safe" : "pr-safe",
252 )}
253 >
254 {children}
255 </div>
249256 </SheetPopup>
250257 </Sheet>
251258 </SidebarInstanceContext.Provider>
apps/web/src/index.css+28-3
......@@ -58,6 +58,22 @@
5858 }
5959}
6060
61/* Safe-area inset utilities for surfaces that opt into edge-to-edge rendering.
62 Insets resolve to 0 when the browser already constrains the layout viewport
63 to the safe area. */
64@utility pt-safe {
65 padding-top: max(env(safe-area-inset-top), 0px);
66}
67@utility pb-safe {
68 padding-bottom: max(env(safe-area-inset-bottom), 0px);
69}
70@utility pl-safe {
71 padding-left: max(env(safe-area-inset-left), 0px);
72}
73@utility pr-safe {
74 padding-right: max(env(safe-area-inset-right), 0px);
75}
76
6177/* Suppress all transitions during theme changes */
6278.no-transitions,
6379.no-transitions *,
......@@ -138,19 +154,28 @@ body {
138154 sans-serif;
139155 margin: 0;
140156 padding: 0;
141 min-height: 100vh;
142157}
143158
144159html,
145body,
160body {
161 min-height: calc(100svh + env(safe-area-inset-top));
162 overscroll-behavior: none;
163}
164
165body {
166 height: 100%;
167 overflow: hidden;
168}
169
146170#root {
147171 height: 100%;
148172 width: 100%;
149173 max-width: 100%;
150 overflow-y: hidden;
151174 overflow-x: hidden;
152175 overflow-x: clip;
176 overflow-y: hidden;
153177 overscroll-behavior-y: none;
178 padding-top: max(env(safe-area-inset-top), 0px);
154179}
155180
156181body::after {
apps/web/src/routes/_chat.$environmentId.$threadId.tsx+2-2
......@@ -240,7 +240,7 @@ function ChatThreadRouteView() {
240240 if (!shouldUseDiffSheet) {
241241 return (
242242 <>
243 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground">
243 <SidebarInset className="h-svh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground md:h-dvh">
244244 <ChatView
245245 environmentId={threadRef.environmentId}
246246 threadId={threadRef.threadId}
......@@ -261,7 +261,7 @@ function ChatThreadRouteView() {
261261
262262 return (
263263 <>
264 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground">
264 <SidebarInset className="h-svh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground md:h-dvh">
265265 <ChatView
266266 environmentId={threadRef.environmentId}
267267 threadId={threadRef.threadId}
apps/web/src/routes/_chat.draft.$draftId.tsx+2-2
......@@ -55,7 +55,7 @@ function DraftChatThreadRouteView() {
5555
5656 if (canonicalThreadRef) {
5757 return (
58 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground">
58 <SidebarInset className="h-svh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground md:h-dvh">
5959 <ChatView
6060 environmentId={canonicalThreadRef.environmentId}
6161 threadId={canonicalThreadRef.threadId}
......@@ -70,7 +70,7 @@ function DraftChatThreadRouteView() {
7070 }
7171
7272 return (
73 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground">
73 <SidebarInset className="h-svh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground md:h-dvh">
7474 <ChatView
7575 draftId={draftId}
7676 environmentId={draftSession.environmentId}