improve(ui): compact the New session controls and hero on phones (#105177)

* improve(ui): compact the new-session screen on phones

The /new target controls condense on phones: Where and Worktree share one
line and the folder picker takes its own full-width line below, so long
paths stay readable instead of stacking three loose rows. The shared
welcome hero (start screen and /new) scales down on phones so the
composer and recent chats fit the first screenful, and the /new scroll
inset matches the chat thread's mobile padding.

* fix(ui): keep mobile target rows in DOM order

Review caught that order: 2 on the folder chip made visual and tab order
diverge on phones. The folder chip now flexes next to Where with a 140px
floor that pushes Worktree to the second line, so the compact layout
keeps visual, reading, and focus order aligned.

* fix(ui): wrap the worktree fields with their toggle

Groups the worktree toggle and its branch/name fields in one flex unit so
line breaks never separate the dependent fields from the toggle at any
width; review caught that the previous flex sizing let the branch control
wrap alone on wider phones.
This commit is contained in:
Peter Steinberger
2026-07-12 10:02:04 +01:00
committed by GitHub
parent 004b7b69c7
commit 92accfde94
3 changed files with 125 additions and 56 deletions
+58 -56
View File
@@ -647,62 +647,64 @@ class NewSessionPage extends OpenClawLightDomElement {
`
: nothing}
</label>
<label
class="new-session-page__target new-session-page__target--toggle"
title=${worktreeAvailable
? t("chat.runControls.newSessionWorktree")
: t("newSession.worktreeUnavailable")}
>
<input
type="checkbox"
.checked=${this.worktree}
?disabled=${!worktreeAvailable || customFolder}
@change=${(event: Event) => {
this.worktree = (event.target as HTMLInputElement).checked;
if (this.worktree) {
this.maybeLoadBranches();
}
}}
/>
<span class="new-session-page__target-icon" aria-hidden="true">${icons.gitBranch}</span>
<span>${t("newSession.worktree")}</span>
</label>
${this.worktree
? html`
<label class="new-session-page__target" title=${t("newSession.baseBranch")}>
<input
type="text"
list="new-session-branches"
class="new-session-page__branch"
aria-label=${t("newSession.baseBranch")}
placeholder=${this.branchesLoading
? t("common.loading")
: (branches?.defaultBranch ?? t("newSession.baseBranch"))}
.value=${this.baseRef}
@input=${(event: Event) => {
this.baseRef = (event.target as HTMLInputElement).value.trim();
}}
/>
<datalist id="new-session-branches">
${(branches?.branches ?? []).map(
(branch) => html`<option value=${branch.name}></option>`,
)}
</datalist>
</label>
<label class="new-session-page__target" title=${t("newSession.worktreeName")}>
<input
type="text"
class="new-session-page__branch"
aria-label=${t("newSession.worktreeName")}
placeholder=${t("newSession.worktreeNamePlaceholder")}
.value=${this.worktreeName}
@input=${(event: Event) => {
this.worktreeName = (event.target as HTMLInputElement).value.trim();
}}
/>
</label>
`
: nothing}
<div class="new-session-page__target-group">
<label
class="new-session-page__target new-session-page__target--toggle"
title=${worktreeAvailable
? t("chat.runControls.newSessionWorktree")
: t("newSession.worktreeUnavailable")}
>
<input
type="checkbox"
.checked=${this.worktree}
?disabled=${!worktreeAvailable || customFolder}
@change=${(event: Event) => {
this.worktree = (event.target as HTMLInputElement).checked;
if (this.worktree) {
this.maybeLoadBranches();
}
}}
/>
<span class="new-session-page__target-icon" aria-hidden="true">${icons.gitBranch}</span>
<span>${t("newSession.worktree")}</span>
</label>
${this.worktree
? html`
<label class="new-session-page__target" title=${t("newSession.baseBranch")}>
<input
type="text"
list="new-session-branches"
class="new-session-page__branch"
aria-label=${t("newSession.baseBranch")}
placeholder=${this.branchesLoading
? t("common.loading")
: (branches?.defaultBranch ?? t("newSession.baseBranch"))}
.value=${this.baseRef}
@input=${(event: Event) => {
this.baseRef = (event.target as HTMLInputElement).value.trim();
}}
/>
<datalist id="new-session-branches">
${(branches?.branches ?? []).map(
(branch) => html`<option value=${branch.name}></option>`,
)}
</datalist>
</label>
<label class="new-session-page__target" title=${t("newSession.worktreeName")}>
<input
type="text"
class="new-session-page__branch"
aria-label=${t("newSession.worktreeName")}
placeholder=${t("newSession.worktreeNamePlaceholder")}
.value=${this.worktreeName}
@input=${(event: Event) => {
this.worktreeName = (event.target as HTMLInputElement).value.trim();
}}
/>
</label>
`
: nothing}
</div>
</div>
`;
}
+29
View File
@@ -4206,6 +4206,35 @@ openclaw-chat-pane:has(> .chat-pane__header) .chat-thread {
}
}
/* Phones (and short landscape): scale the welcome hero down so the composer
and recent chats fit the first screenful on the start screen and /new. */
@media (max-width: 768px), (max-width: 932px) and (max-height: 500px) and (orientation: landscape) {
.agent-chat__welcome {
gap: 8px;
padding: 16px 12px;
}
.agent-chat__welcome h2 {
font-size: 20px;
}
.agent-chat__welcome-avatar {
width: 64px;
height: 64px;
}
.agent-chat__welcome-clawd {
width: 88px;
height: 77px;
}
.agent-chat__welcome .agent-chat__avatar--text {
width: 64px;
height: 64px;
font-size: 22px;
}
}
.agent-chat__avatar--text {
width: 80px;
height: 80px;
+38
View File
@@ -60,6 +60,15 @@ openclaw-new-session-page {
padding: 0 2px;
}
/* The worktree toggle and its branch/name fields wrap as one unit so the
dependent fields never land on a different line than their toggle. */
.new-session-page__target-group {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
gap: inherit;
}
.new-session-page__target {
display: inline-flex;
align-items: center;
@@ -251,3 +260,32 @@ openclaw-new-session-page {
opacity: 0.5;
cursor: default;
}
/* Phones (and short landscape): match the chat thread's mobile inset and
condense the target rows in DOM order — the folder chip flexes next to
Where and the worktree group wraps below as a unit, so visual, reading,
and tab order stay aligned at every phone width. */
@media (max-width: 768px), (max-width: 932px) and (max-height: 500px) and (orientation: landscape) {
.new-session-page__scroll {
padding: 12px 8px;
}
.new-session-page__targets {
gap: 4px 12px;
}
.new-session-page__target--folder {
flex: 1 1 140px;
min-width: 140px;
}
.new-session-page__target--folder input {
flex: 1 1 auto;
width: 0;
max-width: none;
}
.new-session-page__branch {
width: 110px;
}
}