use crate::{prelude::FluentBuilder as _, *};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum BubbleSide {
#[default]
Left,
Right,
}
#[derive(IntoElement)]
pub struct Bubble {
side: BubbleSide,
avatar: Option<AnyElement>,
children: Vec<AnyElement>,
style: StyleRefinement,
}
impl Bubble {
pub fn new() -> Self {
Self {
side: BubbleSide::Left,
avatar: None,
children: Vec::new(),
style: StyleRefinement::default(),
}
}
pub fn side(mut self, side: BubbleSide) -> Self {
self.side = side;
self
}
pub fn avatar(mut self, avatar: impl IntoElement) -> Self {
self.avatar = Some(avatar.into_any_element());
self
}
}
impl Default for Bubble {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for Bubble {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl Styled for Bubble {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for Bubble {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let theme = cx.theme();
let accent = theme.tokens.accent.color;
let muted = theme.tokens.muted;
let user_style = self.style;
let bubble_bg = match self.side {
BubbleSide::Left => muted.opacity(0.12),
BubbleSide::Right => accent.opacity(0.18),
};
let mut row = div().flex().w_full().gap(px(8.0)).items_start().py(px(4.0));
row = match self.side {
BubbleSide::Left => row.justify_start(),
BubbleSide::Right => row.justify_end().flex_row_reverse(),
};
if let Some(avatar) = self.avatar {
row = row.child(div().flex_shrink_0().child(avatar));
}
row.child(
div()
.flex()
.flex_col()
.gap(px(4.0))
.px(px(12.0))
.py(px(8.0))
.rounded_lg()
.bg(bubble_bg)
.max_w(relative(0.75))
.children(self.children),
)
.map(|mut this| {
this.style().refine(&user_style);
this
})
}
}