Lists · tree guides fall from the parent's chevron and run unbroken across rows (#2)
The chevron takes its indent as a margin, so no gap parts it from its guide column; the cursor's ring is an overlay, so the guides fill the row through its border.
This commit is contained in:
1 parent
943b7d4f8d
commit
ec586e371b
4 files changed
+45
-11
No files matched your search
+17
-11
@@ -48,14 +48,14 @@ pub(super) fn draw(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A faint line down each level a row sits under.
|
/// A faint line down each level a row sits under.
|
||||||
fn guides(depth: usize, cx: &App) -> impl IntoElement {
|
fn guides(name: &str, depth: usize, cx: &App) -> impl IntoElement {
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
div()
|
div()
|
||||||
.absolute()
|
.absolute()
|
||||||
.inset_0()
|
.inset_0()
|
||||||
.px_2()
|
.px_2()
|
||||||
.flex()
|
.flex()
|
||||||
.children((0..depth).map(|_| {
|
.children((0..depth).map(|level| {
|
||||||
div()
|
div()
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.w(theme.tree_indent())
|
.w(theme.tree_indent())
|
||||||
@@ -64,6 +64,7 @@ fn guides(depth: usize, cx: &App) -> impl IntoElement {
|
|||||||
.justify_center()
|
.justify_center()
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
.debug_selector(|| format!("tree-guide-{name}-{level}"))
|
||||||
.h_full()
|
.h_full()
|
||||||
.border_l_1()
|
.border_l_1()
|
||||||
.border_color(theme.colors.border),
|
.border_color(theme.colors.border),
|
||||||
@@ -121,8 +122,10 @@ fn row(rows: &Rows, ix: usize, window: &mut Window, cx: &mut App) -> AnyElement
|
|||||||
);
|
);
|
||||||
let (dropped_on, dragged_over, shut) = (key.clone(), key.clone(), key.clone());
|
let (dropped_on, dragged_over, shut) = (key.clone(), key.clone(), key.clone());
|
||||||
let chevron = div()
|
let chevron = div()
|
||||||
|
.debug_selector(|| format!("tree-chevron-{key}"))
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.w(indent)
|
.w(indent)
|
||||||
|
.ml(indent * item.depth as f32)
|
||||||
.flex()
|
.flex()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.when(opens, |slot| {
|
.when(opens, |slot| {
|
||||||
@@ -176,12 +179,6 @@ fn row(rows: &Rows, ix: usize, window: &mut Window, cx: &mut App) -> AnyElement
|
|||||||
.gap_1()
|
.gap_1()
|
||||||
.px_2()
|
.px_2()
|
||||||
.rounded(theme.radius(Radius::Sm))
|
.rounded(theme.radius(Radius::Sm))
|
||||||
.border_1()
|
|
||||||
.border_color(if rows.current == Some(ix) {
|
|
||||||
colors.focus
|
|
||||||
} else {
|
|
||||||
gpui::transparent_black()
|
|
||||||
})
|
|
||||||
.text_size(theme.text_size(TextSize::Sm))
|
.text_size(theme.text_size(TextSize::Sm))
|
||||||
.text_color(colors.fg)
|
.text_color(colors.fg)
|
||||||
.when(selected, |row| row.bg(colors.active))
|
.when(selected, |row| row.bg(colors.active))
|
||||||
@@ -189,8 +186,7 @@ fn row(rows: &Rows, ix: usize, window: &mut Window, cx: &mut App) -> AnyElement
|
|||||||
.when(landing == Some(DropAt::Inside), |row| {
|
.when(landing == Some(DropAt::Inside), |row| {
|
||||||
row.bg(colors.selection)
|
row.bg(colors.selection)
|
||||||
})
|
})
|
||||||
.child(guides(item.depth, cx))
|
.child(guides(&key, item.depth, cx))
|
||||||
.child(div().flex_none().w(indent * item.depth as f32))
|
|
||||||
.child(chevron)
|
.child(chevron)
|
||||||
.children(
|
.children(
|
||||||
checked
|
checked
|
||||||
@@ -218,6 +214,16 @@ fn row(rows: &Rows, ix: usize, window: &mut Window, cx: &mut App) -> AnyElement
|
|||||||
.child(Ellipsis::new(note))
|
.child(Ellipsis::new(note))
|
||||||
}))
|
}))
|
||||||
.children(landing.filter(|at| *at != DropAt::Inside).map(line))
|
.children(landing.filter(|at| *at != DropAt::Inside).map(line))
|
||||||
|
.when(rows.current == Some(ix), |row| {
|
||||||
|
row.child(
|
||||||
|
div()
|
||||||
|
.absolute()
|
||||||
|
.inset_0()
|
||||||
|
.rounded(theme.radius(Radius::Sm))
|
||||||
|
.border_1()
|
||||||
|
.border_color(colors.focus),
|
||||||
|
)
|
||||||
|
})
|
||||||
.on_click(move |event, window, cx| {
|
.on_click(move |event, window, cx| {
|
||||||
window.focus(&focus, cx);
|
window.focus(&focus, cx);
|
||||||
if event.click_count() == 2 {
|
if event.click_count() == 2 {
|
||||||
@@ -289,7 +295,7 @@ fn waiting(rows: &Rows, ix: usize, depth: usize, cx: &App) -> AnyElement {
|
|||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.px_2()
|
.px_2()
|
||||||
.child(guides(depth, cx))
|
.child(guides(&format!("waiting-{ix}"), depth, cx))
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex_none()
|
.flex_none()
|
||||||
|
|||||||
@@ -220,3 +220,23 @@ fn a_drop_in_a_folders_middle_moves_the_node_inside(cx: &mut TestAppContext) {
|
|||||||
[format!("move readme {:?} ui", DropAt::Inside)]
|
[format!("move readme {:?} ui", DropAt::Inside)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn guides_run_unbroken_under_the_parents_chevron(cx: &mut TestAppContext) {
|
||||||
|
let (_, cx) = explorer(false, cx);
|
||||||
|
let bounds = |name: &'static str, cx: &mut VisualTestContext| {
|
||||||
|
cx.debug_bounds(name).unwrap_or_else(|| panic!("no {name}"))
|
||||||
|
};
|
||||||
|
let chevron = bounds("tree-chevron-src", cx);
|
||||||
|
let (lib, ui) = (
|
||||||
|
bounds("tree-guide-lib-0", cx),
|
||||||
|
bounds("tree-guide-ui-0", cx),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
lib.center().x,
|
||||||
|
chevron.center().x,
|
||||||
|
"the guide falls from the chevron's middle"
|
||||||
|
);
|
||||||
|
assert_eq!(lib.bottom(), ui.top(), "one row's guide meets the next");
|
||||||
|
assert_eq!(lib.size.height, px(28.0), "a guide takes its row's height");
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# GitHub round, 2026-10-03
|
||||||
|
|
||||||
|
- [x] G1 PR #1: build on Windows with `escape_args`; review, verify, merge, answer CodeRabbit
|
||||||
|
- [x] G2 Issue #2: tree guides line up under the chevron and run unbroken across rows
|
||||||
|
- [ ] G3 Issue #3: Checkbox, Switch, Radio, Slider and Select name their role, label and state
|
||||||
|
- [ ] G4 Push, comment on #2 and #3, close #2
|
||||||
@@ -347,3 +347,5 @@
|
|||||||
| T48m | 1 | FAIL | the every-guide test never checked the title |
|
| T48m | 1 | FAIL | the every-guide test never checked the title |
|
||||||
| T48m | 2 | FAIL | the in-place link test used a hash link, which survives without preventDefault |
|
| T48m | 2 | FAIL | the in-place link test used a hash link, which survives without preventDefault |
|
||||||
| T48m | 3 | PASS | |
|
| T48m | 3 | PASS | |
|
||||||
|
| G1 | 1 | PASS | PR #1 merged; CodeRabbit's opt-out declined: Launch is argv |
|
||||||
|
| G2 | 1 | PASS | |
|
||||||
Reference in new issue
Block a user