Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 53 additions & 49 deletions apps/web/src/pages/workspace/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1323,56 +1323,60 @@ export function StageWorkspace({
className="composer"
data-working={working || sending ? "" : undefined}
>
{attachFault === null ? null : (
<p className="workspace-fault" role="alert">
{attachFault}
</p>
)}
{sendFailed && sendFault ? (
<p className="workspace-fault" role="alert">
{sendFault}
</p>
) : null}
{caution === null ? null : (
<div className="workspace-caution" role="alert">
<p>{wording.earlierDocument.warning(participantLabel(caution))}</p>
<div className="workspace-caution-actions">
<UiButton type="button" size="sm" onClick={sendNow}>
{wording.earlierDocument.sendAnyway}
</UiButton>
<UiButton
type="button"
size="sm"
variant="ghost"
onClick={() => {
setCaution(null);
composerRef.current?.focus();
}}
>
{wording.action.cancel}
</UiButton>
<div className="composer-notes">
{attachFault === null ? null : (
<p className="workspace-fault" role="alert">
{attachFault}
</p>
)}
{sendFailed && sendFault ? (
<p className="workspace-fault" role="alert">
{sendFault}
</p>
) : null}
{caution === null ? null : (
<div className="workspace-caution" role="alert">
<p>
{wording.earlierDocument.warning(participantLabel(caution))}
</p>
<div className="workspace-caution-actions">
<UiButton type="button" size="sm" onClick={sendNow}>
{wording.earlierDocument.sendAnyway}
</UiButton>
<UiButton
type="button"
size="sm"
variant="ghost"
onClick={() => {
setCaution(null);
composerRef.current?.focus();
}}
>
{wording.action.cancel}
</UiButton>
</div>
</div>
</div>
)}
{replies.length > 0 && !providerMissing ? (
<div
className="workspace-replies"
role="group"
aria-label="Suggested replies"
>
{replies.map((reply) => (
<UiButton
key={reply}
type="button"
variant="outline"
size="sm"
onClick={() => void deliver(reply)}
>
{reply}
</UiButton>
))}
</div>
) : null}
)}
{replies.length > 0 && !providerMissing ? (
<div
className="workspace-replies"
role="group"
aria-label="Suggested replies"
>
{replies.map((reply) => (
<UiButton
key={reply}
type="button"
variant="outline"
size="sm"
onClick={() => void deliver(reply)}
>
{reply}
</UiButton>
))}
</div>
) : null}
</div>
<AttachmentDropZone
onFiles={addFiles}
disabled={!attaching}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/pages/workspace/persistent-workspace.css
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@
color: var(--wb-foreground);
}

.composer > .workspace-fault {
.composer-notes > .workspace-fault {
padding: 0;
}

Expand Down
33 changes: 17 additions & 16 deletions apps/web/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1049,15 +1049,28 @@ h3 {
gap: var(--space-2);
flex: none;
position: relative;
/* However long the text gets, the box stops at a share of the window and
the text scrolls inside it (#160): a `flex: none` row that outgrew the
column pushed the send, stop, attach and mic controls below the pane's
edge, where nothing could reach them. */
/* Capped so the send, stop, attach and mic controls never leave the pane.
The composer itself must not scroll: the attachment tray and the model
list float above the box, and a scrolling composer clips them. The
textarea scrolls its own text, and the notes above the box give way. */
max-height: 70vh;
min-height: 0;
}

/* Errors, the earlier-document caution and suggested replies share one
region that scrolls once the composer reaches its cap, so the box below
keeps its full height. */
.composer > .composer-notes {
display: grid;
gap: var(--space-2);
min-height: 0;
overflow-y: auto;
}

.composer > .composer-notes:empty {
display: none;
}

/* The box itself is a flex column: textarea body above, action row beneath.
Capping the box and letting the body scroll keeps the action row pinned
at every text length. The textarea's own cap is the library's 200px; a
Expand Down Expand Up @@ -1090,18 +1103,6 @@ h3 {
overflow-y: auto;
}

/* The send-back picker a hold on send raises, the reviewer's notes and the
model profile list float above the composer, anchored to it rather than the
viewport. The composer scrolls its own overflow (#160), which would clip them
above it, so it stops while one is open (#210). */
.composer:has(> .sbpick),
.composer:has([data-slot="prompt-input-model-select"][data-state="open"]),
.composer:has(.reviewer-stance[data-open]),
.composer:has(.reviewer-stance:hover),
.composer:has(.reviewer-stance:focus-within) {
overflow: visible;
}

.document {
border: 1px solid var(--wb-border);
background: var(--wb-card);
Expand Down