T24c round 1 fix

- FileChangeCard's header wraps: the path keeps label_width, counts and
  verdict drop below as one group; MultiFileDiffReview's header wraps its
  counts and its all-buttons inside the box, parted by justify_between
- git::DiffViewer's fold rows are Tab stops with a focus ring when the
  owner opens folds; every row keeps a transparent border so heights match;
  an inert fold no longer shows a pointer
- tests: a_narrow_review_wraps_its_rows_inside_its_box,
  git::a_fold_opens_from_the_keyboard; the gallery adds a 280px review
- AGENTS: taffy drops gaps beside an auto margin; wrapping headers
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 08:52:38 -04:00
1 parent 0a44a2d905
commit b9bff970d0
8 files changed
+172 -28

No files matched your search

+32 -16
View File
@@ -135,6 +135,7 @@ impl RenderOnce for FileChangeCard {
div()
.id((self.id.clone(), "header"))
.flex()
.flex_wrap()
.items_center()
.gap_2()
.px_2()
@@ -162,17 +163,20 @@ impl RenderOnce for FileChangeCard {
.child(
div()
.flex_1()
.min_w_0()
.min_w(theme.label_width())
.font_family(theme.mono_family.clone())
.child(Ellipsis::new(self.change.path.clone())),
)
.child(div().flex_none().child(DiffStat::new(added, removed)))
.child(div().flex_none().child(verdict(
&self.id,
self.change.state,
decide,
cx,
))),
.child(
div()
.flex_none()
.ml_auto()
.flex()
.items_center()
.gap_2()
.child(DiffStat::new(added, removed))
.child(verdict(&self.id, self.change.state, decide, cx)),
),
)
.when(open, |card| {
card.child(
@@ -248,6 +252,7 @@ impl RenderOnce for MultiFileDiffReview {
let all = self.on_decide.clone().filter(|_| open > 0).map(|decide| {
let (reject, accept) = (decide.clone(), decide);
div()
.flex_none()
.flex()
.items_center()
.gap_1()
@@ -279,18 +284,29 @@ impl RenderOnce for MultiFileDiffReview {
.child(
div()
.flex()
.flex_wrap()
.items_center()
.gap_3()
.justify_between()
.gap_y_2()
.child(
div()
.flex_none()
.font_weight(FontWeight::MEDIUM)
.child(format!("{count} files changed")),
.flex()
.flex_wrap()
.items_center()
.gap_x_3()
.gap_y_1()
.child(
div()
.font_weight(FontWeight::MEDIUM)
.child(format!("{count} files changed")),
)
.child(DiffStat::new(added, removed))
.child(
div()
.text_color(colors.fg_subtle)
.child(format!("{} of {count} reviewed", count - open)),
),
)
.child(div().flex_none().child(DiffStat::new(added, removed)))
.child(div().flex_1().min_w_0().text_color(colors.fg_subtle).child(
Ellipsis::new(format!("{} of {count} reviewed", count - open)),
))
.children(all),
)
.children(self.changes.into_iter().enumerate().map(|(ix, change)| {
+58 -3
View File
@@ -31,7 +31,7 @@ fn setup(cx: &mut TestAppContext) {
});
}
/// One change card in a 400px column, its verdicts and the column's height.
/// One change card in a 640px column, its verdicts and the column's height.
struct Card {
verdicts: Vec<bool>,
height: Rc<Cell<Pixels>>,
@@ -42,7 +42,7 @@ impl Render for Card {
let (view, height) = (cx.entity(), self.height.clone());
div()
.relative()
.w(px(400.0))
.w(px(640.0))
.child(
FileChangeCard::new("card", change("src/theme/lift.rs")).on_decide(
move |accepted, _, cx| view.update(cx, |card, _| card.verdicts.push(accepted)),
@@ -72,7 +72,7 @@ fn a_press_on_accept_decides_and_leaves_the_card_shut(cx: &mut TestAppContext) {
});
settle(cx);
let shut = height.get();
let accept = point(px(400.0 - 16.0), shut / 2.0);
let accept = point(px(640.0 - 16.0), shut / 2.0);
cx.simulate_mouse_move(accept, None, Modifiers::none());
cx.simulate_click(accept, Modifiers::none());
settle(cx);
@@ -135,3 +135,58 @@ fn a_cards_verdict_names_its_file(cx: &mut TestAppContext) {
[Decision::Accept(1)]
);
}
/// A review at `width`, and its height as drawn.
struct Narrow {
width: Pixels,
height: Rc<Cell<Pixels>>,
}
impl Render for Narrow {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
let height = self.height.clone();
div()
.relative()
.w(self.width)
.child(
MultiFileDiffReview::new(
"narrow",
["src/theme/lift.rs", "src/theme/tokens.rs"].map(change),
)
.on_decide(|_, _, _| {}),
)
.child(
canvas(
move |bounds, _, _| height.set(bounds.size.height),
|_, _, _, _| {},
)
.absolute()
.top_0()
.left_0()
.size_full(),
)
}
}
#[gpui::test]
fn a_narrow_review_wraps_its_rows_inside_its_box(cx: &mut TestAppContext) {
setup(cx);
let height = Rc::new(Cell::new(Pixels::ZERO));
let seen = height.clone();
let (view, cx) = cx.add_window_view(|_, _| Narrow {
width: px(640.0),
height: seen,
});
settle(cx);
let wide = height.get();
view.update(cx, |narrow, cx| {
narrow.width = px(280.0);
cx.notify();
});
settle(cx);
assert!(
height.get() > wide,
"at 280px the counts and verdicts wrap below: {:?} vs {wide:?}",
height.get()
);
}