Path: blob/main/src/vs/sessions/browser/parts/mobile/mobileChatShell.css
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45/*6* `!important` policy for this file:7*8* Only use `!important` when fighting one of:9* 1. SplitView.View.layoutContainer — sets inline position/top/left/width/height10* on every `.split-view-view` (src/vs/base/browser/ui/splitview/splitview.ts).11* 2. Part.layoutContents — inlines width/height on `.part > .content` via size().12* 3. An equal-specificity desktop rule in the main workbench stylesheet.13*14* Rules that only face lower-specificity desktop CSS (e.g. a single `.part.X`15* selector) do NOT need `!important` — the `.phone-layout` class on the16* workbench root already wins. When adding a new rule, omit `!important`17* first and only add it if DevTools shows an actual override.18*/1920/* ---- Mobile Top Bar ---- */2122.mobile-top-bar {23display: flex;24align-items: center;25height: 48px;26min-height: 48px;27padding: 0 4px;28padding-top: env(safe-area-inset-top);29background: var(--vscode-editor-background);30flex-shrink: 0;31-webkit-touch-callout: none;32user-select: none;33-webkit-user-select: none;34touch-action: manipulation;35z-index: 10;36}3738.mobile-top-bar .mobile-top-bar-button {39display: flex;40align-items: center;41justify-content: center;42width: 44px;43height: 44px;44border: none;45background: none;46color: var(--vscode-foreground);47cursor: pointer;48border-radius: 50%;49flex-shrink: 0;50touch-action: manipulation;51font-size: 18px;52padding: 0;53}5455.monaco-workbench .mobile-top-bar .mobile-top-bar-button:focus {56outline: none !important;57}5859.mobile-top-bar .mobile-top-bar-button:focus-visible {60outline: 1px solid var(--vscode-focusBorder);61outline-offset: -1px;62}6364.mobile-top-bar .mobile-top-bar-button:active {65background: var(--vscode-toolbar-hoverBackground);66}6768/* -- Mobile titlebar: Changes pill ------------------------------------- */69/* Pill-shaped button showing total insertions/deletions for the active session. Tapping opens a quick pick of changed files; selecting one opens the mobile diff view. Hidden when the session has no changes or when on the welcome / new-chat screen. */7071.mobile-top-bar .mobile-top-bar-button.mobile-changes-pill {72width: auto;73height: 28px;74padding: 0 10px;75border-radius: 14px;76gap: 4px;77font-size: 12px;78line-height: 18px;79font-variant-numeric: tabular-nums;80border: 1px solid var(--vscode-widget-border, color-mix(in srgb, var(--vscode-foreground) 15%, transparent));81background: transparent;82color: var(--vscode-foreground);83}8485.mobile-top-bar .mobile-changes-pill .mobile-changes-pill-icon {86font-size: 14px;87color: var(--vscode-descriptionForeground);88display: flex;89align-items: center;90}9192.mobile-top-bar .mobile-changes-pill .mobile-changes-pill-added {93color: var(--vscode-gitDecoration-addedResourceForeground, var(--vscode-charts-green));94}9596.mobile-top-bar .mobile-changes-pill .mobile-changes-pill-removed {97color: var(--vscode-gitDecoration-deletedResourceForeground, var(--vscode-charts-red));98}99100.mobile-top-bar .mobile-changes-pill:active {101background: var(--vscode-toolbar-hoverBackground);102}103104.mobile-top-bar .mobile-top-bar-center {105flex: 1;106min-width: 0;107display: flex;108align-items: center;109height: 100%;110}111112.mobile-top-bar .mobile-session-title {113flex: 1;114min-width: 0;115text-align: center;116font-size: 16px;117font-weight: 500;118color: var(--vscode-foreground);119overflow: hidden;120text-overflow: ellipsis;121white-space: nowrap;122padding: 0 4px;123cursor: pointer;124border: none;125background: none;126touch-action: manipulation;127font-family: inherit;128}129130.monaco-workbench .mobile-top-bar .mobile-session-title:focus {131outline: none !important;132}133134.mobile-top-bar .mobile-session-title:focus-visible {135outline: 1px solid var(--vscode-focusBorder);136outline-offset: -1px;137}138139.mobile-top-bar .mobile-session-title:active {140opacity: 0.7;141}142143.mobile-top-bar .mobile-top-bar-actions {144display: none;145flex: 1;146min-width: 0;147align-items: center;148height: 100%;149}150151/* When the welcome screen is visible and the center menu has contributed152items (e.g., the web host filter on the home screen) the title is153hidden and the toolbar takes its place. */154.mobile-top-bar.show-actions .mobile-session-title {155display: none;156}157158.mobile-top-bar.show-actions .mobile-top-bar-actions {159display: flex;160flex-direction: column;161}162163/* ---- Phone Layout: Full-screen chat ---- */164165/* On phone, stack the mobile top bar and grid vertically */166.agent-sessions-workbench.phone-layout {167display: flex;168flex-direction: column;169overflow: hidden;170}171172/* On phone, all split-view-view wrappers inside the grid — both those173wrapping parts AND those wrapping nested grid branch nodes — fill the174full grid area. This collapses the multi-axis grid into a single175full-screen viewport so parts overlap rather than share horizontal176space. The sidebar uses its own z-index + transform to slide over177the chat (see sidebarPart.css). The :has() conditions scope strictly178to grid wrappers so splitviews used inside individual parts' content179(e.g. a sidebar's view list) are not affected. */180.agent-sessions-workbench.phone-layout .split-view-view:has(> .part),181.agent-sessions-workbench.phone-layout .split-view-view:has(> .monaco-grid-branch-node) {182position: absolute !important;183top: 0 !important;184left: 0 !important;185width: 100% !important;186height: 100% !important;187}188189/* All grid branch nodes fill their parent. `.monaco-grid-branch-node` is190specific to the grid widget, so this descendant selector won't hit191splitviews used inside individual parts' content. The grid widget192does not write inline geometry to branch nodes (only to the wrapping193`.split-view-view`), so plain CSS suffices here. */194.agent-sessions-workbench.phone-layout .monaco-grid-branch-node {195position: absolute;196top: 0;197left: 0;198width: 100%;199height: 100%;200}201202/* Remove card appearance from ALL parts on phone.203Specificity wins over the desktop card rule in style.css without !important;204width/height match what the mobile Part.layout() already inlines. */205.agent-sessions-workbench.phone-layout .part.chatbar,206.agent-sessions-workbench.phone-layout .part.sidebar,207.agent-sessions-workbench.phone-layout .part.auxiliarybar,208.agent-sessions-workbench.phone-layout .part.panel {209margin: 0;210border: none;211border-radius: 0;212box-shadow: none;213--part-border-color: transparent;214width: 100%;215height: 100%;216}217218/* Pin Part content to the wrapper's full width on phone.219`!important` is required because `Part.layoutContents()` inlines the220width on `.part > .content` based on the splitview size (rule #2 in the221policy above). Without this, opening the sidebar — which makes the222splitview share space between sidebar and chatbar — would shrink the223chatbar's content during the drawer slide animation. */224.agent-sessions-workbench.phone-layout .part.chatbar > .content,225.agent-sessions-workbench.phone-layout .part.sidebar > .content,226.agent-sessions-workbench.phone-layout .part.auxiliarybar > .content,227.agent-sessions-workbench.phone-layout .part.panel > .content {228width: 100% !important;229height: 100% !important;230}231232/* Hide the session composite bar (Copilot CLI / Approvals / Branch) on phone */233.agent-sessions-workbench.phone-layout .session-composite-bar {234display: none;235}236237/* Ensure the grid view element doesn't overflow — flex child must shrink */238.agent-sessions-workbench.phone-layout > .monaco-grid-view {239flex: 1 1 0% !important;240min-height: 0 !important;241overflow: hidden !important;242height: auto !important;243background-color: var(--vscode-editor-background);244}245246/* Remove max-width constraint on chat content */247.agent-sessions-workbench.phone-layout .interactive-session .interactive-item-container {248max-width: none !important;249}250251.agent-sessions-workbench.phone-layout .interactive-session > .chat-suggest-next-widget {252max-width: none !important;253}254255.agent-sessions-workbench.phone-layout .interactive-session .interactive-input-part {256max-width: none !important; /* fights equal-specificity rule in style.css */257padding-bottom: calc(10px + env(safe-area-inset-bottom));258}259260/* Chat input minimum font size to prevent iOS auto-zoom */261.agent-sessions-workbench.phone-layout .interactive-session .chat-input-container textarea,262.agent-sessions-workbench.phone-layout .interactive-session .chat-input-container input {263font-size: 16px !important;264}265266/* Hide the desktop titlebar on phone — replaced by mobile top bar */267.agent-sessions-workbench.phone-layout .part.titlebar {268display: none !important;269}270271/* Sidebar content and customization toolbar should stack and scroll */272.agent-sessions-workbench.phone-layout .part.sidebar {273display: flex !important;274flex-direction: column !important;275overflow: hidden !important;276}277278.agent-sessions-workbench.phone-layout .part.sidebar > .composite.title {279display: none;280}281282.agent-sessions-workbench.phone-layout .part.sidebar > .content {283top: 0 !important;284flex: 1 !important;285min-height: 0 !important;286overflow-y: auto !important;287-webkit-overflow-scrolling: touch;288}289290/* Customization toolbar: hidden on phone (opens editors, not mobile-compatible) */291.agent-sessions-workbench.phone-layout .part.sidebar .ai-customization-toolbar {292display: none;293}294295/* Make sidebar footer touch-friendly */296.agent-sessions-workbench.phone-layout .part.sidebar > .sidebar-footer .sidebar-action-button {297min-height: 44px;298padding: 8px 12px;299}300301/* Hide the "+ Session" button in the sidebar on phone — replaced by top bar + button */302.agent-sessions-workbench.phone-layout .agent-sessions-new-button-container {303display: none;304}305306/* Hide sashes on phone */307.agent-sessions-workbench.phone-layout .monaco-sash {308display: none !important;309pointer-events: none !important;310}311312/* Overscroll containment */313.agent-sessions-workbench.phone-layout .interactive-session {314overscroll-behavior: contain;315}316317.agent-sessions-workbench.phone-layout .monaco-list {318overscroll-behavior: contain;319}320321/* On phone, push the chat input to the bottom of the chat area */322.agent-sessions-workbench.phone-layout .interactive-session .interactive-input-and-execute-toolbar {323margin-top: auto;324}325326/* ---- Phone Layout: Chat Welcome Page ---- */327328/* Make the welcome page a flex column that fills the chat area */329.agent-sessions-workbench.phone-layout .new-chat-widget-container {330display: flex !important;331flex-direction: column !important;332height: 100% !important;333padding: 8px 8px 0 8px !important;334}335336.agent-sessions-workbench.phone-layout .new-chat-widget-content {337display: flex !important;338flex-direction: column !important;339flex: 1 !important;340min-height: 0 !important;341max-width: 100% !important;342padding-bottom: 20px !important;343}344345/* Workspace picker centered vertically with icon above */346.agent-sessions-workbench.phone-layout .new-session-workspace-picker-container {347flex: 1 !important;348display: flex !important;349flex-direction: column !important;350align-items: center !important;351justify-content: center !important;352max-width: 100% !important;353}354355/* Show the sessions logo above the workspace picker — same asset as the auth page */356.agent-sessions-workbench.phone-layout .new-session-workspace-picker-container::before {357content: '';358display: block;359width: 64px;360height: 64px;361margin-bottom: 16px;362background-image: url('../../media/sessions-logo-light.svg');363background-size: contain;364background-repeat: no-repeat;365background-position: center;366}367368.vs .agent-sessions-workbench.phone-layout .new-session-workspace-picker-container::before,369.hc-light .agent-sessions-workbench.phone-layout .new-session-workspace-picker-container::before {370background-image: url('../../media/sessions-logo-dark.svg');371}372373/* Center the picker text */374.agent-sessions-workbench.phone-layout .session-workspace-picker {375display: flex !important;376flex-direction: column !important;377align-items: center !important;378gap: 8px !important;379font-size: 16px !important;380}381382.agent-sessions-workbench.phone-layout .session-workspace-picker-label {383font-size: 18px;384opacity: 0.6;385}386387/* Input slot pinned to the bottom */388.agent-sessions-workbench.phone-layout .new-chat-input-container {389flex-shrink: 0 !important;390padding: 0 0 8px 0 !important;391max-width: 100% !important;392}393394/* Make the chat input full-width and edge-to-edge styled */395.agent-sessions-workbench.phone-layout .sessions-chat-input-area {396border-radius: 16px !important;397max-width: 100% !important;398}399400/* Hide the local mode bar (Copilot CLI / Default Approvals / Branch) on phone */401.agent-sessions-workbench.phone-layout .new-chat-bottom-container {402display: none;403}404405/* Also hide the sessions-chat-widget's DnD overlay on phone */406.agent-sessions-workbench.phone-layout .sessions-chat-dnd-overlay {407display: none;408}409410/* Chat widget fills full width on phone */411.agent-sessions-workbench.phone-layout .sessions-chat-widget {412width: 100% !important;413}414415/* allow-any-unicode-next-line */416/* Compact chat toolbar on phone */417.agent-sessions-workbench.phone-layout .sessions-chat-toolbar {418padding: 0 6px 0 6px !important;419max-height: 32px !important;420gap: 4px !important;421}422423/* Prevent card transitions from flashing on phone */424.agent-sessions-workbench.phone-layout .part.chatbar,425.agent-sessions-workbench.phone-layout .part.sidebar,426.agent-sessions-workbench.phone-layout .part.auxiliarybar,427.agent-sessions-workbench.phone-layout .part.panel {428transition: none !important;429}430431/* ---- Mobile Account Indicator ---- */432433.mobile-top-bar .mobile-account-indicator {434position: relative;435}436437.mobile-top-bar .mobile-account-avatar {438display: none;439width: 28px;440height: 28px;441border-radius: 50%;442object-fit: cover;443border: 1px solid var(--vscode-commandCenter-border, transparent);444box-sizing: border-box;445}446447.mobile-top-bar .mobile-account-avatar.visible {448display: block;449}450451/* Hide the codicon when the avatar is loaded */452.mobile-top-bar .mobile-account-indicator .codicon.hidden {453display: none;454}455456.mobile-top-bar .mobile-account-badge {457position: absolute;458top: 8px;459right: 8px;460width: 8px;461height: 8px;462border-radius: 50%;463border: 1.5px solid var(--vscode-editor-background);464background: var(--vscode-editorWarning-foreground);465pointer-events: none;466}467468.mobile-top-bar .mobile-account-badge.dot-badge-warning {469background: var(--vscode-editorWarning-foreground);470}471472.mobile-top-bar .mobile-account-badge.dot-badge-error {473background: var(--vscode-editorError-foreground);474}475476/* ---- Mobile Account Sheet (full-screen bottom sheet) ---- */477478.mobile-account-sheet {479position: fixed;480inset: 0;481z-index: 1000;482display: flex;483flex-direction: column;484background: var(--vscode-editor-background);485color: var(--vscode-foreground);486touch-action: manipulation;487-webkit-touch-callout: none;488user-select: none;489-webkit-user-select: none;490}491492.mobile-account-sheet-header {493display: flex;494align-items: center;495justify-content: space-between;496height: 56px;497min-height: 56px;498padding: 0 16px;499padding-top: env(safe-area-inset-top);500border-bottom: 1px solid var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent));501flex-shrink: 0;502}503504.mobile-account-sheet-title {505font-size: 18px;506font-weight: 600;507margin: 0;508color: var(--vscode-foreground);509}510511.mobile-account-sheet-close {512display: flex;513align-items: center;514justify-content: center;515width: 44px;516height: 44px;517border: none;518background: none;519color: var(--vscode-foreground);520cursor: pointer;521border-radius: 50%;522font-size: 18px;523padding: 0;524touch-action: manipulation;525}526527.mobile-account-sheet-close:active {528background: var(--vscode-toolbar-hoverBackground);529}530531.mobile-account-sheet-content {532flex: 1;533overflow-y: auto;534-webkit-overflow-scrolling: touch;535overscroll-behavior: contain;536padding: 0 16px;537padding-bottom: calc(16px + env(safe-area-inset-bottom));538}539540/* Profile card */541542.mobile-account-sheet-profile {543display: flex;544align-items: center;545gap: 16px;546padding: 24px 0 20px;547}548549.mobile-account-sheet-avatar {550width: 56px;551height: 56px;552border-radius: 50%;553object-fit: cover;554flex-shrink: 0;555}556557.mobile-account-sheet-avatar-placeholder {558display: flex;559align-items: center;560justify-content: center;561width: 56px;562height: 56px;563border-radius: 50%;564background: var(--vscode-badge-background);565color: var(--vscode-badge-foreground);566font-size: 28px;567flex-shrink: 0;568}569570.mobile-account-sheet-profile-info {571min-width: 0;572flex: 1;573}574575.mobile-account-sheet-name {576font-size: 18px;577font-weight: 600;578overflow: hidden;579text-overflow: ellipsis;580white-space: nowrap;581}582583.mobile-account-sheet-provider {584font-size: 14px;585color: var(--vscode-descriptionForeground);586margin-top: 2px;587overflow: hidden;588text-overflow: ellipsis;589white-space: nowrap;590}591592/* Dashboard section */593594.mobile-account-sheet-section {595padding: 8px 0 16px;596border-top: 1px solid var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent));597}598599/* Action rows */600601.mobile-account-sheet-actions {602display: flex;603flex-direction: column;604border-top: 1px solid var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent));605padding: 8px 0;606}607608.mobile-account-sheet-action {609display: flex;610align-items: center;611gap: 16px;612height: 52px;613min-height: 52px;614padding: 0 4px;615border: none;616border-radius: 12px;617background: none;618color: var(--vscode-foreground);619font-size: 16px;620text-align: left;621cursor: pointer;622touch-action: manipulation;623font-family: inherit;624}625626.mobile-account-sheet-action:active {627background: var(--vscode-list-hoverBackground);628}629630.mobile-account-sheet-action:disabled {631opacity: 0.5;632cursor: default;633}634635.mobile-account-sheet-action-icon {636font-size: 20px;637width: 24px;638text-align: center;639flex-shrink: 0;640color: var(--vscode-descriptionForeground);641}642643.mobile-account-sheet-action-label {644flex: 1;645min-width: 0;646overflow: hidden;647text-overflow: ellipsis;648white-space: nowrap;649}650651.mobile-account-sheet-separator {652height: 1px;653margin: 4px 0;654background: var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent));655}656657.agent-sessions-workbench.phone-layout .sessions-account-titlebar-panel-action {658min-height: 44px;659touch-action: manipulation;660}661662.agent-sessions-workbench.phone-layout .sessions-account-titlebar-panel-header-action {663min-width: 44px;664min-height: 44px;665touch-action: manipulation;666}667668/* -- Phone: Sessions list header --------------------------------------- */669/* The desktop header row (Sessions label + New + Filter + Find toolbar) is hidden on phone in favor of the filter-chips row and the (+) button in MobileTitlebarPart. The row container itself is still rendered because the tree's find widget mounts inside it; the `phone-layout-empty` class is removed when the find widget is open so the row reappears for searching. */670671.agent-sessions-workbench.phone-layout .agent-sessions-header-row.phone-layout-empty {672display: none;673}674675/* On phone the label / actions slots are intentionally left empty (the676* desktop header content is replaced by the mobile filter chips and the677* (+) button in MobileTitlebarPart). When the find widget opens the row678* becomes visible, but these two empty flex children would still occupy679* leading space because of `gap` between siblings. Collapse them so the680* find input sits flush with the row's leading edge. */681.agent-sessions-workbench.phone-layout .agent-sessions-header-row > .agent-sessions-header-label,682.agent-sessions-workbench.phone-layout .agent-sessions-header-row > .agent-sessions-header-actions {683display: none;684}685686/* -- Phone: Find widget mobile-friendly UX ----------------------------- */687/* When the user opens find on phone, the desktop type-filter widget is normally a tiny floating input with a 24px tall input box and a 22x22 close button — designed for a mouse cursor. On phone, expand it to a full-width row with thumb-sized targets and a single visible search input. */688689.agent-sessions-workbench.phone-layout .agent-sessions-header-row {690/* The find widget commandeers the row when open. Use minimal horizontal padding so the input stretches as close to the screen edges as possible — feels right for a phone search field. */691padding: 6px 4px 6px 8px;692min-height: 52px;693gap: 4px;694}695696.agent-sessions-workbench.phone-layout .agent-sessions-find-widget-container {697/* Take the full width on phone — there's no label/toolbar competing for space because they're hidden in this mode. */698flex: 1 1 auto;699min-width: 0;700}701702.agent-sessions-workbench.phone-layout703.agent-sessions-find-widget-container > .monaco-tree-type-filter {704/* Reset desktop offsets — the desktop widget tries to align with the tree-element rows above it; on phone it lives in its own row. */705width: 100%;706gap: 4px;707}708709.agent-sessions-workbench.phone-layout710.agent-sessions-find-widget-container > .monaco-tree-type-filter711.monaco-tree-type-filter-input {712flex: 1 1 auto;713min-width: 0;714}715716.agent-sessions-workbench.phone-layout717.agent-sessions-find-widget-container > .monaco-tree-type-filter718.monaco-tree-type-filter-input > .monaco-findInput {719display: block;720width: 100%;721}722723.agent-sessions-workbench.phone-layout724.agent-sessions-find-widget-container > .monaco-tree-type-filter725.monaco-tree-type-filter-input > .monaco-findInput > .monaco-inputbox {726min-height: 36px;727border-radius: 18px;728padding: 0 12px;729font-size: 14px;730width: 100%;731}732733.agent-sessions-workbench.phone-layout734.agent-sessions-find-widget-container > .monaco-tree-type-filter735.monaco-tree-type-filter-input > .monaco-findInput > .monaco-inputbox input {736font-size: 14px;737line-height: 22px;738}739740/* Hide the per-input "filter mode" toggle (matches whole word, etc.) on phone — it's tiny and rarely useful for a sessions list lookup; the primary action is "type to filter". */741.agent-sessions-workbench.phone-layout742.agent-sessions-find-widget-container > .monaco-tree-type-filter743.monaco-tree-type-filter-input > .monaco-findInput > .controls {744display: none;745}746747/* Close button: thumb-sized, hugs the right edge. Override the desktop actionbar's natural left-margin so there is no extra empty gap between the input and the X. */748.agent-sessions-workbench.phone-layout749.agent-sessions-find-widget-container > .monaco-tree-type-filter750> .monaco-tree-type-filter-actionbar {751margin: 0;752flex-shrink: 0;753}754755.agent-sessions-workbench.phone-layout756.agent-sessions-find-widget-container > .monaco-tree-type-filter757> .monaco-tree-type-filter-actionbar .monaco-action-bar .action-label {758width: 36px;759height: 36px;760padding: 0;761}762763764