Add block title helpers and use them in UI

This commit is contained in:
2026-03-29 15:12:40 +02:00
parent 1d1dc0f2f7
commit 9719e1ba6b
5 changed files with 115 additions and 15 deletions
+99
View File
@@ -0,0 +1,99 @@
use ratatui::{
style::{Color, Style, Stylize},
text::{Line, Span},
};
/// Creates a styled title `Line` for a UI block.
///
/// This helper builds a `Line` that looks like:
/// ```text
/// [ <title1> <separator> <title2> ... ]
/// ```
/// where each title fragment is rendered in the color supplied by the caller,
/// and the surrounding brackets and any separator are rendered in gray.
///
/// # Arguments
///
/// * `texts` A slice of tuples. Each tuple contains a title fragment (`&str`)
/// and a `Color` that should be applied to that fragment. The order of the
/// tuples determines the order of the fragments in the final line.
///
/// * `separator` An optional string that will be inserted (in gray) between
/// successive title fragments. If `None` the fragments are concatenated
/// directly without any separator.
///
/// # Returns
///
/// A `Line<'a>` that starts with a gray “\[ ”, contains the colored title
/// fragments separated (if requested) by a gray separator, and ends with a
/// gray “ \]”. The line can be passed directly to widgets such as `Block::title`.
///
/// # Example
///
/// ```rust
/// use ratatui::style::Color;
///
/// let title: Line<'_> = block_title_helper(
/// &[
/// ("Skirmish", Color::Magenta),
/// ("Map", Color::Green),
/// ],
/// Some(" - ")
/// );
/// // `title` now represents: [ Skirmish - Map ] with the appropriate colors.
/// ```
pub fn block_title_helper<'a>(texts: &[(&'a str, Color)], separator: Option<&'a str>) -> Line<'a> {
let mut line: Line<'a> = Line::default();
line.spans.push(Span::from("[ ").gray());
for (i, (text, color)) in texts.iter().enumerate() {
let span: Span<'a> = Span::styled(*text, Style::new().fg(*color));
line.spans.push(span);
if let Some(sep) = separator {
if i + 1 < texts.len() {
line.spans.push(Span::from(sep).gray());
}
}
}
line.spans.push(Span::from(" ]").gray());
line
}
/// Convenience wrapper for `block_title_helper` that creates a title line for a
/// single piece of text.
///
/// This function builds a `Line` that looks like:
/// ```text
/// [ <text> ]
/// ```
/// where `<text>` is rendered with the supplied color, and the surrounding
/// brackets are rendered in gray. It simply forwards the arguments to
/// `block_title_helper` with `separator` set to `None`.
///
/// # Arguments
///
/// * `text` The title string to display.
///
/// * `color` The `Color` that should be applied to the title text.
///
/// # Returns
///
/// A `Line<'a>` containing the grey brackets and the coloured title text,
/// ready to be passed to widgets such as `Block::title`.
///
/// # Example
///
/// ```rust
/// use ratatui::style::Color;
///
/// let title: Line<'_> = block_single_title_helper("Keybindings", Color::Magenta);
/// // `title` now represents: [ Keybindings ] with “Keybindings” coloured magenta.
/// ```
pub fn block_single_title_helper<'a>(text: &'a str, color: Color) -> Line<'a> {
block_title_helper(&[(text, color)], None)
}
+3
View File
@@ -0,0 +1,3 @@
pub mod block_title;
pub use block_title::{block_single_title_helper, block_title_helper};
+1
View File
@@ -1,4 +1,5 @@
pub mod app;
pub mod helpers;
pub mod keybind;
pub mod keybindings;
pub mod state;
+6 -8
View File
@@ -1,12 +1,13 @@
use crate::app::{
App,
helpers::block_title_helper,
keybindings::{Action, count_largest_group},
widgets::{BoardWidget, KeybindingsWidget},
};
use ratatui::{
buffer::Buffer,
layout::{Alignment, Constraint, Layout, Margin, Rect},
style::Stylize,
style::{Color, Stylize},
text::Line,
widgets::{Block, Borders, Padding, Paragraph, Widget},
};
@@ -69,13 +70,10 @@ pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) {
{
let board_block: Block = Block::new()
.gray()
.title(Line::from_iter([
"[ ".gray(),
"Skirmish".magenta(),
" - ".gray(),
"Map".green(),
" ]".gray(),
]))
.title(block_title_helper(
&[("Skirmish", Color::Magenta), ("Map", Color::Green)],
Some(" - "),
))
.borders(Borders::LEFT | Borders::TOP | Borders::RIGHT);
let board_area: Rect = board_block.inner(main_area);
+6 -7
View File
@@ -1,9 +1,12 @@
use crate::app::keybindings::{Action, Group, KeyBinding, binding_for};
use crate::app::{
helpers::block_single_title_helper,
keybindings::{Action, Group, KeyBinding, binding_for},
};
use clap::ValueEnum;
use ratatui::{
buffer::Buffer,
layout::{Alignment, Constraint, Layout, Rect},
style::Stylize,
style::{Color, Stylize},
text::Line,
widgets::{Block, Borders, Padding, Paragraph, Widget},
};
@@ -72,11 +75,7 @@ impl Widget for KeybindingsWidget {
let block: Block<'_> = Block::default()
.borders(Borders::ALL)
.title(Line::from_iter([
"[ ".gray(),
"Keybindings".magenta(),
" ]".gray(),
]));
.title(block_single_title_helper("Keybindings", Color::Magenta));
let inner: Rect = block.inner(area);