1use gpui::prelude::*;
12use gpui::{div, px, AnyElement, App, IntoElement, SharedString, Window};
13
14use crate::icon::{Icon, IconName};
15use crate::theme::{theme, ColorName, Size};
16
17#[derive(IntoElement)]
22pub struct Blockquote {
23 children: Vec<AnyElement>,
24 text: Option<SharedString>,
25 color: ColorName,
26 cite: Option<SharedString>,
27 icon: Option<IconName>,
28 padding: Size,
29 radius: Option<Size>,
30}
31
32impl Blockquote {
33 pub fn new() -> Self {
34 Blockquote {
35 children: Vec::new(),
36 text: None,
37 color: ColorName::Blue,
38 cite: None,
39 icon: None,
40 padding: Size::Lg,
41 radius: None,
42 }
43 }
44
45 pub fn text(mut self, text: impl Into<SharedString>) -> Self {
47 self.text = Some(text.into());
48 self
49 }
50
51 pub fn color(mut self, color: ColorName) -> Self {
53 self.color = color;
54 self
55 }
56
57 pub fn cite(mut self, cite: impl Into<SharedString>) -> Self {
60 self.cite = Some(cite.into());
61 self
62 }
63
64 pub fn icon(mut self, icon: IconName) -> Self {
66 self.icon = Some(icon);
67 self
68 }
69
70 pub fn padding(mut self, padding: Size) -> Self {
71 self.padding = padding;
72 self
73 }
74
75 pub fn radius(mut self, radius: Size) -> Self {
76 self.radius = Some(radius);
77 self
78 }
79}
80
81impl Default for Blockquote {
82 fn default() -> Self {
83 Blockquote::new()
84 }
85}
86
87impl ParentElement for Blockquote {
88 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
89 self.children.extend(elements);
90 }
91}
92
93impl RenderOnce for Blockquote {
94 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
95 let t = theme(cx);
96 let dark = t.scheme.is_dark();
97 let accent = t.color(self.color, if dark { 4 } else { 6 }).hsla();
98 let wash = t.color(self.color, if dark { 5 } else { 6 }).alpha(0.06);
99 let text_color = t.text().hsla();
100 let dimmed = t.dimmed().hsla();
101 let padding = t.spacing(self.padding);
102 let gap = t.spacing(Size::Sm);
103 let radius = t.radius(self.radius.unwrap_or(t.default_radius));
104 let font_md = t.font_size(Size::Md);
105 let font_sm = t.font_size(Size::Sm);
106
107 let mut el = div()
108 .flex()
109 .flex_col()
110 .gap(px(gap))
111 .p(px(padding))
112 .border_l(px(3.0))
113 .border_color(accent)
114 .rounded_r(px(radius))
115 .bg(wash)
116 .text_size(px(font_md))
117 .text_color(text_color);
118
119 if let Some(icon) = self.icon {
120 el = el.child(
121 div()
122 .flex()
123 .text_color(accent)
124 .child(Icon::new(icon).size(Size::Sm)),
125 );
126 }
127 if let Some(text) = self.text {
128 el = el.child(div().child(text));
129 }
130 el = el.children(self.children);
131 if let Some(cite) = self.cite {
132 el = el.child(div().text_size(px(font_sm)).text_color(dimmed).child(cite));
133 }
134 el
135 }
136}