Skip to content

Commit

Permalink
style(tui): add generating animation
Browse files Browse the repository at this point in the history
  • Loading branch information
orhun committed Dec 28, 2024
1 parent 3d3a2dd commit 367d45a
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 84 deletions.
11 changes: 0 additions & 11 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion git-cliff-tui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
ratatui = { version = "0.29.0", features = ["unstable-widget-ref"] }
copypasta = "0.10.1"
throbber-widgets-tui = "0.8.0"
tui-markdown = "0.3.0"
ansi-to-tui = "7.0.0"
unicode-width = "0.2.0"
Expand Down
11 changes: 8 additions & 3 deletions git-cliff-tui/src/effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,20 @@ fn create_color_cycle(
///
/// An Effect that animates a border around the specified area using cycled
/// colors
pub fn create_border_effect(base_color: Color, area: Rect) -> Effect {
let color_cycle = create_color_cycle(base_color, 3);
pub fn create_border_effect(
base_color: Color,
speed: f32,
length: usize,
area: Rect,
) -> Effect {
let color_cycle = create_color_cycle(base_color, length);

let effect =
fx::effect_fn_buf(Instant::now(), u32::MAX, move |started_at, ctx, buf| {
let elapsed = started_at.elapsed().as_secs_f32();

// speed n cells/s
let idx = (elapsed * 30.0) as usize;
let idx = (elapsed * speed) as usize;

let area = ctx.area;

Expand Down
4 changes: 4 additions & 0 deletions git-cliff-tui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ fn main() -> Result<()> {
if let Ok(event) = receiver.try_recv() {
match event {
Event::Generate => {
state.is_generating = true;
state.border_effect = None;
state.generate_changelog()?;
}
Event::UpdateChangelog(contents) => {
state.is_generating = false;
state.border_effect = None;
state.configs = contents;
}
Event::Quit => break,
Expand Down
31 changes: 10 additions & 21 deletions git-cliff-tui/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::{
thread,
};
use tachyonfx::Effect;
use throbber_widgets_tui::ThrobberState;

use crate::event::Event;
use crate::logo::Logo;
Expand All @@ -26,25 +25,23 @@ pub struct Config {
/// Application state.
pub struct State {
/// git-cliff arguments.
pub args: Args,
pub args: Args,
/// Built-in configuration files.
pub configs: Vec<Config>,
pub configs: Vec<Config>,
/// The state of the list.
pub list_state: ListState,
pub list_state: ListState,
/// Event sender.
pub sender: mpsc::Sender<Event>,
pub sender: mpsc::Sender<Event>,
/// Scroll index.
pub scroll_index: usize,
pub scroll_index: usize,
/// Clipboard context.
pub clipboard: Option<ClipboardContext>,
/// Throbber state.
pub throbber_state: ThrobberState,
pub clipboard: Option<ClipboardContext>,
/// Is generating?
pub is_generating: bool,
pub is_generating: bool,
/// Logo widget.
pub logo: Logo,
pub logo: Logo,
/// Border effect.
pub border_effect: Option<Effect>,
pub border_effect: Option<Effect>,
}

impl State {
Expand All @@ -65,15 +62,14 @@ impl State {
},
sender,
scroll_index: 0,
throbber_state: ThrobberState::default(),
clipboard: match ClipboardContext::new() {
Ok(ctx) => Some(ctx),
Err(e) => {
eprintln!("Failed to initialize clipboard: {e}");
None
}
},
is_generating: false,
is_generating: true,
logo: Logo::default(),
args,
border_effect: None,
Expand Down Expand Up @@ -113,11 +109,4 @@ impl State {

Ok(())
}

/// Handles the tick event of the terminal.
pub fn tick(&mut self) {
if self.is_generating {
self.throbber_state.calc_next();
}
}
}
65 changes: 17 additions & 48 deletions git-cliff-tui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use ratatui::{
},
style::{
Color,
Modifier,
Style,
Stylize,
},
Expand Down Expand Up @@ -111,26 +110,19 @@ fn render_changelog(state: &mut State, frame: &mut Frame, area: Rect) {
.unwrap_or_default();
frame.render_widget(
Block::bordered()
.title_top("|Changelog|".yellow().into_left_aligned_line())
.title_top(
if state.is_generating {
"|Generating|"
} else {
"|Changelog|"
}
.yellow()
.into_left_aligned_line(),
)
.title_bottom(
Line::from(if state.is_generating {
Line::from(if !contents.is_empty() {
vec![
"|".fg(Color::Rgb(100, 100, 100)),
"> Generating...".white(),
"|".fg(Color::Rgb(100, 100, 100)),
]
} else if !contents.is_empty() {
vec![
"|".fg(Color::Rgb(100, 100, 100)),
state
.list_state
.selected()
.map(|i| state.configs[i].name.clone())
.unwrap_or_default()
.white()
.italic(),
"|".fg(Color::Rgb(100, 100, 100)),
" |".fg(Color::Rgb(100, 100, 100)),
"c".yellow().bold(),
"opy".white(),
"|".fg(Color::Rgb(100, 100, 100)),
Expand All @@ -152,13 +144,9 @@ fn render_changelog(state: &mut State, frame: &mut Frame, area: Rect) {
"|".fg(Color::Rgb(100, 100, 100)),
]
} else {
vec![
"|".fg(Color::Rgb(100, 100, 100)),
"Select config to start".white(),
"|".fg(Color::Rgb(100, 100, 100)),
]
vec![]
})
.left_aligned(),
.right_aligned(),
)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Rgb(100, 100, 100))),
Expand Down Expand Up @@ -189,35 +177,16 @@ fn render_changelog(state: &mut State, frame: &mut Frame, area: Rect) {
&mut ScrollbarState::new(contents.len()).position(state.scroll_index),
);

if state.is_generating {
let throbber_area = Rect::new(
area.left().saturating_add(2),
area.bottom().saturating_sub(1),
1,
1,
);
frame.render_stateful_widget(
throbber_widgets_tui::Throbber::default()
.style(Style::default().fg(Color::Yellow))
.throbber_style(
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
)
.throbber_set(throbber_widgets_tui::BLACK_CIRCLE)
.use_type(throbber_widgets_tui::WhichUse::Spin),
throbber_area,
&mut state.throbber_state,
);
}

match &mut state.border_effect {
Some(effect) => {
frame.render_effect(effect, area, Duration::from_millis(100));
}
None => {
state.border_effect =
Some(effect::create_border_effect(Color::Gray, area));
state.border_effect = Some(if state.is_generating {
effect::create_border_effect(Color::Rgb(205, 100, 42), 60., 1, area)
} else {
effect::create_border_effect(Color::Gray, 30., 3, area)
});
}
}
}

0 comments on commit 367d45a

Please sign in to comment.