diff --git a/packages/web-shell/client/App.module.css b/packages/web-shell/client/App.module.css index 2e39548727..5372644fd6 100644 --- a/packages/web-shell/client/App.module.css +++ b/packages/web-shell/client/App.module.css @@ -13,6 +13,18 @@ flex-direction: column; height: 100%; min-height: 0; + /* + * Safe-area padding for mobile devices with notch / home indicator. + * With `viewport-fit=cover` in index.html the page extends behind the + * status-bar, home-indicator, and landscape notch regions; these env() + * insets push the content back into the visible safe area. On desktop + * or phones without notches every inset evaluates to 0 so nothing + * changes. + */ + padding-top: env(safe-area-inset-top); + padding-bottom: env(safe-area-inset-bottom); + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); background: var(--background); color: var(--foreground); font-family: var(--font-mono); @@ -101,6 +113,14 @@ pointer-events: auto; /* Show immediately on open; only the close path needs the delay above. */ transition-delay: 0s; + /* With `viewport-fit=cover`, the fixed drawer extends behind the status + bar, home indicator, and landscape notch. Push the sidebar content + into the safe area while keeping the backdrop full-screen (it is a + sibling, not a child). */ + padding-top: env(safe-area-inset-top); + padding-bottom: env(safe-area-inset-bottom); + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); } .mobileBackdrop { diff --git a/packages/web-shell/client/components/ChatEditor.tsx b/packages/web-shell/client/components/ChatEditor.tsx index 6fa6d13b1d..32f579e5dd 100644 --- a/packages/web-shell/client/components/ChatEditor.tsx +++ b/packages/web-shell/client/components/ChatEditor.tsx @@ -1261,7 +1261,7 @@ export const ChatEditor = memo( const showCancelButton = isRunning && !core.hasContent; return ( -
+
); + // Re-enable text selection on every message row so users can long-press / + // drag-select reply text. The blanket `html * { user-select: none }` in + // standalone.css disables selection on UI chrome (native-app feel); this + // attribute opts the message subtree back in, including descendants + // (Markdown body, code blocks, tool panels, sub-messages). + const selectableSafeBody =
{safeBody}
; + if (message.role === 'assistant') { if (showAssistantActions) { - return safeBody; + return selectableSafeBody; } return ( - {safeBody} + {selectableSafeBody} ); } - // The cancellation marker is a right-aligned, full-width turn-terminal row; a - // hover timestamp would overlap its text, so render it without the wrapper. + // The cancellation marker is a right-aligned, full-width turn-terminal row; + // a hover timestamp would overlap its text, so skip the MessageTimestamp + // wrapper. The data-user-selectable div is still applied for consistency. if (message.role === 'system' && message.source === 'prompt_cancelled') { - return safeBody; + return selectableSafeBody; } return ( @@ -173,7 +181,7 @@ export const MessageItem = memo(function MessageItem({ copyText={message.role === 'user' ? message.content : undefined} copyTitle="Copy" > - {safeBody} + {selectableSafeBody} ); }, areMessageItemPropsEqual); diff --git a/packages/web-shell/client/index.html b/packages/web-shell/client/index.html index 37efbd16dd..30564df443 100644 --- a/packages/web-shell/client/index.html +++ b/packages/web-shell/client/index.html @@ -2,8 +2,33 @@ - + + + + Qwen Code Web chat + +