chore: wrap long titles 45037f22
Steve Simkins · 2026-05-06 18:44 1 file(s) · +52 −18
src/main.rs +52 −18
85 85
    format!("{} {}{}, {}", dt.format("%B"), day, suffix, dt.format("%Y"))
86 86
}
87 87
88 +
fn wrap_text(text: &str, max_width: usize) -> Vec<String> {
89 +
    if max_width == 0 {
90 +
        return vec![text.to_string()];
91 +
    }
92 +
    let mut lines: Vec<String> = Vec::new();
93 +
    let mut current = String::new();
94 +
    for word in text.split_whitespace() {
95 +
        if current.is_empty() {
96 +
            current.push_str(word);
97 +
        } else if current.len() + 1 + word.len() <= max_width {
98 +
            current.push(' ');
99 +
            current.push_str(word);
100 +
        } else {
101 +
            lines.push(current);
102 +
            current = word.to_string();
103 +
        }
104 +
    }
105 +
    if !current.is_empty() {
106 +
        lines.push(current);
107 +
    }
108 +
    if lines.is_empty() {
109 +
        lines.push(String::new());
110 +
    }
111 +
    lines
112 +
}
113 +
88 114
fn render(frame: &mut Frame, entries: &[(&Entry, Option<&str>)], state: &mut ListState) {
115 +
    let outer = frame.area();
116 +
    let [_, center, _] = Layout::default()
117 +
        .direction(Direction::Horizontal)
118 +
        .constraints([
119 +
            Constraint::Fill(1),
120 +
            Constraint::Max(80),
121 +
            Constraint::Fill(1),
122 +
        ])
123 +
        .areas(outer);
124 +
125 +
    let block = Block::new().padding(Padding::symmetric(2, 1));
126 +
    let inner = block.inner(center);
127 +
    let title_width = inner.width.saturating_sub(2) as usize;
128 +
89 129
    let dim = Style::new().fg(Color::DarkGray);
90 130
    let author_style = Style::new()
91 131
        .fg(Color::DarkGray)
110 150
                .and_then(|a| a.name.as_deref())
111 151
                .or(*feed_title)
112 152
                .unwrap_or("anon");
113 -
            ListItem::new(Text::from(vec![
114 -
                Line::from(vec![Span::raw(bar), Span::styled(date, dim)]),
115 -
                Line::from(vec![Span::raw(bar), Span::raw(title.to_string())]),
116 -
                Line::from(vec![Span::raw(bar), Span::styled(author.to_string(), author_style)]),
117 -
                Line::from(""),
118 -
            ]))
153 +
154 +
            let mut lines = vec![Line::from(vec![Span::raw(bar), Span::styled(date, dim)])];
155 +
            for wrapped in wrap_text(title, title_width) {
156 +
                lines.push(Line::from(vec![Span::raw(bar), Span::raw(wrapped)]));
157 +
            }
158 +
            lines.push(Line::from(vec![
159 +
                Span::raw(bar),
160 +
                Span::styled(author.to_string(), author_style),
161 +
            ]));
162 +
            lines.push(Line::from(""));
163 +
164 +
            ListItem::new(Text::from(lines))
119 165
        })
120 166
        .collect();
121 167
122 -
    let outer = frame.area();
123 -
    let [_, center, _] = Layout::default()
124 -
        .direction(Direction::Horizontal)
125 -
        .constraints([
126 -
            Constraint::Fill(1),
127 -
            Constraint::Max(80),
128 -
            Constraint::Fill(1),
129 -
        ])
130 -
        .areas(outer);
131 -
132 -
    let block = Block::new().padding(Padding::symmetric(2, 1));
133 -
    let inner = block.inner(center);
134 168
    frame.render_widget(block, center);
135 169
    frame.render_stateful_widget(
136 170
        List::new(items)