mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
chore(ui): refine composer status coexistence
This commit is contained in:
@@ -223,3 +223,8 @@
|
||||
2026-08-21 22:46 · Optically aligned the active Plan label with its 2/3 counter and kept the canonical spinner running across the entire hover preview · ui/src/styles/chat/progress-card.css, ITERATION-NOTES.md · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-21 22:55 · Made Plan use the real spinner ring at rest and animate it only on hover, then replace it with a check, the truncated final step, and 3/3 when complete · ui/src/components/session-progress-card.ts, ui/src/styles/chat/progress-card.css, ITERATION-NOTES.md · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-21 22:56 · Kept the active Plan spinner rotating continuously instead of gating its motion on hover · ui/src/styles/chat/progress-card.css, ITERATION-NOTES.md · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-22 00:03 · Kept bottom error and status underlaps behind the composer so Interrupted no longer paints across the footer or send action · ui/src/styles/chat/layout.css, ITERATION-NOTES.md · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-22 07:33 · Normalized every in-scope Above composer neighbor to the bench width and flow instead of inheriting transcript-only offsets · ui/src/test-helpers/composer-bench.css · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-22 07:33 · Unified info, danger and offline underlap rows at a vertically centered height with quieter borders · ui/src/styles/chat/layout.css · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-22 07:33 · Projected the canonical reconnect badge onto every queued row while the composer is offline · ui/src/pages/chat/components/chat-composer-view.ts, ui/src/pages/chat/components/chat-composer-queue.ts · COMPONENT #124301 multiline | BENCH
|
||||
2026-08-22 07:33 · Matched running tasks to composer and Plan chrome and aligned both on one shared status row when they coexist · ui/src/styles/chat/tool-cards.css, ui/src/test-helpers/composer-bench.ts, ui/src/test-helpers/composer-bench.css · COMPONENT #124301 multiline | BENCH
|
||||
|
||||
@@ -114,6 +114,11 @@ Local-only working ledger. Re-read after every implementation block; move an ite
|
||||
- [x] Align the Plan step label and 2/3 counter, and keep its canonical spinner active across the full hover preview.
|
||||
- [x] Keep the active Plan spinner visible but paused until hover; replace it with a check and the final step plus 3/3 when complete.
|
||||
- [x] Keep the active Plan spinner rotating continuously, independent of hover.
|
||||
- [x] Keep bottom error and status underlaps behind the composer footer and send action.
|
||||
- [x] Normalize all in-scope Above composer neighbors to the real composer width and flow.
|
||||
- [x] Vertically center every lower composer status band and soften info, danger, and offline borders.
|
||||
- [x] Show the canonical reconnect pill on every queued row while offline.
|
||||
- [x] Match running tasks to Plan/composer chrome and share one horizontal status row when both appear.
|
||||
|
||||
## Observed queue contract
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { renderChatAuthorAvatar } from "./chat-author-avatar.ts";
|
||||
|
||||
type ChatQueueProps = {
|
||||
queue: ChatQueueItem[];
|
||||
offline?: boolean;
|
||||
canAbort?: boolean;
|
||||
onQueueRetry?: (id: string) => void;
|
||||
onQueueSteer?: (id: string) => void;
|
||||
@@ -114,11 +115,13 @@ function renderChatQueueItem(
|
||||
) {
|
||||
const authorAvatar = renderChatAuthorAvatar(item.sender);
|
||||
const hasAuthorAvatar = authorAvatar !== nothing;
|
||||
const stateLabel = sendStateLabel(item);
|
||||
const stateLabel = props.offline
|
||||
? t("chat.queue.states.waitingForReconnect")
|
||||
: sendStateLabel(item);
|
||||
const failed = item.sendState === "failed" || item.sendState === "unconfirmed";
|
||||
const isSteer = item.queueMode === "steer";
|
||||
const steerMode = isSteer && !failed;
|
||||
const reconnecting = item.sendState === "waiting-reconnect";
|
||||
const reconnecting = props.offline || item.sendState === "waiting-reconnect";
|
||||
const busy = item.sendState === "executing-command";
|
||||
const editing = props.editingId === item.id;
|
||||
const canSteer =
|
||||
|
||||
@@ -254,6 +254,7 @@ export function renderChatComposerView(context: ChatComposerViewContext) {
|
||||
|
||||
const queue = renderChatQueue({
|
||||
queue: props.queue,
|
||||
offline: props.offline,
|
||||
canAbort: showAbortableUi,
|
||||
onQueueRetry: props.connected && canCompose ? props.onQueueRetry : undefined,
|
||||
onQueueSteer: props.connected && canCompose ? props.onQueueSteer : undefined,
|
||||
|
||||
@@ -2971,6 +2971,10 @@ button.chat-pr__diff {
|
||||
--chat-composer-editor-line: calc(var(--chat-composer-editor-size) * 1.5);
|
||||
|
||||
position: relative;
|
||||
/* Queue, goal and status rows deliberately underlap the composer. Keep the
|
||||
writing surface in the foreground so their backgrounds cannot paint over
|
||||
the footer controls while their exposed content remains below it. */
|
||||
z-index: 1;
|
||||
container-name: chat-composer;
|
||||
container-type: inline-size;
|
||||
display: flex;
|
||||
@@ -3137,6 +3141,7 @@ button.chat-pr__diff {
|
||||
|
||||
.agent-chat__composer-underlaps {
|
||||
--chat-composer-bottom-underlap: 18px;
|
||||
--chat-composer-underlap-row-height: 44px;
|
||||
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
@@ -3147,7 +3152,7 @@ button.chat-pr__diff {
|
||||
)
|
||||
0 0;
|
||||
padding-top: calc(var(--chat-composer-shell-gap) + var(--chat-composer-bottom-underlap));
|
||||
border: 1px solid color-mix(in srgb, var(--border) 78%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--border) 16%, transparent);
|
||||
border-top: 0;
|
||||
border-radius: 0 0 calc(20px * var(--openclaw-corner-radius-scale))
|
||||
calc(20px * var(--openclaw-corner-radius-scale));
|
||||
@@ -3158,7 +3163,7 @@ button.chat-pr__diff {
|
||||
.agent-chat__composer-underlaps:has(.agent-chat__composer-error):not(
|
||||
:has(.agent-chat__offline-hint)
|
||||
) {
|
||||
border-color: color-mix(in srgb, var(--danger) 26%, transparent);
|
||||
border-color: color-mix(in srgb, var(--danger) 16%, transparent);
|
||||
}
|
||||
|
||||
.agent-chat__composer-underlaps:has(.agent-chat__composer-errors) {
|
||||
@@ -3168,13 +3173,14 @@ button.chat-pr__diff {
|
||||
.agent-chat__composer-underlaps:has(.agent-chat__composer-notice):not(
|
||||
:has(.agent-chat__composer-error)
|
||||
) {
|
||||
border-color: color-mix(in srgb, var(--info) 16%, transparent);
|
||||
background: color-mix(in srgb, var(--info) 9%, var(--chat-composer-surface));
|
||||
}
|
||||
|
||||
.agent-chat__composer-underlaps:has(.agent-chat__offline-hint):not(
|
||||
:has(.agent-chat__composer-errors)
|
||||
) {
|
||||
border-color: color-mix(in srgb, var(--warn) 26%, transparent);
|
||||
border-color: color-mix(in srgb, var(--warn) 16%, transparent);
|
||||
background: color-mix(in srgb, var(--warn) 9%, var(--chat-composer-surface));
|
||||
}
|
||||
|
||||
@@ -3191,9 +3197,12 @@ button.chat-pr__diff {
|
||||
}
|
||||
|
||||
.agent-chat__offline-hint {
|
||||
display: flex;
|
||||
min-height: var(--chat-composer-underlap-row-height);
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 7px 14px;
|
||||
padding: 8px 14px;
|
||||
background: color-mix(in srgb, var(--warn) 9%, var(--chat-composer-surface));
|
||||
color: color-mix(in srgb, var(--warn) 72%, var(--text));
|
||||
font-size: 11px;
|
||||
@@ -4138,7 +4147,7 @@ button.chat-pr__diff {
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
box-sizing: border-box;
|
||||
min-height: 36px;
|
||||
min-height: var(--chat-composer-underlap-row-height, 44px);
|
||||
padding: 8px 10px 8px 14px;
|
||||
font-size: var(--control-ui-text-sm);
|
||||
line-height: 1.35;
|
||||
@@ -4150,7 +4159,7 @@ button.chat-pr__diff {
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
box-sizing: border-box;
|
||||
min-height: 36px;
|
||||
min-height: var(--chat-composer-underlap-row-height, 44px);
|
||||
padding: 8px 10px 8px 14px;
|
||||
font-size: var(--control-ui-text-sm);
|
||||
line-height: 1.35;
|
||||
|
||||
@@ -2048,8 +2048,9 @@
|
||||
min-height: 34px;
|
||||
padding: 0 12px;
|
||||
color: var(--muted);
|
||||
background: color-mix(in srgb, var(--bg-elevated) 76%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--text-strong) 11%, transparent);
|
||||
background: var(--chat-composer-surface, var(--card));
|
||||
border: 1px solid
|
||||
var(--chat-composer-hairline, color-mix(in srgb, var(--text-strong) 11%, transparent));
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
||||
@@ -479,6 +479,32 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.composer-bench__composer-stack {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.composer-bench__composer-stack[data-shared-status-row] {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.composer-bench__composer-stack[data-shared-status-row]
|
||||
> :is(.composer-bench__tasks-status, .agent-chat__composer-shell) {
|
||||
grid-area: 1 / 1;
|
||||
}
|
||||
|
||||
.composer-bench__composer-stack[data-shared-status-row] > .composer-bench__tasks-status {
|
||||
z-index: 5;
|
||||
align-self: start;
|
||||
justify-self: start;
|
||||
width: auto;
|
||||
padding-top: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.composer-bench__composer-stack[data-shared-status-row] .chat-tasks-status {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.composer-bench__tasks-status {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
@@ -492,13 +518,19 @@ body {
|
||||
}
|
||||
|
||||
.composer-bench__neighbor {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.composer-bench__neighbor > :first-child {
|
||||
margin-top: 0;
|
||||
.composer-bench__neighbor > * {
|
||||
position: relative;
|
||||
inset: auto;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
@@ -1421,7 +1421,13 @@ function renderChatSurface(sessionList: SessionsListResult) {
|
||||
onGatewayQuestionSkip: () => publishState({ inset: "none" }),
|
||||
onSlashIntent: () => {},
|
||||
});
|
||||
return html`${renderBenchNeighbor()}${renderBenchTasksStatus()}${composer}`;
|
||||
const shareStatusRow = state.tasks !== "none" && state.plan !== "none";
|
||||
return html`${renderBenchNeighbor()}<div
|
||||
class="composer-bench__composer-stack"
|
||||
?data-shared-status-row=${shareStatusRow}
|
||||
>
|
||||
${renderBenchTasksStatus()}${composer}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderNewTargetBar() {
|
||||
|
||||
Reference in New Issue
Block a user