T24d round 3 fix, after the cap
- BrowserPreview marks the shown frame with accent; the focus color stays the focus ring's - BrowserPreview and ComputerUseViewer take the host's ratio, 16:10 unless set, so frames keep their shape and a pointer's share lands on the picture; test a_screen_takes_its_pictures_shape - TASKS: the review moves to a Claude Fable 5.1 max session after codex ran out of quota; round 3 fixed after the cap, no fourth review - AGENTS: focus and choice colors part; host pictures keep their shape
This commit is contained in:
1 parent
6274b24f03
commit
8550c086b0
4 files changed
+77
-9
No files matched your search
@@ -137,6 +137,8 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
|
|||||||
- A flex line whose free space goes to an auto margin loses its gaps in taffy 0.9. A row that parts left and right groups its sides and uses `justify_between`; `ml_auto` is safe only beside a `flex_1` item that leaves no free space.
|
- A flex line whose free space goes to an auto margin loses its gaps in taffy 0.9. A row that parts left and right groups its sides and uses `justify_between`; `ml_auto` is safe only beside a `flex_1` item that leaves no free space.
|
||||||
- A header that holds a name beside counts and actions wraps: `flex_wrap`, the name `flex_1` with `min_w(label_width)`, the rest one `flex_none` group that drops below.
|
- A header that holds a name beside counts and actions wraps: `flex_wrap`, the name `flex_1` with `min_w(label_width)`, the rest one `flex_none` group that drops below.
|
||||||
- Every header, row and strip works at 280px: a name keeps its minimum width, the rest wraps below or scrolls, and nothing draws past its box.
|
- Every header, row and strip works at 280px: a name keeps its minimum width, the rest wraps below or scrolls, and nothing draws past its box.
|
||||||
|
- The focus color belongs to the focus ring. A chosen or shown item takes accent, as `forms::glyphs` and `lists::ListItem` do.
|
||||||
|
- A box that shows a host's picture takes the picture's shape from the host (`ratio`), so nothing is cropped and a point given as a share lands on the picture.
|
||||||
|
|
||||||
## Decisions
|
## Decisions
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Tasks
|
# Tasks
|
||||||
|
|
||||||
Progress truth. Work runs top to bottom. No item is skipped.
|
Progress truth. Work runs top to bottom. No item is skipped.
|
||||||
Each `T` item ends with a codex review (`gpt-6-astra`, effort `max`, herdr split pane). Three rounds at most.
|
Each `T` item ends with a review in a herdr split pane, three rounds at most: codex (`gpt-6-astra`, effort `max`) through T24d round 2; from T24d round 3, after codex ran out of quota on 2026-09-26, a Claude session on Fable 5.1 at max effort, at the user's word.
|
||||||
|
|
||||||
Per-component lines live in `tasks/`. Tags there:
|
Per-component lines live in `tasks/`. Tags there:
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ Per-component lines live in `tasks/`. Tags there:
|
|||||||
- [x] T24a Agent · Tool calls
|
- [x] T24a Agent · Tool calls
|
||||||
- [x] T24b Agent · Progress
|
- [x] T24b Agent · Progress
|
||||||
- [x] T24c Agent · Changes
|
- [x] T24c Agent · Changes
|
||||||
- [ ] T24d Agent · Previews
|
- [x] T24d Agent · Previews
|
||||||
- [ ] T24e Agent · Environment
|
- [ ] T24e Agent · Environment
|
||||||
- [ ] T24f Agent · Control and cost
|
- [ ] T24f Agent · Control and cost
|
||||||
- [ ] T25 Generative
|
- [ ] T25 Generative
|
||||||
@@ -281,3 +281,4 @@ Per-component lines live in `tasks/`. Tags there:
|
|||||||
| T24c | 2 | PASS | |
|
| T24c | 2 | PASS | |
|
||||||
| T24d | 1 | FAIL | at 280px eight thumbnails ran past the browser card; the artifact panel lost its title and its controls ran out of the box |
|
| T24d | 1 | FAIL | at 280px eight thumbnails ran past the browser card; the artifact panel lost its title and its controls ran out of the box |
|
||||||
| T24d | 2 | FAIL | Tab to a later thumbnail left the strip where it was, the focused frame and its ring clipped |
|
| T24d | 2 | FAIL | Tab to a later thumbnail left the strip where it was, the focused frame and its ring clipped |
|
||||||
|
| T24d | 3 | FAIL | reviewed by Claude Fable 5.1 max after codex ran out of quota: the shown thumbnail wore the focus color, so focus and choice looked alike; frames were forced to 16:10 and cropped, and a pointer's share missed its target. Fixed after the cap: the shown frame takes accent, and BrowserPreview and ComputerUseViewer take the host's ratio (test a_screen_takes_its_pictures_shape); no fourth review |
|
||||||
+28
-7
@@ -16,17 +16,22 @@ use crate::{
|
|||||||
typography::Ellipsis,
|
typography::Ellipsis,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Width over height of a frame from the host.
|
/// Width over height of a frame from the host, unless it says.
|
||||||
const FRAME: f32 = 16.0 / 10.0;
|
const FRAME: f32 = 16.0 / 10.0;
|
||||||
|
|
||||||
|
fn checked(ratio: f32) -> f32 {
|
||||||
|
assert!(ratio.is_finite() && ratio > 0.0, "a frame ratio of {ratio}");
|
||||||
|
ratio
|
||||||
|
}
|
||||||
|
|
||||||
/// A box that keeps a frame's shape at the width it is given.
|
/// A box that keeps a frame's shape at the width it is given.
|
||||||
fn framed(cx: &App) -> Div {
|
fn framed(ratio: f32, cx: &App) -> Div {
|
||||||
let mut frame = div()
|
let mut frame = div()
|
||||||
.relative()
|
.relative()
|
||||||
.w_full()
|
.w_full()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.bg(cx.theme().colors.sunken);
|
.bg(cx.theme().colors.sunken);
|
||||||
frame.style().aspect_ratio = Some(FRAME);
|
frame.style().aspect_ratio = Some(ratio);
|
||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +87,7 @@ pub struct BrowserPreview {
|
|||||||
url: SharedString,
|
url: SharedString,
|
||||||
frames: Vec<SharedString>,
|
frames: Vec<SharedString>,
|
||||||
shown: usize,
|
shown: usize,
|
||||||
|
ratio: f32,
|
||||||
loading: bool,
|
loading: bool,
|
||||||
on_show: Option<Pick>,
|
on_show: Option<Pick>,
|
||||||
}
|
}
|
||||||
@@ -101,11 +107,18 @@ impl BrowserPreview {
|
|||||||
url: url.into(),
|
url: url.into(),
|
||||||
frames,
|
frames,
|
||||||
shown,
|
shown,
|
||||||
|
ratio: FRAME,
|
||||||
loading: false,
|
loading: false,
|
||||||
on_show: None,
|
on_show: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The frames' width over their height, 16:10 unless set, so the boxes take the pictures' shape.
|
||||||
|
pub fn ratio(mut self, width_over_height: f32) -> Self {
|
||||||
|
self.ratio = checked(width_over_height);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn loading(mut self, loading: bool) -> Self {
|
pub fn loading(mut self, loading: bool) -> Self {
|
||||||
self.loading = loading;
|
self.loading = loading;
|
||||||
self
|
self
|
||||||
@@ -174,7 +187,7 @@ impl RenderOnce for BrowserPreview {
|
|||||||
.rounded(theme.radius(Radius::Sm))
|
.rounded(theme.radius(Radius::Sm))
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_color(if ix == shown {
|
.border_color(if ix == shown {
|
||||||
colors.focus
|
colors.accent
|
||||||
} else {
|
} else {
|
||||||
colors.border
|
colors.border
|
||||||
})
|
})
|
||||||
@@ -183,7 +196,7 @@ impl RenderOnce for BrowserPreview {
|
|||||||
.rounded(theme.radius(Radius::Sm))
|
.rounded(theme.radius(Radius::Sm))
|
||||||
.size_full(),
|
.size_full(),
|
||||||
);
|
);
|
||||||
tile.style().aspect_ratio = Some(FRAME);
|
tile.style().aspect_ratio = Some(self.ratio);
|
||||||
tile.when_some(show, |tile, show| {
|
tile.when_some(show, |tile, show| {
|
||||||
tile.track_focus(&handles[ix])
|
tile.track_focus(&handles[ix])
|
||||||
.focus_ring(cx)
|
.focus_ring(cx)
|
||||||
@@ -204,7 +217,7 @@ impl RenderOnce for BrowserPreview {
|
|||||||
card(cx)
|
card(cx)
|
||||||
.child(address_bar(&self.id, self.url, self.loading, None, cx))
|
.child(address_bar(&self.id, self.url, self.loading, None, cx))
|
||||||
.child(
|
.child(
|
||||||
framed(cx)
|
framed(self.ratio, cx)
|
||||||
.when(strip.is_none(), |frame| {
|
.when(strip.is_none(), |frame| {
|
||||||
frame.rounded_b(theme.radius(Radius::Lg))
|
frame.rounded_b(theme.radius(Radius::Lg))
|
||||||
})
|
})
|
||||||
@@ -228,6 +241,7 @@ impl RenderOnce for BrowserPreview {
|
|||||||
pub struct ComputerUseViewer {
|
pub struct ComputerUseViewer {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
frame: SharedString,
|
frame: SharedString,
|
||||||
|
ratio: f32,
|
||||||
pointer: Option<Point<f32>>,
|
pointer: Option<Point<f32>>,
|
||||||
action: Option<SharedString>,
|
action: Option<SharedString>,
|
||||||
}
|
}
|
||||||
@@ -238,11 +252,18 @@ impl ComputerUseViewer {
|
|||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
frame: frame.into(),
|
frame: frame.into(),
|
||||||
|
ratio: FRAME,
|
||||||
pointer: None,
|
pointer: None,
|
||||||
action: None,
|
action: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The frame's width over its height, 16:10 unless set, so the box takes the picture's shape.
|
||||||
|
pub fn ratio(mut self, width_over_height: f32) -> Self {
|
||||||
|
self.ratio = checked(width_over_height);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Where the agent points, each side a share of the frame from its top left.
|
/// Where the agent points, each side a share of the frame from its top left.
|
||||||
pub fn pointer(mut self, at: Point<f32>) -> Self {
|
pub fn pointer(mut self, at: Point<f32>) -> Self {
|
||||||
assert!(
|
assert!(
|
||||||
@@ -302,7 +323,7 @@ impl RenderOnce for ComputerUseViewer {
|
|||||||
});
|
});
|
||||||
card(cx)
|
card(cx)
|
||||||
.child(
|
.child(
|
||||||
framed(cx)
|
framed(self.ratio, cx)
|
||||||
.rounded_t(theme.radius(Radius::Lg))
|
.rounded_t(theme.radius(Radius::Lg))
|
||||||
.when(self.action.is_none(), |frame| {
|
.when(self.action.is_none(), |frame| {
|
||||||
frame.rounded_b(theme.radius(Radius::Lg))
|
frame.rounded_b(theme.radius(Radius::Lg))
|
||||||
|
|||||||
@@ -244,3 +244,47 @@ fn tab_brings_a_hidden_frame_into_view(cx: &mut TestAppContext) {
|
|||||||
"the eighth frame sits in view"
|
"the eighth frame sits in view"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A 4:3 screen in a 480px column, and its height as drawn.
|
||||||
|
struct Screen {
|
||||||
|
height: Rc<Cell<Pixels>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for Screen {
|
||||||
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let height = self.height.clone();
|
||||||
|
div()
|
||||||
|
.relative()
|
||||||
|
.w(px(480.0))
|
||||||
|
.child(
|
||||||
|
ComputerUseViewer::new("screen", "a.png")
|
||||||
|
.ratio(4.0 / 3.0)
|
||||||
|
.pointer(point(0.5, 0.95)),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
canvas(
|
||||||
|
move |bounds, _, _| height.set(bounds.size.height),
|
||||||
|
|_, _, _, _| {},
|
||||||
|
)
|
||||||
|
.absolute()
|
||||||
|
.top_0()
|
||||||
|
.left_0()
|
||||||
|
.size_full(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_screen_takes_its_pictures_shape(cx: &mut TestAppContext) {
|
||||||
|
setup(cx);
|
||||||
|
let height = Rc::new(Cell::new(Pixels::ZERO));
|
||||||
|
let seen = height.clone();
|
||||||
|
let (_, cx) = cx.add_window_view(|_, _| Screen { height: seen });
|
||||||
|
settle(cx);
|
||||||
|
let expected = px(478.0 * 3.0 / 4.0 + 2.0);
|
||||||
|
assert!(
|
||||||
|
(height.get() - expected).abs() < px(1.0),
|
||||||
|
"478px inside the border at 4:3, plus the border: {:?} vs {expected:?}",
|
||||||
|
height.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user