T24a round 1 fix

- overlays::Dialog caps its card at the window, a title bar's height clear
  at each end, and scrolls its body while heading and actions stay; the
  fullscreen body scrolls too; test a_tall_dialog_keeps_its_actions_in_the_window
- ToolCallCard's tool name gives way with an Ellipsis, so time and chevron
  stay in a narrow column; the gallery shows one at 280px
- the Agent script shuts the card it opened, so each theme's shot opens it
- AGENTS: dialogs fit the window
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 08:09:46 -04:00
1 parent 1db0a0db44
commit aac5e4ead2
7 files changed
+86 -9

No files matched your search

+2 -2
View File
@@ -123,10 +123,10 @@ impl RenderOnce for ToolCallCard {
.child(step_mark((self.id.clone(), "mark").into(), self.status, cx))
.child(
div()
.flex_none()
.min_w_0()
.font_family(theme.mono_family.clone())
.text_color(colors.fg)
.child(self.name),
.child(Ellipsis::new(self.name)),
)
.child(
div()
+31 -4
View File
@@ -120,6 +120,7 @@ impl RenderOnce for Dialog {
let theme = cx.theme();
let colors = &theme.colors;
let heading = div()
.flex_none()
.flex()
.flex_col()
.gap_1()
@@ -143,8 +144,14 @@ impl RenderOnce for Dialog {
.into_iter()
.map(|build| build(close.clone()))
.collect();
let actions =
(!buttons.is_empty()).then(|| div().flex().justify_end().gap_2().children(buttons));
let actions = (!buttons.is_empty()).then(|| {
div()
.flex_none()
.flex()
.justify_end()
.gap_2()
.children(buttons)
});
let enter = self.enter.map(|build| {
let field = self
.first
@@ -179,7 +186,15 @@ impl RenderOnce for Dialog {
.on_click(move |_, window, cx| button(window, cx)),
),
)
.child(div().flex_1().min_h_0().p_6().children(self.body))
.child(
div()
.id((self.id.clone(), "body"))
.flex_1()
.min_h_0()
.overflow_y_scroll()
.p_6()
.children(self.body),
)
.children(actions.map(|row| {
div()
.px_6()
@@ -189,12 +204,24 @@ impl RenderOnce for Dialog {
.child(row)
}))
} else {
let margin = theme.titlebar_height().to_pixels(window.rem_size());
let body = (!self.body.is_empty()).then(|| {
div()
.id((self.id.clone(), "body"))
.min_h_0()
.overflow_y_scroll()
.flex()
.flex_col()
.gap_5()
.children(self.body)
});
div()
.id(self.id.clone())
.flex()
.flex_col()
.gap_5()
.w(theme.dialog_width())
.max_h(window.viewport_size().height - margin * 2.0)
.p_6()
.rounded(theme.radius(Radius::Xl))
.bg(colors.overlay)
@@ -202,7 +229,7 @@ impl RenderOnce for Dialog {
.border_color(colors.border)
.shadow(theme.elevation(Elevation::Modal))
.child(heading)
.children(self.body)
.children(body)
.children(actions)
};
let rise = if fullscreen {
+40 -2
View File
@@ -13,7 +13,7 @@ use crate::{
buttons::Button,
forms::TextInput,
primitives::{FocusNext, FocusScope, Severity},
theme::Theme,
theme::{ActiveTheme, ControlSize, Theme},
};
#[derive(Clone, Copy, PartialEq)]
@@ -22,6 +22,7 @@ enum Open {
Alert,
Confirm,
Prompt,
Tall,
}
/// A popover, a hover card and one dialog at a time, recording what they do.
@@ -90,7 +91,11 @@ impl Render for Stage {
Button::new("follow", "Follow").on_click(move |_, window, cx| follow(window, cx))
},
);
let (shut, confirmed) = (self.shut(cx), self.note(cx, "confirmed"));
let (shut, confirmed, done) = (
self.shut(cx),
self.note(cx, "confirmed"),
self.note(cx, "done"),
);
let sent = cx.entity();
let overlay = self.open.map(|open| match open {
Open::Plain => Dialog::new("plain", "Plain", shut)
@@ -114,6 +119,12 @@ impl Render for Stage {
sent.update(cx, |stage, _| stage.log.push(text));
})
.into_any_element(),
Open::Tall => Dialog::new("tall", "Tall", shut)
.child(div().h(px(2000.0)))
.action(move |_| {
Button::new("tall-done", "Done").on_click(move |_, window, cx| done(window, cx))
})
.into_any_element(),
});
FocusScope::new(&self.root)
.size_full()
@@ -351,3 +362,30 @@ fn enter_on_a_prompt_button_runs_that_button_alone(cx: &mut TestAppContext) {
press("enter", cx);
assert_eq!(log(&view, cx), ["sent notes"]);
}
#[gpui::test]
fn a_tall_dialog_keeps_its_actions_in_the_window(cx: &mut TestAppContext) {
let (view, cx) = stage(cx);
cx.update(|_, cx| Theme::update(cx, |theme| theme.reduced_motion = true));
show(&view, Open::Tall, cx);
std::thread::sleep(Duration::from_millis(2));
settle(cx);
let (size, margin, width, button) = cx.update(|window, cx| {
let (theme, rem) = (cx.theme(), window.rem_size());
(
window.viewport_size(),
theme.titlebar_height().to_pixels(rem),
theme.dialog_width().to_pixels(rem),
theme.control_height(ControlSize::Md).to_pixels(rem),
)
});
let padding = px(24.0);
let x = size.width / 2.0 + width / 2.0 - padding - px(12.0);
let y = size.height - margin - padding - button / 2.0;
click(f32::from(x), f32::from(y), cx);
assert_eq!(
log(&view, cx),
["done"],
"the button sits at the card's foot, inside the window"
);
}