feat(ui): add configurable message timestamps and card rendering layout

This commit is contained in:
2025-10-12 23:57:46 +02:00
parent b80db89391
commit 15f81d9728
4 changed files with 533 additions and 406 deletions

View File

@@ -722,6 +722,8 @@ pub struct UiSettings {
pub show_cursor_outside_insert: bool,
#[serde(default = "UiSettings::default_syntax_highlighting")]
pub syntax_highlighting: bool,
#[serde(default = "UiSettings::default_show_timestamps")]
pub show_timestamps: bool,
}
impl UiSettings {
@@ -765,6 +767,10 @@ impl UiSettings {
false
}
const fn default_show_timestamps() -> bool {
true
}
fn deserialize_role_label_mode<'de, D>(
deserializer: D,
) -> std::result::Result<RoleLabelDisplay, D::Error>
@@ -831,6 +837,7 @@ impl Default for UiSettings {
scrollback_lines: Self::default_scrollback_lines(),
show_cursor_outside_insert: Self::default_show_cursor_outside_insert(),
syntax_highlighting: Self::default_syntax_highlighting(),
show_timestamps: Self::default_show_timestamps(),
}
}
}

View File

@@ -38,6 +38,7 @@ anyhow = { workspace = true }
uuid = { workspace = true }
serde_json.workspace = true
serde.workspace = true
chrono = { workspace = true }
[dev-dependencies]
tokio-test = { workspace = true }

File diff suppressed because it is too large Load Diff

View File

@@ -1029,14 +1029,15 @@ fn render_messages(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
// Calculate viewport dimensions for autoscroll calculations
let viewport_height = area.height.saturating_sub(2) as usize; // subtract borders
let content_width = area.width.saturating_sub(4).max(20);
app.set_viewport_dimensions(viewport_height, usize::from(content_width));
let card_width = usize::from(area.width.saturating_sub(4).max(20));
let body_width = card_width.saturating_sub(4).max(12);
app.set_viewport_dimensions(viewport_height, body_width);
let total_messages = app.message_count();
let mut formatter = app.formatter().clone();
// Reserve space for borders and the message indent so text fits within the block
formatter.set_wrap_width(usize::from(content_width));
formatter.set_wrap_width(body_width);
// Build the lines for messages using cached rendering
let mut lines: Vec<Line<'static>> = Vec::new();
@@ -1055,8 +1056,8 @@ fn render_messages(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
MessageRenderContext::new(
&mut formatter,
role_label_mode,
content_width as usize,
message_index + 1 == total_messages,
body_width,
card_width,
is_streaming,
app.get_loading_indicator(),
&theme,
@@ -1064,9 +1065,6 @@ fn render_messages(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
),
);
lines.extend(message_lines);
if message_index + 1 < total_messages {
lines.push(Line::from(String::new()));
}
}
// Add loading indicator ONLY if we're loading and there are no messages at all,