ratatui/widgets/logo.rs
1use indoc::indoc;
2
3use crate::{buffer::Buffer, layout::Rect, text::Text, widgets::Widget};
4
5/// A widget that renders the Ratatui logo
6///
7/// The Ratatui logo takes up two lines of text and comes in two sizes: `Tiny` and `Small`. This may
8/// be used in an application's help or about screen to show that it is powered by Ratatui.
9///
10/// # Examples
11///
12/// The [Ratatui-logo] example demonstrates how to use the `RatatuiLogo` widget. This can be run by
13/// cloning the Ratatui repository and then running the following command with an optional size
14/// argument:
15///
16/// ```shell
17/// cargo run --example ratatui-logo [size]
18/// ```
19///
20/// [Ratatui-logo]: https://github.com/ratatui/ratatui/blob/main/examples/ratatui-logo.rs
21///
22/// ## Tiny (default, 2x15 characters)
23///
24/// ```
25/// use ratatui::widgets::RatatuiLogo;
26///
27/// # fn draw(frame: &mut ratatui::Frame) {
28/// frame.render_widget(RatatuiLogo::tiny(), frame.area());
29/// # }
30/// ```
31///
32/// Renders:
33///
34/// ```text
35/// ▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌
36/// ▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌
37/// ```
38///
39/// ## Small (2x27 characters)
40///
41/// ```
42/// use ratatui::widgets::RatatuiLogo;
43///
44/// # fn draw(frame: &mut ratatui::Frame) {
45/// frame.render_widget(RatatuiLogo::small(), frame.area());
46/// # }
47/// ```
48///
49/// Renders:
50///
51/// ```text
52/// █▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █
53/// █▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █
54/// ```
55#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
56pub struct RatatuiLogo {
57 size: Size,
58}
59
60/// The size of the logo
61#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
62#[non_exhaustive]
63pub enum Size {
64 /// A tiny logo
65 ///
66 /// The default size of the logo (2x15 characters)
67 ///
68 /// ```text
69 /// ▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌
70 /// ▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌
71 /// ```
72 #[default]
73 Tiny,
74 /// A small logo
75 ///
76 /// A slightly larger version of the logo (2x27 characters)
77 ///
78 /// ```text
79 /// █▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █
80 /// █▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █
81 /// ```
82 Small,
83}
84
85impl RatatuiLogo {
86 /// Create a new Ratatui logo widget
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// use ratatui::widgets::{RatatuiLogo, RatatuiLogoSize};
92 ///
93 /// let logo = RatatuiLogo::new(RatatuiLogoSize::Tiny);
94 /// ```
95 pub const fn new(size: Size) -> Self {
96 Self { size }
97 }
98
99 /// Set the size of the logo
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use ratatui::widgets::{RatatuiLogo, RatatuiLogoSize};
105 ///
106 /// let logo = RatatuiLogo::default().size(RatatuiLogoSize::Small);
107 /// ```
108 #[must_use]
109 pub const fn size(self, size: Size) -> Self {
110 let _ = self;
111 Self { size }
112 }
113
114 /// Create a new Ratatui logo widget with a tiny size
115 ///
116 /// # Examples
117 ///
118 /// ```
119 /// use ratatui::widgets::RatatuiLogo;
120 ///
121 /// let logo = RatatuiLogo::tiny();
122 /// ```
123 pub const fn tiny() -> Self {
124 Self::new(Size::Tiny)
125 }
126
127 /// Create a new Ratatui logo widget with a small size
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// use ratatui::widgets::RatatuiLogo;
133 ///
134 /// let logo = RatatuiLogo::small();
135 /// ```
136 pub const fn small() -> Self {
137 Self::new(Size::Small)
138 }
139}
140
141impl Widget for RatatuiLogo {
142 fn render(self, area: Rect, buf: &mut Buffer) {
143 let logo = self.size.as_str();
144 Text::raw(logo).render(area, buf);
145 }
146}
147
148impl Size {
149 const fn as_str(self) -> &'static str {
150 match self {
151 Self::Tiny => Self::tiny(),
152 Self::Small => Self::small(),
153 }
154 }
155
156 const fn tiny() -> &'static str {
157 indoc! {"
158 ▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌
159 ▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌
160 "}
161 }
162
163 const fn small() -> &'static str {
164 indoc! {"
165 █▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █
166 █▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █
167 "}
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use rstest::rstest;
174
175 use super::*;
176
177 #[rstest]
178 #[case::tiny(Size::Tiny)]
179 #[case::small(Size::Small)]
180 fn new_size(#[case] size: Size) {
181 let logo = RatatuiLogo::new(size);
182 assert_eq!(logo.size, size);
183 }
184
185 #[test]
186 fn default_logo_is_tiny() {
187 let logo = RatatuiLogo::default();
188 assert_eq!(logo.size, Size::Tiny);
189 }
190
191 #[test]
192 fn set_logo_size_to_small() {
193 let logo = RatatuiLogo::default().size(Size::Small);
194 assert_eq!(logo.size, Size::Small);
195 }
196
197 #[test]
198 fn tiny_logo_constant() {
199 let logo = RatatuiLogo::tiny();
200 assert_eq!(logo.size, Size::Tiny);
201 }
202
203 #[test]
204 fn small_logo_constant() {
205 let logo = RatatuiLogo::small();
206 assert_eq!(logo.size, Size::Small);
207 }
208
209 #[test]
210 #[rustfmt::skip]
211 fn render_tiny() {
212 let mut buf = Buffer::empty(Rect::new(0, 0, 15, 2));
213 RatatuiLogo::tiny().render(buf.area, &mut buf);
214 assert_eq!(
215 buf,
216 Buffer::with_lines([
217 "▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌",
218 "▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌",
219 ])
220 );
221 }
222
223 #[test]
224 #[rustfmt::skip]
225 fn render_small() {
226 let mut buf = Buffer::empty(Rect::new(0, 0, 27, 2));
227 RatatuiLogo::small().render(buf.area, &mut buf);
228 assert_eq!(
229 buf,
230 Buffer::with_lines([
231 "█▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █",
232 "█▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █",
233 ])
234 );
235 }
236}