Merge worktree-llm-web-config (939, with latest master) into worktree/onboarding-deepseek-config
This commit is contained in:
@@ -19,6 +19,13 @@
|
||||
border-radius: 20px;
|
||||
background: var(--dsw-specific-input-major);
|
||||
box-shadow: var(--dsw-shadow-lv2);
|
||||
/* Elevated surface in dark, same as the menus: `.body` inside scrolls once
|
||||
the justification or command passes the cap, so the thumb takes the l2
|
||||
pair. Declared on the card because the elevation belongs to the surface,
|
||||
and the custom properties inherit down to the region that actually
|
||||
scrolls (see ui-theme styles/scrollbar.css for the rebinding contract). */
|
||||
--dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
|
||||
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
|
||||
}
|
||||
|
||||
/* Tinted full-width header band. */
|
||||
@@ -40,11 +47,22 @@
|
||||
background: var(--dsw-alias-state-warn-primary);
|
||||
}
|
||||
|
||||
/* Scroll region: an agent's justification and its command are unbounded model
|
||||
text (a one-line `cd` or a 40-line heredoc), and the seat sits in a
|
||||
fixed-height column — uncapped, a long command pushed the action row past
|
||||
the viewport and the approval could not be answered at all. The strip and
|
||||
the action row stay outside, so the buttons are always on screen. */
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 12px 16px 14px;
|
||||
/* border-box so the cap is the region's OUTER height: the composer's draft
|
||||
area counts its padding inside the same number, and the two seats are
|
||||
only interchangeable if they occupy the same box. */
|
||||
box-sizing: border-box;
|
||||
max-height: var(--dsh-composer-text-max-height);
|
||||
overflow-y: auto;
|
||||
padding: 12px 16px 0;
|
||||
}
|
||||
|
||||
/* The model's justification is the panel's message, not a footnote. */
|
||||
@@ -63,11 +81,15 @@
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* Card-level row, not body content. Its padding reproduces the metrics the row
|
||||
had inside the body: 14px above (the flex gap of 6 plus the row's 8px top
|
||||
margin, neither of which reaches it out here) and the body's former 14px
|
||||
bottom pad below, so the resting card is unchanged. */
|
||||
.actionRow {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
padding: 14px 16px 14px;
|
||||
}
|
||||
|
||||
.allow,
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
// pending, this panel occupies the composer slot in place of the InputBar:
|
||||
// an amber "Waiting for approval" strip on the card top, the model's
|
||||
// justification as the headline, the paired command in muted code text, and
|
||||
// a right-aligned refuse/allow action row. One-shot: the buttons disable
|
||||
// a right-aligned refuse/allow action row. Justification and command are
|
||||
// unbounded model text, so they scroll inside the card at the shared composer
|
||||
// cap (`data-approval-scroll`) and the action row stays outside it — the
|
||||
// buttons must be reachable no matter how long the command is.
|
||||
// One-shot: the buttons disable
|
||||
// after a click and the panel leaves (the InputBar returns) on the broadcast
|
||||
// resolved frame. The draft's "Always allow this type" is deferred with
|
||||
// grant storage.
|
||||
@@ -53,17 +57,20 @@ function ApprovalFlow({ pending, command }: { pending: PendingApproval; command?
|
||||
<div className={css.root} data-approval-key={pending.key}>
|
||||
<div className={css.card}>
|
||||
<div className={css.strip}><span className={css.dot} />等待审批</div>
|
||||
<div className={css.body}>
|
||||
{/* Tab stop: the region scrolls once the command passes the cap and
|
||||
holds nothing focusable of its own, so without one a keyboard-only
|
||||
user cannot reach the command's tail before answering. */}
|
||||
<div className={css.body} data-approval-scroll="" tabIndex={0} role="group" aria-label="审批详情">
|
||||
<div className={css.headline}>{pending.reason ?? `工具 ${pending.toolName} 请求越权执行`}</div>
|
||||
{command !== undefined && <div className={css.command}>{command}</div>}
|
||||
<div className={css.actionRow}>
|
||||
<button type="button" className={css.reject} disabled={answered} onClick={() => { answer('rejected') }}>
|
||||
拒绝
|
||||
</button>
|
||||
<button type="button" className={css.allow} disabled={answered} onClick={() => { answer('allowed-once') }}>
|
||||
允许一次
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.actionRow}>
|
||||
<button type="button" className={css.reject} disabled={answered} onClick={() => { answer('rejected') }}>
|
||||
拒绝
|
||||
</button>
|
||||
<button type="button" className={css.allow} disabled={answered} onClick={() => { answer('allowed-once') }}>
|
||||
允许一次
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -143,6 +143,14 @@
|
||||
display: flex;
|
||||
flex: none;
|
||||
flex-direction: column;
|
||||
/* One cap for every scrolling text region a composer seat can hold: the
|
||||
InputBar draft (figma Input 75:8208 max 14 lines × 24px line) and the
|
||||
takeover panels' bodies top out at the same height, so electing a
|
||||
takeover never grows the footer past the card it replaces. Declared on
|
||||
the seat because it is the chain's only shared ancestor — fallback and
|
||||
elected overlay are siblings — and custom properties inherit down to
|
||||
whichever entry is mounted. */
|
||||
--dsh-composer-text-max-height: 336px;
|
||||
}
|
||||
|
||||
/* Active phase: header is ordinary column chrome above the scrollport (not
|
||||
|
||||
@@ -209,7 +209,9 @@
|
||||
.mirror {
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
max-height: 336px;
|
||||
/* 14-line cap, shared with the composer takeovers (declared on
|
||||
ConversationRoot .composerSeat). */
|
||||
max-height: var(--dsh-composer-text-max-height);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user