Files
Ely-GPUI-Components/examples/gallery/pages/agent/previews.rs
T
ZacharyZhang-NY 26913df98a T24d: Agent, previews
- BrowserPreview: the address with a lock and a spinner while it loads, the
  host's frame shown, and the frames so far along the foot as Tab stops;
  ScreenshotStream is that strip
- ComputerUseViewer: the host's frame, a ring where the agent points that
  rings again at each new point, and what it does there
- LivePreview: the host's page under its address, with reload
- ArtifactPanel: title, versions through chat::BranchNavigator, Preview and
  Source when it has both, copy and download; it fails loud with neither
- gallery: frames cut from the gallery's own pages; one asset! macro in
  main.rs replaces three copies
2026-09-26 08:59:12 -04:00

164 lines
6.0 KiB
Rust

use ely_gpui_component::{
agent::{ArtifactPanel, BrowserPreview, ComputerUseViewer, LivePreview},
buttons::{Button, ButtonVariant},
chat::CodeBlock,
documents::MarkdownRenderer,
primitives::IconName,
theme::{ActiveTheme, TextSize},
typography::format::plural,
};
use gpui::{
App, ClipboardItem, FontWeight, IntoElement, ParentElement, Styled, Window, div, point, px,
};
use crate::{
probe::probe,
ui::{keep, section, set},
};
const FRAMES: [&str; 3] = [
asset!("frames/frame-1.jpg"),
asset!("frames/frame-2.jpg"),
asset!("frames/frame-3.jpg"),
];
const ADDRESSES: [&str; 3] = [
"localhost:5173/navigation",
"localhost:5173/git",
"localhost:5173/chat",
];
/// Where the agent points on the screen, and what it does there.
const ACTIONS: [(f32, f32, &str); 3] = [
(0.42, 0.31, "Click Full name"),
(0.42, 0.31, "Type Ada Lovelace"),
(0.34, 0.82, "Click Password"),
];
pub fn watching(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let shown = keep("agent-frame", || 2_usize, window, cx);
let step = keep("agent-pointer", || 0_usize, window, cx);
let (now, at) = (*shown.read(cx), *step.read(cx));
let (x, y, action) = ACTIONS[at];
section(
"BrowserPreview / ScreenshotStream / ComputerUseViewer",
"What an agent sees as it works, in frames from the host: a browser with its address and the frames so far, a press on one shows it; and a screen with where the agent points, a ring for each new point, and what it does there.",
cx,
)
.child(
div()
.flex()
.items_start()
.gap_6()
.child(
div().w(px(480.)).child(
BrowserPreview::new("agent-browser", ADDRESSES[now], FRAMES, now)
.loading(now == FRAMES.len() - 1)
.on_show(move |ix, _, cx| set(&shown, ix, cx)),
),
)
.child(
div()
.w(px(420.))
.flex()
.flex_col()
.gap_3()
.child(
ComputerUseViewer::new("agent-screen", asset!("frames/screen.jpg"))
.pointer(point(x, y))
.action(action),
)
.child(probe(
"agent-pointer-next",
Button::new("agent-pointer-next", "Next action")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
let next = (*step.read(cx) + 1) % ACTIONS.len();
set(&step, next, cx)
}),
)),
),
)
}
const NOTE: &str = "# Lift\n\nA **lift** blends a color toward white. Dark themes lift their accents further, because saturated color on charcoal looks louder.\n\n- Accents lift by 18%\n- Surfaces lift by 4%";
const LIFT: &str =
"pub fn lift(color: Hsla, by: f32) -> Hsla {\n color.mix(white(), by.clamp(0.0, 1.0))\n}";
/// A small page as the host would draw it.
fn page(builds: usize, cx: &App) -> impl IntoElement + use<> {
let theme = cx.theme();
div()
.p_6()
.flex()
.flex_col()
.gap_3()
.child(
div()
.text_size(theme.text_size(TextSize::Xl))
.font_weight(FontWeight::SEMIBOLD)
.child("Lift"),
)
.child(
div()
.text_color(theme.colors.fg_muted)
.child("Blend a color toward white."),
)
.child(
div()
.flex()
.child(Button::new("agent-page-try", "Try it").variant(ButtonVariant::Primary)),
)
.child(
div()
.text_size(theme.text_size(TextSize::Xs))
.text_color(theme.colors.fg_subtle)
.child(format!("Built {}", plural(builds as u64, "time", "times"))),
)
}
pub fn artifacts(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let version = keep("agent-version", || 2_usize, window, cx);
let builds = keep("agent-builds", || 1_usize, window, cx);
let (now, built) = (*version.read(cx), *builds.read(cx));
section(
"ArtifactPanel / ArtifactVersionSwitcher / LivePreview",
"What an agent made, in a panel of its own: the version shown among all, copy and download, the artifact as preview or source; the version switcher is chat::BranchNavigator. A live preview holds the host's page with its address and reload.",
cx,
)
.child(
div()
.flex()
.items_start()
.gap_6()
.child(
div().w(px(460.)).h(px(360.)).child(
ArtifactPanel::new("agent-note", "Notes on lift", IconName::FileText)
.version(now, 3, move |to, _, cx| set(&version, to, cx))
.preview(div().p_4().child(MarkdownRenderer::new("agent-note-text", NOTE)))
.source(div().p_3().child(CodeBlock::new("agent-note-source", NOTE).language("markdown")))
.on_copy(|_, cx| cx.write_to_clipboard(ClipboardItem::new_string(NOTE.to_string()))),
),
)
.child(
div().w(px(420.)).h(px(360.)).child(
ArtifactPanel::new("agent-code", "lift.rs", IconName::Code)
.source(div().p_3().child(CodeBlock::new("agent-code-source", LIFT).language("rust"))),
),
),
)
.child(
div()
.w(px(460.))
.h(px(280.))
.child(
LivePreview::new("agent-live", "localhost:5173/lift", page(built, cx))
.on_reload(move |_, cx| {
let next = *builds.read(cx) + 1;
set(&builds, next, cx)
}),
),
)
}