//! Common widgets shared across all TUI screens.
//!
//! Each widget is a pure rendering function — writes directly into the
//! [`Frame`] buffer using ftui's `Draw` trait. No state mutation,
//! no side effects.

mod breadcrumb;
pub mod cross_ref;
pub mod discussion_tree;
pub mod entity_table;
mod error_toast;
pub mod filter_bar;
mod help_overlay;
mod loading;
mod status_bar;

pub use breadcrumb::render_breadcrumb;
pub use cross_ref::{CrossRef, CrossRefColors, CrossRefKind, CrossRefState, render_cross_refs};
pub use discussion_tree::{
    DiscussionNode, DiscussionTreeColors, DiscussionTreeState, NoteNode, format_relative_time,
    render_discussion_tree,
};
pub use entity_table::{ColumnDef, EntityTableState, TableColors, TableRow, render_entity_table};
pub use error_toast::render_error_toast;
pub use filter_bar::{FilterBarColors, FilterBarState, render_filter_bar};
pub use help_overlay::render_help_overlay;
pub use loading::render_loading;
pub use status_bar::render_status_bar;

/// Truncate a string to at most `max_chars` display characters.
///
/// Uses Unicode ellipsis `…` for truncation. If `max_chars` is too small
/// for an ellipsis (<=1), just truncates without one.
pub fn truncate_str(s: &str, max_chars: usize) -> String {
    if s.chars().count() <= max_chars {
        s.to_string()
    } else if max_chars <= 1 {
        s.chars().take(max_chars).collect()
    } else {
        let truncated: String = s.chars().take(max_chars.saturating_sub(1)).collect();
        format!("{truncated}\u{2026}")
    }
}
