Skip to content

Commit

Permalink
style(tui): add splash logo
Browse files Browse the repository at this point in the history
  • Loading branch information
orhun committed Dec 16, 2024
1 parent b5b6946 commit d0c2968
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 1 deletion.
104 changes: 104 additions & 0 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion git-cliff-tui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ license = "MIT"
edition = "2021"

[dependencies]
ratatui = "0.29.0"
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"
tachyonfx = "0.10.1"
lazy_static.workspace = true

[dependencies.git-cliff]
version = "2.5.0" # managed by release.sh
Expand Down
146 changes: 146 additions & 0 deletions git-cliff-tui/src/logo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::time::Instant;

use ansi_to_tui::IntoText;
use lazy_static::lazy_static;
use ratatui::{
buffer::Buffer,
layout::Rect,
style::{
Color,
Styled,
Stylize,
},
text::{
Line,
Text,
},
widgets::Widget,
};
use tachyonfx::{
fx,
Duration,
Effect,
EffectRenderer,
Interpolation,
Motion,
Shader,
};
use unicode_width::UnicodeWidthStr;

/// ANSI representation of the project logo.
#[rustfmt::skip]
const LOGO_ANSI: &str = "
\x1b[m
\x1b[49m \x1b[38;2;169;182;182;49m▄\x1b[38;2;178;186;189;49m▄\x1b[38;2;177;185;188;49m▄▄\x1b[38;2;178;185;191;49m▄▄\x1b[38;2;176;184;187;49m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;181;186;190;49m▄\x1b[38;2;182;187;191;49m▄\x1b[38;2;180;188;191;48;2;178;186;189m▄\x1b[38;2;180;188;191;48;2;179;186;190m▄\x1b[38;2;181;186;190;48;2;178;185;189m▄\x1b[38;2;179;187;190;48;2;180;186;189m▄\x1b[38;2;179;187;190;48;2;178;186;189m▄\x1b[38;2;179;187;190;48;2;180;186;190m▄\x1b[38;2;179;187;190;48;2;176;185;190m▄\x1b[38;2;179;186;192;48;2;178;186;191m▄\x1b[38;2;179;186;192;48;2;177;185;191m▄\x1b[48;2;178;186;189m \x1b[38;2;179;187;190;48;2;178;186;189m▄\x1b[38;2;178;186;189;48;2;177;185;188m▄\x1b[38;2;178;186;189;49m▄▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;185;190;194;49m▄\x1b[38;2;183;191;194;48;2;183;188;194m▄\x1b[38;2;184;191;194;48;2;183;188;194m▄\x1b[38;2;183;191;194;48;2;180;188;191m▄\x1b[38;2;183;191;194;48;2;181;189;192m▄\x1b[38;2;181;189;192;48;2;180;188;191m▄\x1b[38;2;183;191;194;48;2;182;187;191m▄\x1b[38;2;183;191;194;48;2;181;189;192m▄\x1b[38;2;184;190;194;48;2;180;188;191m▄\x1b[38;2;182;190;193;48;2;181;189;192m▄\x1b[38;2;183;191;194;48;2;180;188;191m▄\x1b[38;2;182;190;193;48;2;180;188;191m▄\x1b[38;2;182;190;193;48;2;181;189;192m▄\x1b[38;2;184;189;193;48;2;180;188;191m▄\x1b[38;2;183;188;192;48;2;180;188;191m▄\x1b[38;2;184;189;193;48;2;180;188;191m▄\x1b[38;2;184;189;193;48;2;180;186;192m▄\x1b[38;2;182;189;193;48;2;180;188;191m▄\x1b[38;2;184;189;193;48;2;180;188;191m▄\x1b[38;2;182;190;193;49m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;185;193;196;49m▄\x1b[48;2;184;192;195m \x1b[38;2;185;192;198;48;2;184;192;195m▄\x1b[38;2;186;193;199;48;2;184;192;195m▄\x1b[38;2;185;193;196;48;2;186;191;195m▄\x1b[38;2;185;193;196;48;2;184;192;195m▄\x1b[38;2;185;192;198;48;2;183;191;194m▄\x1b[38;2;184;191;197;48;2;186;191;195m▄\x1b[38;2;185;193;196;48;2;186;191;195m▄\x1b[38;2;188;193;197;48;2;184;192;195m▄\x1b[48;2;184;192;195m \x1b[38;2;185;192;196;48;2;184;192;195m▄\x1b[38;2;186;194;197;48;2;184;192;195m▄\x1b[38;2;185;193;196;48;2;184;192;195m▄\x1b[38;2;186;191;195;48;2;183;191;194m▄\x1b[38;2;185;193;196;48;2;183;191;194m▄\x1b[38;2;186;194;197;48;2;184;193;196m▄\x1b[38;2;187;192;196;48;2;183;191;194m▄\x1b[38;2;187;192;196;48;2;185;192;195m▄\x1b[38;2;186;191;197;48;2;182;190;193m▄\x1b[38;2;187;192;196;48;2;186;191;195m▄\x1b[38;2;186;191;196;48;2;184;189;193m▄\x1b[38;2;184;192;195;48;2;185;190;194m▄\x1b[38;2;186;191;195;49m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;189;197;200;49m▄\x1b[38;2;190;198;201;48;2;187;195;198m▄\x1b[38;2;190;198;201;48;2;187;195;197m▄\x1b[38;2;190;198;201;48;2;189;194;200m▄\x1b[38;2;192;197;201;48;2;187;194;200m▄\x1b[38;2;191;196;200;48;2;187;194;200m▄\x1b[38;2;189;197;200;48;2;187;195;198m▄\x1b[38;2;190;198;200;48;2;187;194;200m▄\x1b[38;2;190;198;201;48;2;187;194;200m▄\x1b[38;2;190;198;201;48;2;187;195;198m▄\x1b[38;2;192;197;201;48;2;189;194;198m▄\x1b[38;2;189;197;200;48;2;186;194;197m▄\x1b[38;2;191;196;200;48;2;187;195;198m▄\x1b[38;2;190;198;201;48;2;187;194;200m▄\x1b[38;2;190;198;201;48;2;187;195;198m▄▄\x1b[38;2;190;197;203;48;2;187;195;198m▄\x1b[38;2;190;198;201;48;2;187;194;200m▄\x1b[38;2;190;198;201;48;2;189;194;198m▄\x1b[38;2;191;197;200;48;2;189;194;198m▄\x1b[38;2;189;197;200;48;2;189;194;200m▄\x1b[38;2;188;195;201;48;2;188;193;199m▄\x1b[38;2;188;195;201;48;2;189;193;199m▄\x1b[38;2;189;194;198;48;2;185;193;196m▄▄\x1b[38;2;187;193;199;49m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;193;201;204;48;2;190;198;201m▄\x1b[38;2;193;200;206;48;2;191;199;202m▄\x1b[38;2;194;200;204;48;2;192;200;203m▄\x1b[38;2;193;200;206;48;2;192;200;203m▄\x1b[38;2;193;200;206;48;2;192;199;205m▄\x1b[38;2;193;200;206;48;2;192;200;203m▄\x1b[38;2;193;200;206;48;2;190;198;201m▄\x1b[38;2;193;201;204;48;2;192;200;203m▄\x1b[38;2;195;200;204;48;2;191;199;202m▄\x1b[38;2;193;200;204;48;2;191;198;204m▄\x1b[38;2;193;201;204;48;2;190;199;204m▄\x1b[38;2;193;201;204;48;2;191;199;202m▄\x1b[38;2;193;200;206;48;2;190;198;204m▄\x1b[38;2;195;200;204;48;2;190;197;203m▄\x1b[38;2;196;201;205;48;2;191;201;203m▄\x1b[38;2;195;200;204;48;2;191;198;204m▄\x1b[38;2;193;200;206;48;2;192;199;205m▄\x1b[38;2;195;200;204;48;2;190;197;203m▄\x1b[38;2;196;201;207;48;2;191;198;204m▄\x1b[38;2;194;200;204;48;2;192;199;204m▄\x1b[38;2;193;201;204;48;2;190;198;201m▄\x1b[38;2;194;202;205;48;2;190;197;203m▄\x1b[38;2;193;200;205;48;2;188;199;202m▄\x1b[38;2;190;200;202;48;2;189;196;202m▄\x1b[38;2;190;198;201;48;2;190;195;199m▄\x1b[38;2;190;198;201;48;2;189;194;198m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;195;203;206;48;2;194;203;207m▄\x1b[38;2;196;204;207;48;2;193;201;204m▄\x1b[38;2;196;204;207;48;2;194;202;207m▄\x1b[38;2;196;204;207;48;2;196;202;205m▄\x1b[38;2;195;202;208;48;2;194;201;207m▄\x1b[38;2;196;204;207;48;2;194;202;205m▄\x1b[38;2;194;202;205;48;2;194;201;206m▄\x1b[38;2;195;203;206;48;2;193;201;206m▄\x1b[38;2;195;203;206;48;2;194;202;205m▄\x1b[38;2;195;203;208;48;2;194;202;206m▄\x1b[38;2;251;137;72;48;2;195;200;204m▄\x1b[38;2;253;140;74;48;2;193;200;204m▄\x1b[38;2;222;193;185;48;2;194;202;205m▄\x1b[38;2;197;203;206;48;2;194;201;206m▄\x1b[38;2;196;204;207;48;2;194;202;205m▄\x1b[38;2;196;204;207;48;2;194;201;207m▄\x1b[38;2;196;204;207;48;2;196;202;206m▄\x1b[38;2;196;204;207;48;2;195;203;206m▄▄\x1b[38;2;196;204;207;48;2;196;202;206m▄\x1b[38;2;196;204;207;48;2;194;202;205m▄\x1b[38;2;198;203;207;48;2;196;201;207m▄\x1b[38;2;195;203;206;48;2;195;200;204m▄\x1b[38;2;195;203;206;48;2;196;201;205m▄\x1b[38;2;194;202;205;48;2;193;201;204m▄\x1b[38;2;194;199;203;48;2;192;200;203m▄\x1b[38;2;195;200;204;48;2;190;199;201m▄\x1b[38;2;191;201;202;48;2;194;206;206m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;197;202;207;48;2;195;203;206m▄\x1b[48;2;197;205;208m \x1b[38;2;197;205;208;48;2;196;204;207m▄\x1b[48;2;196;204;207m \x1b[38;2;197;205;208;48;2;198;203;207m▄\x1b[48;2;196;204;207m \x1b[38;2;196;202;208;48;2;196;204;207m▄\x1b[38;2;28;42;45;48;2;195;202;208m▄\x1b[38;2;246;139;75;48;2;175;110;76m▄\x1b[38;2;253;138;72;48;2;253;139;72m▄\x1b[38;2;253;138;71;48;2;254;139;72m▄\x1b[38;2;254;139;72;48;2;255;140;73m▄\x1b[38;2;255;139;72;48;2;230;152;93m▄\x1b[38;2;244;140;71;48;2;196;204;207m▄\x1b[38;2;196;202;209;48;2;196;203;209m▄\x1b[48;2;196;203;209m \x1b[48;2;196;204;207m \x1b[48;2;197;205;208m \x1b[38;2;197;205;208;48;2;196;204;207m▄\x1b[48;2;196;204;207m \x1b[38;2;197;205;208;48;2;196;204;207m▄▄\x1b[38;2;198;203;207;48;2;195;203;206m▄\x1b[38;2;196;201;205;48;2;195;200;204m▄\x1b[38;2;198;201;206;48;2;195;200;204m▄\x1b[48;2;192;200;203m \x1b[49m \x1b[m
\x1b[49m \x1b[49;38;2;196;205;207m▀\x1b[38;2;196;204;207;48;2;197;205;208m▄▄▄\x1b[38;2;195;203;209;48;2;196;204;207m▄\x1b[38;2;21;36;39;48;2;196;204;207m▄\x1b[38;2;27;45;47;48;2;207;214;222m▄\x1b[38;2;27;45;47;48;2;26;41;44m▄\x1b[38;2;25;43;45;48;2;26;41;44m▄\x1b[38;2;25;40;43;48;2;27;42;45m▄\x1b[38;2;21;43;41;48;2;25;40;43m▄\x1b[38;2;252;143;71;48;2;50;42;28m▄\x1b[38;2;189;122;71;48;2;249;141;72m▄\x1b[38;2;27;48;55;48;2;253;139;71m▄\x1b[38;2;25;45;46;48;2;248;144;75m▄\x1b[38;2;26;44;46;48;2;254;141;64m▄\x1b[38;2;27;42;45;48;2;166;182;184m▄\x1b[38;2;28;43;46;48;2;194;202;208m▄\x1b[38;2;27;43;42;48;2;192;206;209m▄\x1b[38;2;192;204;214;48;2;197;205;208m▄\x1b[38;2;199;204;208;48;2;197;204;208m▄\x1b[38;2;196;204;207;48;2;197;205;208m▄▄\x1b[38;2;197;205;208;48;2;196;204;207m▄▄\x1b[38;2;199;204;208;48;2;196;204;207m▄\x1b[38;2;199;204;208;48;2;197;200;205m▄\x1b[49;38;2;196;205;207m▀\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;195;203;205;48;2;196;204;207m▄\x1b[38;2;18;39;41;48;2;196;204;207m▄\x1b[38;2;27;50;53;48;2;196;204;207m▄\x1b[38;2;24;48;50;48;2;27;46;48m▄\x1b[38;2;27;48;51;48;2;27;47;48m▄\x1b[38;2;28;47;50;48;2;26;46;47m▄\x1b[38;2;22;48;50;48;2;25;45;46m▄\x1b[38;2;26;52;52;48;2;26;44;46m▄\x1b[38;2;27;51;53;48;2;25;47;48m▄\x1b[38;2;27;46;48;48;2;27;49;51m▄\x1b[38;2;24;44;45;48;2;28;49;52m▄\x1b[38;2;26;45;46;48;2;28;48;49m▄\x1b[38;2;26;43;45;48;2;26;46;47m▄\x1b[38;2;27;42;45;48;2;26;44;46m▄\x1b[38;2;28;43;46;48;2;27;42;45m▄\x1b[48;2;27;42;45m \x1b[38;2;27;41;42;48;2;28;43;46m▄\x1b[38;2;26;40;41;48;2;29;43;46m▄\x1b[38;2;27;41;43;48;2;26;41;43m▄\x1b[38;2;223;114;45;48;2;236;118;39m▄\x1b[38;2;227;114;48;48;2;198;203;209m▄\x1b[38;2;217;160;128;48;2;196;203;209m▄\x1b[38;2;194;205;215;48;2;198;205;210m▄\x1b[38;2;197;205;208;48;2;196;204;207m▄\x1b[38;2;197;204;209;48;2;197;205;208m▄\x1b[38;2;196;203;209;48;2;199;204;208m▄\x1b[49m \x1b[m
\x1b[49m \x1b[49;38;2;26;46;53m▀\x1b[48;2;26;54;55m \x1b[38;2;21;49;50;48;2;27;52;54m▄\x1b[38;2;22;55;54;48;2;28;52;54m▄\x1b[38;2;27;49;52;48;2;25;49;51m▄\x1b[38;2;27;47;50;48;2;27;53;54m▄\x1b[38;2;27;47;48;48;2;31;50;54m▄\x1b[38;2;24;44;45;48;2;27;46;50m▄\x1b[38;2;25;45;46;48;2;26;46;45m▄\x1b[38;2;29;47;49;48;2;27;45;47m▄\x1b[38;2;29;44;47;48;2;25;44;46m▄\x1b[38;2;30;45;48;48;2;28;43;46m▄\x1b[48;2;28;43;46m \x1b[38;2;28;42;45;48;2;26;41;44m▄\x1b[38;2;28;42;45;48;2;27;42;45m▄\x1b[38;2;28;42;43;48;2;28;42;45m▄\x1b[38;2;27;41;42;48;2;28;42;43m▄\x1b[38;2;26;40;41;48;2;28;42;43m▄\x1b[38;2;27;41;42;48;2;26;40;41m▄\x1b[38;2;204;102;44;48;2;209;103;40m▄\x1b[38;2;206;101;40;48;2;217;108;43m▄\x1b[38;2;213;106;42;48;2;222;113;46m▄\x1b[38;2;219;110;45;48;2;228;117;47m▄\x1b[38;2;225;113;47;48;2;202;200;201m▄\x1b[38;2;241;116;43;48;2;198;203;209m▄\x1b[49m \x1b[m
\x1b[49m \x1b[38;2;25;45;48;48;2;28;50;53m▄\x1b[38;2;27;47;48;48;2;30;48;52m▄\x1b[38;2;27;47;48;48;2;25;45;49m▄\x1b[38;2;27;42;45;48;2;28;47;51m▄\x1b[38;2;28;43;46;48;2;26;46;47m▄▄\x1b[48;2;27;42;45m \x1b[38;2;28;43;46;48;2;26;41;44m▄\x1b[48;2;27;42;45m \x1b[38;2;27;42;45;48;2;28;43;46m▄\x1b[38;2;28;42;44;48;2;27;42;45m▄\x1b[48;2;28;42;45m \x1b[38;2;27;41;42;48;2;26;40;41m▄\x1b[38;2;26;40;41;48;2;27;41;44m▄\x1b[48;2;27;41;42m \x1b[38;2;27;41;36;48;2;27;41;42m▄\x1b[38;2;190;98;38;48;2;25;39;39m▄\x1b[38;2;199;97;38;48;2;199;97;35m▄\x1b[38;2;199;97;39;48;2;203;99;38m▄\x1b[38;2;199;99;39;48;2;205;99;39m▄\x1b[38;2;203;98;40;48;2;210;102;40m▄\x1b[38;2;206;101;41;48;2;214;105;40m▄\x1b[49m \x1b[m
\x1b[49m \x1b[49;38;2;26;46;47m▀\x1b[38;2;26;42;45;48;2;28;43;46m▄\x1b[48;2;27;42;45m \x1b[38;2;27;42;45;48;2;28;43;46m▄\x1b[48;2;27;42;45m \x1b[38;2;28;42;45;48;2;27;42;45m▄\x1b[38;2;28;42;45;48;2;28;44;44m▄\x1b[38;2;27;41;42;48;2;27;41;44m▄\x1b[38;2;26;40;41;48;2;29;43;44m▄\x1b[38;2;26;40;41;48;2;27;41;42m▄\x1b[38;2;27;41;44;48;2;26;40;41m▄\x1b[38;2;78;46;24;48;2;27;41;42m▄\x1b[38;2;191;89;31;48;2;24;41;38m▄\x1b[38;2;191;92;35;48;2;192;93;35m▄\x1b[48;2;194;93;37m \x1b[38;2;193;92;36;48;2;196;96;38m▄\x1b[38;2;194;93;37;48;2;197;94;36m▄\x1b[38;2;197;95;37;48;2;199;96;38m▄\x1b[49;38;2;200;95;39m▀\x1b[49m \x1b[m
\x1b[49m \x1b[49;38;2;27;42;45m▀\x1b[49;38;2;28;42;45m▀\x1b[38;2;29;40;42;48;2;28;42;43m▄\x1b[38;2;28;39;41;48;2;28;42;43m▄\x1b[38;2;31;36;43;48;2;27;42;43m▄\x1b[38;2;75;47;26;48;2;28;40;42m▄\x1b[38;2;187;89;41;48;2;26;40;46m▄\x1b[38;2;190;91;36;48;2;58;33;24m▄\x1b[38;2;191;92;37;48;2;188;87;36m▄\x1b[38;2;190;91;36;48;2;190;90;38m▄\x1b[38;2;192;91;35;48;2;190;89;33m▄\x1b[38;2;191;90;34;48;2;191;91;35m▄\x1b[49;38;2;192;91;35m▀▀\x1b[49m \x1b[m
";

lazy_static! {
/// ANSI logo converted to a [`Text`]
static ref LOGO_TEXT: Text<'static> = {
let text = LOGO_ANSI.into_text().expect("failed to parse ANSI");
text.lines
.into_iter()
.map(|line| {
line.spans
.into_iter()
.map(|span| {
// Remove the background color
if let (Some(fg), Some(Color::Reset)) =
(span.style.fg, span.style.bg)
{
span.set_style(fg)
} else {
span
}
})
.collect::<Vec<_>>()
})
.collect()
};
}

/// A logo widget
#[derive(Debug)]
pub struct Logo {
pub is_rendered: bool,
/// The height of the logo
pub height: u16,
/// The width of the logo
pub width: u16,

/// The time the widget was initialized
init_time: Instant,
/// The effect to render the logo
effect: Effect,
}

impl Default for Logo {
fn default() -> Self {
let contents = LOGO_TEXT.clone().reset_style().to_string();
Self {
is_rendered: false,
height: contents.lines().count() as u16,
width: contents
.lines()
.map(|line| line.trim().width())
.max()
.unwrap_or_default() as u16 +
2,
init_time: Instant::now(),
effect: {
let c = Color::from_u32(0x1b1b1b);
let timer = (2000, Interpolation::Linear);
fx::slide_in(Motion::UpToDown, 10, 0, c, timer)
},
}
}
}

impl Widget for &mut Logo {
fn render(self, area: Rect, buf: &mut Buffer) {
LOGO_TEXT.clone().render(area, buf);

// Define the styled line with colored text
let line = Line::from(vec![
"git-".fg(Color::Rgb(255, 255, 255)),
"cliff".fg(Color::Rgb(205, 100, 42)),
])
.italic()
.bold();

// Calculate the length and position
let line_length = line.to_string().len() as u16;
let center_x = area.x + self.width / 2 - line_length / 2;
let center_y = area.y + self.height + 1;
let centered_rect = Rect {
x: center_x.max(area.x),
y: center_y.max(area.y),
width: line_length,
height: 1,
};

// Render the line
line.render(centered_rect, buf);

// Render the effect if running
if self.effect.running() {
buf.render_effect(&mut self.effect, area, Duration::from_millis(100));
}

// Mark as rendered after a delay
self.is_rendered = self.init_time.elapsed().as_millis() > 2000;
}
}
9 changes: 9 additions & 0 deletions git-cliff-tui/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::time::Duration;

use crate::{
event::{
Event,
Expand All @@ -10,6 +12,7 @@ use crate::{
};

pub mod event;
pub mod logo;
pub mod state;
pub mod ui;

Expand All @@ -32,6 +35,12 @@ fn main() -> Result<()> {
// Start the main loop.
loop {
terminal.draw(|frame| ui::render(&mut state, frame))?;

if !state.logo.is_rendered {
std::thread::sleep(Duration::from_millis(16));
continue;
}

let event = events.receiver.recv()?;
match event {
Event::Tick => state.tick(),
Expand Down
5 changes: 5 additions & 0 deletions git-cliff-tui/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use ratatui::widgets::ListState;
use std::error;
use throbber_widgets_tui::ThrobberState;

use crate::logo::Logo;

/// Application result type.
pub type Result<T> = std::result::Result<T, Box<dyn error::Error>>;

Expand All @@ -29,6 +31,8 @@ pub struct State<'a> {
pub throbber_state: ThrobberState,
/// Is generating?
pub is_generating: bool,
/// Logo widget.
pub logo: Logo,
}

impl State<'_> {
Expand All @@ -54,6 +58,7 @@ impl State<'_> {
}
},
is_generating: false,
logo: Logo::default(),
args,
};
state.generate_changelog(false)?;
Expand Down
Loading

0 comments on commit d0c2968

Please sign in to comment.