Skip to content

Commit

Permalink
Create Widgets showcase
Browse files Browse the repository at this point in the history
  • Loading branch information
joshka committed Dec 10, 2023
1 parent 2d9dbc7 commit 0f50eb0
Show file tree
Hide file tree
Showing 18 changed files with 406 additions and 4 deletions.
56 changes: 56 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,13 @@ export default defineConfig({
{ label: "v0.21", link: "/highlights/v021/" },
],
},
{ label: "Showcase", link: "/showcase/" },
{
label: "Showcase", collapsed: true, items: [
{ label: "Showcase", link: "/showcase/" },
{ label: "Apps", link: "/showcase/apps/" },
{ label: "Widgets", link: "/showcase/widgets/" },
],
},
{ label: "References", link: "/references/" },
{
label: "Developer Guide",
Expand Down
21 changes: 21 additions & 0 deletions code/widget-showcase/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "widget-showcase"
version.workspace = true
authors.workspace = true
description.workspace = true
documentation.workspace = true
repository.workspace = true
keywords.workspace = true
license.workspace = true
edition.workspace = true
rust-version.workspace = true
publish.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.4.11", features = ["derive"] }
color-eyre = "0.6.2"
crossterm = "0.27.0"
ratatui = { version = "0.24.0", features = ["all-widgets"] }
time = "0.3.30"
3 changes: 3 additions & 0 deletions code/widget-showcase/bar_chart.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions code/widget-showcase/bar_chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions code/widget-showcase/bar_chart.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This requires vhs installed from source for the updated theme and screenshot command
# go install github.com/charmbracelet/vhs@main
Output "bar_chart.gif"
Set Theme "Aardvark Blue"
Set Width 800
Set Height 300
Type "cargo run -- -w bar-chart" Enter
Sleep 2s
Screenshot "bar_chart.png"
Sleep 1s
3 changes: 3 additions & 0 deletions code/widget-showcase/block.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions code/widget-showcase/block.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions code/widget-showcase/block.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This requires vhs installed from source for the updated theme and screenshot command
# go install github.com/charmbracelet/vhs@main
Output "block.gif"
Set Theme "Aardvark Blue"
Set Width 800
Set Height 300
Type "cargo run -- -w block" Enter
Sleep 2s
Screenshot "block.png"
Sleep 1s
3 changes: 3 additions & 0 deletions code/widget-showcase/calendar.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions code/widget-showcase/calendar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions code/widget-showcase/calendar.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This requires vhs installed from source for the updated theme and screenshot command
# go install github.com/charmbracelet/vhs@main
Output "calendar.gif"
Set Theme "Aardvark Blue"
Set Width 800
Set Height 300
Type "cargo run -- -w calendar" Enter
Sleep 2s
Screenshot "calendar.png"
Sleep 1s
196 changes: 196 additions & 0 deletions code/widget-showcase/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
use std::{panic, time::Duration};

use clap::{Parser, ValueEnum};
use color_eyre::{
config::HookBuilder,
eyre::{self, WrapErr},
};
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
use ratatui::{
prelude::*,
widgets::{
block::Title,
calendar::{CalendarEventStore, Monthly},
*,
},
};
use time::Date;
mod tui;

#[derive(Debug, Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
/// The widget to display.
#[arg(short, long)]
widget: Widget,
}

#[derive(Debug, Clone, Copy, ValueEnum)]
enum Widget {
Block,
BarChart,
Calendar,
}

fn main() -> color_eyre::Result<()> {
install_hooks()?;
let args = Args::parse();
let mut terminal = tui::init()?;
App::default().run(&mut terminal, args.widget)?;
tui::restore()?;
Ok(())
}

/// This replaces the standard color_eyre panic and error hooks with hooks that
/// restore the terminal before printing the panic or error.
pub fn install_hooks() -> color_eyre::Result<()> {
let (panic_hook, eyre_hook) = HookBuilder::default().into_hooks();

// convert from a color_eyre PanicHook to a standard panic hook
let panic_hook = panic_hook.into_panic_hook();
panic::set_hook(Box::new(move |panic_info| {
tui::restore().unwrap();
panic_hook(panic_info);
}));

// convert from a color_eyre EyreHook to a eyre ErrorHook
let eyre_hook = eyre_hook.into_eyre_hook();
eyre::set_hook(Box::new(
move |error: &(dyn std::error::Error + 'static)| {
tui::restore().unwrap();
eyre_hook(error)
},
))?;

Ok(())
}

