T23e: AI chat, welcome

- WelcomeScreen: a greeting for the hour over the owner's composer,
  starters and cards, centered while it fits and scrolled from its top
  when it does not
- SuggestionChips, FollowUpSuggestions and CapabilityCards: each press asks
  the owner; rows and cards are Tab stops
- PromptLibrary is documents::TemplatePicker over saved prompts
- gallery: starters and cards fill the welcome composer, a saved prompt
  fills it too, send clears it with a toast, a follow-up asks its question
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 07:50:09 -04:00
1 parent b967e7d208
commit f64dd5806c
7 files changed
+556 -5

No files matched your search

+1
View File
@@ -10,6 +10,7 @@ use gpui::{
mod cite;
mod compose;
mod history;
mod welcome;
use super::{
ImageMessage, MessageAvatar, MessageBubble, MessageEditor, MessageList, Role, ThinkingBlock,
+55
View File
@@ -0,0 +1,55 @@
use std::{cell::Cell, rc::Rc};
use gpui::{
Context, IntoElement, ParentElement, Pixels, Render, Styled, TestAppContext, Window, canvas,
div, px,
};
use super::settle;
use crate::{chat::WelcomeScreen, theme::Theme};
/// A welcome screen of `height` over a tall body, noting where its first child sits.
struct Welcome {
height: Pixels,
top: Rc<Cell<Pixels>>,
}
impl Render for Welcome {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
let top = self.top.clone();
div().w(px(600.0)).h(self.height).child(
WelcomeScreen::new("welcome", 9)
.child(
canvas(move |bounds, _, _| top.set(bounds.top()), |_, _, _, _| {}).h(px(10.0)),
)
.child(div().h(px(400.0))),
)
}
}
#[gpui::test]
fn the_welcome_centers_what_fits_and_scrolls_what_does_not(cx: &mut TestAppContext) {
cx.update(Theme::init);
let top = Rc::new(Cell::new(Pixels::ZERO));
let seen = top.clone();
let (view, cx) = cx.add_window_view(|_, _| Welcome {
height: px(1200.0),
top: seen,
});
settle(cx);
assert!(
top.get() > px(300.0),
"centered in a tall space, not at {:?}",
top.get()
);
view.update(cx, |view, cx| {
view.height = px(200.0);
cx.notify();
});
settle(cx);
assert!(
top.get() > Pixels::ZERO,
"a short space keeps the start in reach, not at {:?}",
top.get()
);
}