Skip to content

Commit

Permalink
docs(examples): Add examples readme with gifs (#303)
Browse files Browse the repository at this point in the history
This commit adds a readme to the examples directory with gifs of each
example. This should make it easier to see what each example does
without having to run it.

I modified the examples to fit better in the gifs. Mostly this was just
removing the margins, but for the block example I cleaned up the code a
bit to make it more readable and changed it so the background bug is not
triggered.

For the table example, the combination of Min, Length, and Percent
constraints was causing the table to panic when the terminal was too
small. I changed the example to use the Max constraint instead of the
Length constraint.

The layout example now shows information about how the layout is
constrained on each block (which is now a paragraph with a block).
  • Loading branch information
joshka committed Jul 24, 2023
1 parent 60a4131 commit add578a
Show file tree
Hide file tree
Showing 29 changed files with 546 additions and 75 deletions.
209 changes: 209 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# Examples

These gifs were created using [Charm VHS](https://github.com/charmbracelet/vhs).

VHS has a problem rendering some background color transitions, which shows up in several examples
below. See <https://github.com/charmbracelet/vhs/issues/344> for more info. These problems don't
occur in a terminal.

## Barchart ([barchart.rs](./barchart.rs)

```shell
cargo run --example=barchart --features=crossterm
```

![Barchart][barchart.gif]

## Block ([block.rs](./block.rs))

```shell
cargo run --example=block --features=crossterm
```

![Block][block.gif]

## Calendar ([calendar.rs](./calendar.rs))

```shell
cargo run --example=calendar --features=crossterm widget-calendar
```

![Calendar][calendar.gif]

## Canvas ([canvas.rs](./canvas.rs))

```shell
cargo run --example=canvas --features=crossterm
```

![Canvas][canvas.gif]

## Chart ([chart.rs](./chart.rs))

```shell
cargo run --example=chart --features=crossterm
```

![Chart][chart.gif]

## Custom Widget ([custom_widget.rs](./custom_widget.rs))

```shell
cargo run --example=custom_widget --features=crossterm
```

This is not a particularly exciting example visually, but it demonstrates how to implement your own widget.

![Custom Widget][custom_widget.gif]

## Gauge ([gauge.rs](./gauge.rs))

Please note: the background renders poorly when we generate this example using VHS.
This problem doesn't generally happen during normal rendering in a terminal.
See <https://github.com/charmbracelet/vhs/issues/344> for more details

```shell
cargo run --example=gauge --features=crossterm
```

![Gauge][gauge.gif]

## Hello World ([hello_world.rs](./hello_world.rs))

```shell
cargo run --example=hello_world --features=crossterm
```

This is a pretty boring example, but it contains some good comments of documentation on some of the
standard approaches to writing tui apps.

![Hello World][hello_world.gif]

## Inline ([inline.rs](./inline.rs))

```shell
cargo run --example=inline --features=crossterm
```

![Inline][inline.gif]

## Layout ([layout.rs](./layout.rs))

```shell
cargo run --example=layout --features=crossterm
```

![Layout][layout.gif]

## List ([list.rs](./list.rs))

```shell
cargo run --example=list --features=crossterm
```

![List][list.gif]

## Panic ([panic.rs](./panic.rs))

```shell
cargo run --example=panic --features=crossterm
```

![Panic][panic.gif]

## Paragraph ([paragraph.rs](./paragraph.rs))

```shell
cargo run --example=paragraph --features=crossterm
```

![Paragraph][paragraph.gif]

## Popup ([popup.rs](./popup.rs))

```shell
cargo run --example=popup --features=crossterm
```

Please note: the background renders poorly when we generate this example using VHS.
This problem doesn't generally happen during normal rendering in a terminal.
See <https://github.com/charmbracelet/vhs/issues/344> for more details

![Popup][popup.gif]

## Scrollbar ([scrollbar.rs](./scrollbar.rs))

```shell
cargo run --example=scrollbar --features=crossterm
```

![Scrollbar][scrollbar.gif]

## Sparkline ([sparkline.rs](./sparkline.rs))

```shell
cargo run --example=sparkline --features=crossterm
```

![Sparkline][sparkline.gif]

## Table ([table.rs](./table.rs))

```shell
cargo run --example=table --features=crossterm
```

![Table][table.gif]

## Tabs ([tabs.rs](./tabs.rs))

```shell
cargo run --example=tabs --features=crossterm
```

![Tabs][tabs.gif]

## User Input ([user_input.rs](./user_input.rs))

```shell
cargo run --example=user_input --features=crossterm
```

![User Input][user_input.gif]

<!--
links to images to make it easier to update in bulk
These are generated with `vhs publish examples/xxx.gif`
To update these examples in bulk:
```shell
# build to ensure that running the examples doesn't have to wait so long
cargo build --examples --features=crossterm,all-widgets
for i in examples/*.tape
do
echo -n "[${i:s:examples/:::s:.tape:.gif:}]: "
vhs $i --publish --quiet
# may need to adjust this depending on if you see rate limiting from VHS
sleep 1
done
```
-->
[barchart.gif]: https://vhs.charm.sh/vhs-6ioxdeRBVkVpyXcjIEVaJU.gif
[block.gif]: https://vhs.charm.sh/vhs-1sEo9vVkHRwFtu95MOXrTj.gif
[calendar.gif]: https://vhs.charm.sh/vhs-1dBcpMSSP80WkBgm4lBhNo.gif
[canvas.gif]: https://vhs.charm.sh/vhs-4zeWEPF6bLEFSHuJrvaHlN.gif
[chart.gif]: https://vhs.charm.sh/vhs-zRzsE2AwRixQhcWMTAeF1.gif
[custom_widget.gif]: https://vhs.charm.sh/vhs-32mW1TpkrovTcm79QXmBSu.gif
[gauge.gif]: https://vhs.charm.sh/vhs-2rvSeP5r4lRkGTzNCKpm9a.gif
[hello_world.gif]: https://vhs.charm.sh/vhs-3CKUwxFuQi8oKQMS5zkPfQ.gif
[inline.gif]: https://vhs.charm.sh/vhs-miRl1mosKFoJV7LjjvF4T.gif
[layout.gif]: https://vhs.charm.sh/vhs-5R8O3LQGQ5pQVWwlPVrdbQ.gif
[list.gif]: https://vhs.charm.sh/vhs-4goo9reeUM9r0nYb54R7SP.gif
[panic.gif]: https://vhs.charm.sh/vhs-HrvKCHV4yeN69fb1EadTH.gif
[paragraph.gif]: https://vhs.charm.sh/vhs-2qIPDi79DUmtmeNDEeHVEF.gif
[popup.gif]: https://vhs.charm.sh/vhs-2QnC682AUeNYNXcjNlKTyp.gif
[scrollbar.gif]: https://vhs.charm.sh/vhs-2p13MMFreW7Gwt1xIonIWu.gif
[sparkline.gif]: https://vhs.charm.sh/vhs-4t59Vxw5Za33Rtvt9QrftA.gif
[table.gif]: https://vhs.charm.sh/vhs-6IrGHgT385DqA6xnwGF9oD.gif
[tabs.gif]: https://vhs.charm.sh/vhs-61WkbfhyDk0kbkjncErdHT.gif
[user_input.gif]: https://vhs.charm.sh/vhs-4fxUgkpEWcVyBRXuyYKODY.gif
11 changes: 11 additions & 0 deletions examples/barchart.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is a vhs script. See https://github.com/charmbracelet/vhs for more info.
# To run this script, install vhs and run `vhs ./examples/barchart.tape`
Output "target/barchart.gif"
Set Width 1200
Set Height 800
Hide
Type "cargo run --example=barchart"
Enter
Sleep 1s
Show
Sleep 5s
114 changes: 58 additions & 56 deletions examples/block.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{error::Error, io};
use std::{error::Error, io, time::Duration};

use crossterm::{
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
Expand All @@ -25,6 +25,7 @@ fn main() -> Result<(), Box<dyn Error>> {
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.clear()?;
terminal.show_cursor()?;

if let Err(err) = res {
Expand All @@ -38,9 +39,11 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {
loop {
terminal.draw(ui)?;

if let Event::Key(key) = event::read()? {
if let KeyCode::Char('q') = key.code {
return Ok(());
if event::poll(Duration::from_millis(250))? {
if let Event::Key(key) = event::read()? {
if let KeyCode::Char('q') = key.code {
return Ok(());
}
}
}
}
Expand All @@ -49,73 +52,72 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {
fn ui<B: Backend>(f: &mut Frame<B>) {
// Wrapping block for a group
// Just draw the block and the group on the same area and build the group
// with at least a margin of 1
let size = f.size();

// Surrounding block
let block = Block::default()
let outer = f.size();
let outer_block = Block::default()
.borders(Borders::ALL)
.title(block::Title::from("Main block with round corners").alignment(Alignment::Center))
.border_type(BorderType::Rounded);
f.render_widget(block, size);

let chunks = Layout::default()
let inner = outer_block.inner(outer);
let [top, bottom] = *Layout::default()
.direction(Direction::Vertical)
.margin(4)
.margin(1)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(f.size());

// Top two inner blocks
let top_chunks = Layout::default()
.split(inner)
else {
return;
};
let [top_left, top_right] = *Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(chunks[0]);

// Top left inner block with green background
let block = Block::default()
.title(vec!["With".yellow(), " background".into()])
.on_green();
f.render_widget(block, top_chunks[0]);

// Top right inner block with styled title aligned to the right
let block = Block::default().title(
block::Title::from("Styled title".white().on_red().bold()).alignment(Alignment::Right),
);
f.render_widget(block, top_chunks[1]);

// Bottom two inner blocks
let bottom_chunks = Layout::default()
.split(top)
else {
return;
};
let [bottom_left, bottom_right] = *Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(chunks[1]);

// Bottom left block with all default borders
let block = Block::default()
.title("With borders")
.borders(Borders::ALL)
.padding(Padding {
left: 4,
right: 4,
top: 2,
bottom: 2,
});

let text = Paragraph::new("text inside padded block").block(block);
f.render_widget(text, bottom_chunks[0]);

// Bottom right block with styled left and right border
let block = Block::default()
.split(bottom)
else {
return;
};

let top_left_block = Block::default()
.title("With Green Background")
.borders(Borders::all())
.on_green();
let top_right_block = Block::default()
.title(
block::Title::from("With styled title".white().on_red().bold())
.alignment(Alignment::Right),
)
.borders(Borders::ALL);
let bottom_left_block = Paragraph::new("Text inside padded block").block(
Block::default()
.title("With borders")
.borders(Borders::ALL)
.padding(Padding {
left: 4,
right: 4,
top: 2,
bottom: 2,
}),
);
let bottom_right_block = Block::default()
.title("With styled borders and doubled borders")
.border_style(Style::default().fg(Color::Cyan))
.borders(Borders::LEFT | Borders::RIGHT)
.border_type(BorderType::Double)
.padding(Padding::uniform(1));

let inner_block = Block::default()
let bottom_inner_block = Block::default()
.title("Block inside padded block")
.borders(Borders::ALL);

let inner_area = block.inner(bottom_chunks[1]);
f.render_widget(block, bottom_chunks[1]);
f.render_widget(inner_block, inner_area);
f.render_widget(outer_block, outer);
f.render_widget(Clear, top_left);
f.render_widget(top_left_block, top_left);
f.render_widget(top_right_block, top_right);
f.render_widget(bottom_left_block, bottom_left);
let bottom_right_inner = bottom_right_block.inner(bottom_right);
f.render_widget(bottom_right_block, bottom_right);
f.render_widget(bottom_inner_block, bottom_right_inner);
}
11 changes: 11 additions & 0 deletions examples/block.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is a vhs script. See https://github.com/charmbracelet/vhs for more info.
# To run this script, install vhs and run `vhs ./examples/block.tape`
Output "target/block.gif"
Set Width 1200
Set Height 800
Hide
Type "cargo run --example=block"
Enter
Sleep 1s
Show
Sleep 5s
11 changes: 11 additions & 0 deletions examples/calendar.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is a vhs script. See https://github.com/charmbracelet/vhs for more info.
# To run this script, install vhs and run `vhs ./examples/calendar.tape`
Output "target/calendar.gif"
Set Width 1200
Set Height 800
Hide
Type "cargo run --example=calendar --features=crossterm,widget-calendar"
Enter
Sleep 3s
Show
Sleep 5s

0 comments on commit add578a

Please sign in to comment.