add reveal text

This commit is contained in:
2026-10-30 14:03:14 +07:00
parent 905a339e3e
commit 41837e487b
5 changed files with 189 additions and 48 deletions
+46 -4
View File
@@ -1,12 +1,13 @@
use std::collections::BTreeMap;
use std::rc::Rc;
use std::time::Duration;
use gpui::prelude::FluentBuilder as _;
use gpui::{
AnyElement, App, ClickEvent, Context, ElementId, InteractiveElement as _, IntoElement,
MouseButton, MouseDownEvent, ObjectFit, ParentElement as _, RenderOnce, SharedString,
SharedUri, StatefulInteractiveElement as _, StyleRefinement, Styled, StyledImage, Window, div,
img, px,
Animation, AnimationExt as _, AnyElement, App, ClickEvent, Context, ElementId,
InteractiveElement as _, IntoElement, MouseButton, MouseDownEvent, ObjectFit,
ParentElement as _, RenderOnce, SharedString, SharedUri, StatefulInteractiveElement as _,
StyleRefinement, Styled, StyledImage, Window, div, img, px,
};
use gpui_kit::assets::IconName;
use gpui_kit::component::button::{Button, ButtonVariants as _};
@@ -750,3 +751,44 @@ impl RenderOnce for MessageActions {
.refine_style(&style)
}
}
/// A message's text revealed word by word, paced by the estimated speech duration.
#[derive(IntoElement)]
pub struct RevealText {
text: SharedString,
duration: Duration,
}
impl RevealText {
pub fn new(text: impl Into<SharedString>, duration: Duration) -> Self {
Self {
text: text.into(),
duration,
}
}
}
impl RenderOnce for RevealText {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let words: Vec<SharedString> = self
.text
.split_whitespace()
.map(SharedString::from)
.collect();
let total = words.len().max(1) as f32;
div().flex().flex_wrap().gap_x_1().with_animation(
"speech-reveal",
Animation::new(self.duration).with_max_fps(30.),
move |this, progress| {
let visible = ((progress * total).ceil() as usize).min(words.len());
this.children(words.iter().enumerate().map(|(ix, word)| {
div()
.when(ix >= visible, |this| this.invisible())
.child(word.clone())
}))
},
)
}
}