#[derive(Debug, Default)]
pub struct App {
running_state: RunningState,
}

#[derive(Debug, Default, PartialEq, Eq)]
enum RunningState {
#[default]
Running,
Finished,
}
impl App {
fn run(
&mut self,
terminal: &mut Terminal<impl Backend>,
widget: Widget,
) -> color_eyre::Result<()> {
while self.running_state != RunningState::Finished {
terminal.draw(|frame| self.render_frame(frame, widget))?;
self.update().wrap_err("update failed")?;
}
Ok(())
}
fn render_frame(&self, frame: &mut Frame, widget: Widget) {
match widget {
Widget::Block => render_block(frame),
Widget::BarChart => render_bar_chart(frame),
Widget::Calendar => render_calendar(frame),
}
}

fn update(&mut self) -> color_eyre::Result<()> {
// quit if a timeout occurs
if !event::poll(Duration::from_secs(3))? {
self.running_state = RunningState::Finished;
}
match event::read()? {
Event::Key(KeyEvent {
code,
kind: KeyEventKind::Press,
..
}) => match code {
KeyCode::Char('q') | KeyCode::Char('Q') => {
self.running_state = RunningState::Finished;
}
_ => {}
},
_ => {}
}
Ok(())
}
}

fn render_block(frame: &mut Frame) {
// intentionally mismatched border types to show how they look
let border_set = symbols::border::Set {
top_left: symbols::line::ROUNDED.top_left,
top_right: symbols::line::THICK.top_right,
bottom_left: symbols::line::ROUNDED.bottom_left,
bottom_right: symbols::border::THICK.bottom_right,
vertical_left: symbols::line::ROUNDED.vertical,
vertical_right: symbols::line::THICK.vertical,
horizontal_top: symbols::line::NORMAL.horizontal,
horizontal_bottom: symbols::line::DOUBLE.horizontal,
};
let block = Block::default()
.title("Left Title".yellow())
.title(Title::from("Center title".blue()).alignment(Alignment::Center))
.title(Title::from("Right Title".green()).alignment(Alignment::Right))
.title(
Title::from("Bottom Center title".blue())
.alignment(Alignment::Center)
.position(block::Position::Bottom),
)
.borders(Borders::ALL)
.border_set(border_set)
.border_style(Style::default().fg(Color::Red));
frame.render_widget(
Paragraph::new("A Block widget that wraps other widgets.".italic())
.block(block)
.alignment(Alignment::Center)
.wrap(Wrap { trim: true }),
frame.size(),
);
}

fn title_block<'a>(title: &'a str) -> Block<'a> {
Block::default()
.title(Title::from(title).alignment(Alignment::Center))
.borders(Borders::ALL)
.border_set(symbols::border::THICK)
.border_style(Style::new().dark_gray())
}

fn render_bar_chart(frame: &mut Frame) {
let barchart = BarChart::default()
.bar_width(3)
.bar_gap(1)
.data(&[
("B1", 2),
("B2", 5),
("B3", 7),
("B4", 9),
("B5", 12),
("B6", 8),
("B7", 5),
("B8", 2),
("B9", 7),
("B10", 9),
("B11", 12),
("B12", 8),
])
.block(title_block("Bar Chart"));
frame.render_widget(barchart, frame.size());
}

fn render_calendar(frame: &mut Frame) {
let default_style = Style::default()
.add_modifier(Modifier::BOLD)
.bg(Color::Rgb(50, 50, 50));
let events = CalendarEventStore::default();
let calendar = Monthly::new(
Date::from_calendar_date(2023, time::Month::January, 1).unwrap(),
events,
)
.show_month_header(Style::default())
.default_style(default_style);
frame.render_widget(calendar, frame.size());
}
Loading

0 comments on commit 0f50eb0

Please sign in to comment.