mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-21 20:23:11 +00:00
feat(logo): Add a Ratatui logo widget
This is a simple logo widget that can be used to render the Ratatui logo in the terminal. It is used in the `examples/ratatui-logo.rs` example, and may be used in your applications' help or about screens. ```rust use ratatui::{Frame, widgets::RatatuiLogo}; fn draw(frame: &mut Frame) { frame.render_widget(RatatuiLogo::tiny(), frame.area()); } ```
This commit is contained in:
parent
baf047f556
commit
2805dddf05
5 changed files with 273 additions and 47 deletions
|
@ -27,6 +27,7 @@ cassowary = "0.3"
|
|||
compact_str = "0.8.0"
|
||||
crossterm = { version = "0.28.1", optional = true }
|
||||
document-features = { version = "0.2.7", optional = true }
|
||||
indoc = "2"
|
||||
instability = "0.3.1"
|
||||
itertools = "0.13"
|
||||
lru = "0.12.0"
|
||||
|
|
|
@ -13,57 +13,42 @@
|
|||
//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples
|
||||
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
||||
|
||||
use std::{
|
||||
io::{self},
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
use std::env::args;
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, Event};
|
||||
use ratatui::{
|
||||
layout::{Constraint, Layout},
|
||||
widgets::{RatatuiLogo, RatatuiLogoSize},
|
||||
DefaultTerminal, TerminalOptions, Viewport,
|
||||
};
|
||||
|
||||
use indoc::indoc;
|
||||
use itertools::izip;
|
||||
use ratatui::{widgets::Paragraph, TerminalOptions, Viewport};
|
||||
|
||||
/// A fun example of using half block characters to draw a logo
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn logo() -> String {
|
||||
let r = indoc! {"
|
||||
▄▄▄
|
||||
█▄▄▀
|
||||
█ █
|
||||
"};
|
||||
let a = indoc! {"
|
||||
▄▄
|
||||
█▄▄█
|
||||
█ █
|
||||
"};
|
||||
let t = indoc! {"
|
||||
▄▄▄
|
||||
█
|
||||
█
|
||||
"};
|
||||
let u = indoc! {"
|
||||
▄ ▄
|
||||
█ █
|
||||
▀▄▄▀
|
||||
"};
|
||||
let i = indoc! {"
|
||||
▄
|
||||
█
|
||||
█
|
||||
"};
|
||||
izip!(r.lines(), a.lines(), t.lines(), u.lines(), i.lines())
|
||||
.map(|(r, a, t, u, i)| format!("{r:5}{a:5}{t:4}{a:5}{t:4}{u:5}{i:5}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let mut terminal = ratatui::init_with_options(TerminalOptions {
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init_with_options(TerminalOptions {
|
||||
viewport: Viewport::Inline(3),
|
||||
});
|
||||
terminal.draw(|frame| frame.render_widget(Paragraph::new(logo()), frame.area()))?;
|
||||
sleep(Duration::from_secs(5));
|
||||
let size = match args().nth(1).as_deref() {
|
||||
Some("small") => RatatuiLogoSize::Small,
|
||||
Some("tiny") => RatatuiLogoSize::Tiny,
|
||||
_ => RatatuiLogoSize::default(),
|
||||
};
|
||||
let result = run(terminal, size);
|
||||
ratatui::restore();
|
||||
println!();
|
||||
Ok(())
|
||||
result
|
||||
}
|
||||
|
||||
fn run(mut terminal: DefaultTerminal, size: RatatuiLogoSize) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|frame| {
|
||||
use Constraint::{Fill, Length};
|
||||
let [top, bottom] = Layout::vertical([Length(1), Fill(1)]).areas(frame.area());
|
||||
frame.render_widget("Powered by", top);
|
||||
frame.render_widget(RatatuiLogo::new(size), bottom);
|
||||
})?;
|
||||
if matches!(event::read()?, Event::Key(_)) {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,3 +10,5 @@ Enter
|
|||
Sleep 2s
|
||||
Show
|
||||
Sleep 2s
|
||||
Hide
|
||||
Escape
|
||||
|
|
|
@ -31,6 +31,7 @@ mod chart;
|
|||
mod clear;
|
||||
mod gauge;
|
||||
mod list;
|
||||
mod logo;
|
||||
mod paragraph;
|
||||
mod reflow;
|
||||
mod scrollbar;
|
||||
|
@ -46,6 +47,7 @@ pub use self::{
|
|||
clear::Clear,
|
||||
gauge::{Gauge, LineGauge},
|
||||
list::{List, ListDirection, ListItem, ListState},
|
||||
logo::{RatatuiLogo, Size as RatatuiLogoSize},
|
||||
paragraph::{Paragraph, Wrap},
|
||||
scrollbar::{ScrollDirection, Scrollbar, ScrollbarOrientation, ScrollbarState},
|
||||
sparkline::{RenderDirection, Sparkline},
|
||||
|
|
236
src/widgets/logo.rs
Normal file
236
src/widgets/logo.rs
Normal file
|
@ -0,0 +1,236 @@
|
|||
use indoc::indoc;
|
||||
|
||||
use crate::{buffer::Buffer, layout::Rect, text::Text, widgets::Widget};
|
||||
|
||||
/// A widget that renders the Ratatui logo
|
||||
///
|
||||
/// The Ratatui logo takes up two lines of text and comes in two sizes: `Tiny` and `Small`. This may
|
||||
/// be used in an application's help or about screen to show that it is powered by Ratatui.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The [Ratatui-logo] example demonstrates how to use the `RatatuiLogo` widget. This can be run by
|
||||
/// cloning the Ratatui repository and then running the following command with an optional size
|
||||
/// argument:
|
||||
///
|
||||
/// ```shell
|
||||
/// cargo run --example ratatui-logo [size]
|
||||
/// ```
|
||||
///
|
||||
/// [Ratatui-logo]: https://github.com/ratatui/ratatui/blob/main/examples/ratatui-logo.rs
|
||||
///
|
||||
/// ## Tiny (default, 2x15 characters)
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::RatatuiLogo;
|
||||
///
|
||||
/// # fn draw(frame: &mut ratatui::Frame) {
|
||||
/// frame.render_widget(RatatuiLogo::tiny(), frame.area());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Renders:
|
||||
///
|
||||
/// ```text
|
||||
/// ▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌
|
||||
/// ▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌
|
||||
/// ```
|
||||
///
|
||||
/// ## Small (2x27 characters)
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::RatatuiLogo;
|
||||
///
|
||||
/// # fn draw(frame: &mut ratatui::Frame) {
|
||||
/// frame.render_widget(RatatuiLogo::small(), frame.area());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Renders:
|
||||
///
|
||||
/// ```text
|
||||
/// █▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █
|
||||
/// █▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct RatatuiLogo {
|
||||
size: Size,
|
||||
}
|
||||
|
||||
/// The size of the logo
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Size {
|
||||
/// A tiny logo
|
||||
///
|
||||
/// The default size of the logo (2x15 characters)
|
||||
///
|
||||
/// ```text
|
||||
/// ▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌
|
||||
/// ▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌
|
||||
/// ```
|
||||
#[default]
|
||||
Tiny,
|
||||
/// A small logo
|
||||
///
|
||||
/// A slightly larger version of the logo (2x27 characters)
|
||||
///
|
||||
/// ```text
|
||||
/// █▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █
|
||||
/// █▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █
|
||||
/// ```
|
||||
Small,
|
||||
}
|
||||
|
||||
impl RatatuiLogo {
|
||||
/// Create a new Ratatui logo widget
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::{RatatuiLogo, RatatuiLogoSize};
|
||||
///
|
||||
/// let logo = RatatuiLogo::new(RatatuiLogoSize::Tiny);
|
||||
/// ```
|
||||
pub const fn new(size: Size) -> Self {
|
||||
Self { size }
|
||||
}
|
||||
|
||||
/// Set the size of the logo
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::{RatatuiLogo, RatatuiLogoSize};
|
||||
///
|
||||
/// let logo = RatatuiLogo::default().size(RatatuiLogoSize::Small);
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn size(self, size: Size) -> Self {
|
||||
let _ = self;
|
||||
Self { size }
|
||||
}
|
||||
|
||||
/// Create a new Ratatui logo widget with a tiny size
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::RatatuiLogo;
|
||||
///
|
||||
/// let logo = RatatuiLogo::tiny();
|
||||
/// ```
|
||||
pub const fn tiny() -> Self {
|
||||
Self::new(Size::Tiny)
|
||||
}
|
||||
|
||||
/// Create a new Ratatui logo widget with a small size
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::RatatuiLogo;
|
||||
///
|
||||
/// let logo = RatatuiLogo::small();
|
||||
/// ```
|
||||
pub const fn small() -> Self {
|
||||
Self::new(Size::Small)
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for RatatuiLogo {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let logo = self.size.as_str();
|
||||
Text::raw(logo).render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Size {
|
||||
const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Tiny => Self::tiny(),
|
||||
Self::Small => Self::small(),
|
||||
}
|
||||
}
|
||||
|
||||
const fn tiny() -> &'static str {
|
||||
indoc! {"
|
||||
▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌
|
||||
▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌
|
||||
"}
|
||||
}
|
||||
|
||||
const fn small() -> &'static str {
|
||||
indoc! {"
|
||||
█▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █
|
||||
█▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █
|
||||
"}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[rstest]
|
||||
#[case::tiny(Size::Tiny)]
|
||||
#[case::small(Size::Small)]
|
||||
fn new_size(#[case] size: Size) {
|
||||
let logo = RatatuiLogo::new(size);
|
||||
assert_eq!(logo.size, size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_logo_is_tiny() {
|
||||
let logo = RatatuiLogo::default();
|
||||
assert_eq!(logo.size, Size::Tiny);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_logo_size_to_small() {
|
||||
let logo = RatatuiLogo::default().size(Size::Small);
|
||||
assert_eq!(logo.size, Size::Small);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tiny_logo_constant() {
|
||||
let logo = RatatuiLogo::tiny();
|
||||
assert_eq!(logo.size, Size::Tiny);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn small_logo_constant() {
|
||||
let logo = RatatuiLogo::small();
|
||||
assert_eq!(logo.size, Size::Small);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn render_tiny() {
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 2));
|
||||
RatatuiLogo::tiny().render(buf.area, &mut buf);
|
||||
assert_eq!(
|
||||
buf,
|
||||
Buffer::with_lines([
|
||||
"▛▚▗▀▖▜▘▞▚▝▛▐ ▌▌",
|
||||
"▛▚▐▀▌▐ ▛▜ ▌▝▄▘▌",
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn render_small() {
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 27, 2));
|
||||
RatatuiLogo::small().render(buf.area, &mut buf);
|
||||
assert_eq!(
|
||||
buf,
|
||||
Buffer::with_lines([
|
||||
"█▀▀▄ ▄▀▀▄▝▜▛▘▄▀▀▄▝▜▛▘█ █ █",
|
||||
"█▀▀▄ █▀▀█ ▐▌ █▀▀█ ▐▌ ▀▄▄▀ █",
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue