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