mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
fix(sidebar): let an agent's status dot sit outside its disc (#846)
`status_dot` places itself with negative offsets so that it overhangs the avatar's edge — that overhang is what makes it read as a badge sitting on the disc rather than a notch bitten out of it. But it is added as a child of the element carrying `rounded_full`, so everything past the circle is clipped along the arc and the badge comes back as a crescent. Give the wrapper the positioning and move the disc down a level. The radius then only ever clips the disc's own fill and mark, and the dot becomes a sibling drawn after it, which settles the paint order too. No test: the change is structural — which element carries the radius — and the tests here cover the pure decisions behind the avatar (`needs_edge`, `agent_status_label`) rather than its element tree.
This commit is contained in:
+48
-38
@@ -1319,13 +1319,22 @@ impl Tty7App {
|
||||
size: f32,
|
||||
cx: &App,
|
||||
) -> gpui::AnyElement {
|
||||
let base = div()
|
||||
.id(id)
|
||||
.flex_shrink_0()
|
||||
.size(px(size))
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center();
|
||||
// The wrapper positions; the disc below carries the radius.
|
||||
// `status_dot` hangs itself off the edge with negative offsets — that
|
||||
// overhang is what makes it a badge on the avatar rather than a notch
|
||||
// in it — and as a child of the rounded element the overhang was
|
||||
// clipped along the arc, leaving a crescent.
|
||||
let base = div().id(id).flex_shrink_0().relative().size(px(size));
|
||||
// Fill, hairline and mark all live here, so the radius only ever clips
|
||||
// the disc's own paint.
|
||||
let disc = || {
|
||||
div()
|
||||
.size(px(size))
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.rounded_full()
|
||||
};
|
||||
match agent {
|
||||
Some(agent) => {
|
||||
let hollow = status == Some(crate::core::cli_agent::AgentStatus::Waiting);
|
||||
@@ -1344,40 +1353,41 @@ impl Tty7App {
|
||||
// column of twenty.
|
||||
let accent = agent.accent_rgb();
|
||||
let surface = cx.theme().background;
|
||||
base.relative()
|
||||
.rounded_full()
|
||||
.bg(gpui::rgb(accent))
|
||||
// Codex and Grok are both pure black, which is the window
|
||||
// fill on a dark theme — the disc dissolves and leaves the
|
||||
// glyph floating. A hairline keeps it a disc in any theme.
|
||||
.when(crate::ui::presets::needs_edge(accent, surface), |d| {
|
||||
d.border_1().border_color(cx.theme().border)
|
||||
})
|
||||
.child(
|
||||
gpui::svg()
|
||||
.path(agent.icon_path())
|
||||
.size(px(size * 0.54))
|
||||
// SVG assets render as a single-colour mask, so
|
||||
// the mark's colour comes from the agent rather
|
||||
// than from the file. The tray icon reads the same
|
||||
// answer.
|
||||
.text_color(gpui::rgb(agent.icon_rgb())),
|
||||
)
|
||||
.when_some(dot, |b, dot| b.child(dot))
|
||||
.tooltip(move |window, cx| {
|
||||
gpui_component::tooltip::Tooltip::new(tip.clone()).build(window, cx)
|
||||
})
|
||||
.into_any_element()
|
||||
base.child(
|
||||
disc()
|
||||
.bg(gpui::rgb(accent))
|
||||
// Codex and Grok are both pure black, which is the
|
||||
// window fill on a dark theme — the disc dissolves and
|
||||
// leaves the glyph floating. A hairline keeps it a disc
|
||||
// in any theme.
|
||||
.when(crate::ui::presets::needs_edge(accent, surface), |d| {
|
||||
d.border_1().border_color(cx.theme().border)
|
||||
})
|
||||
.child(
|
||||
gpui::svg()
|
||||
.path(agent.icon_path())
|
||||
.size(px(size * 0.54))
|
||||
// SVG assets render as a single-colour mask, so
|
||||
// the mark's colour comes from the agent rather
|
||||
// than from the file. The tray icon reads the
|
||||
// same answer.
|
||||
.text_color(gpui::rgb(agent.icon_rgb())),
|
||||
),
|
||||
)
|
||||
.when_some(dot, |b, dot| b.child(dot))
|
||||
.tooltip(move |window, cx| {
|
||||
gpui_component::tooltip::Tooltip::new(tip.clone()).build(window, cx)
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
None => base
|
||||
.relative()
|
||||
.rounded_full()
|
||||
.bg(cx.theme().muted)
|
||||
.child(
|
||||
gpui::svg()
|
||||
.path("icons/terminal.svg")
|
||||
.size(px(size * 0.56))
|
||||
.text_color(cx.theme().foreground.opacity(0.65)),
|
||||
disc().bg(cx.theme().muted).child(
|
||||
gpui::svg()
|
||||
.path("icons/terminal.svg")
|
||||
.size(px(size * 0.56))
|
||||
.text_color(cx.theme().foreground.opacity(0.65)),
|
||||
),
|
||||
)
|
||||
.when_some(ssh, |b, rgb| {
|
||||
b.child(Self::status_dot(rgb, 0, size, cx.theme().background, false))
|
||||
|
||||
Reference in New Issue
Block a user