Feat: entretien de la codebase

This commit is contained in:
2026-02-09 21:12:49 +01:00
parent 60bc7618d3
commit 80c392c24b
25 changed files with 847 additions and 878 deletions

View File

@@ -2,7 +2,7 @@ use cagire_markdown::{CodeHighlighter, MarkdownTheme};
use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line as RLine, Span};
use ratatui::widgets::{Block, Borders, List, ListItem, Padding, Paragraph, Wrap};
use ratatui::widgets::{Block, Borders, Padding, Paragraph, Wrap};
use ratatui::Frame;
#[cfg(not(feature = "desktop"))]
use tui_big_text::{BigText, PixelSize};
@@ -12,6 +12,7 @@ use crate::model::docs::{get_topic, DocEntry, DOCS};
use crate::state::HelpFocus;
use crate::theme;
use crate::views::highlight;
use crate::widgets::{render_search_bar, CategoryItem, CategoryList};
use DocEntry::{Section, Topic};
@@ -100,80 +101,28 @@ pub fn render(frame: &mut Frame, app: &App, area: Rect) {
fn render_topics(frame: &mut Frame, app: &App, area: Rect) {
let theme = theme::get();
let focused = app.ui.help_focus == HelpFocus::Topics;
let visible_height = area.height.saturating_sub(2) as usize;
let total_items = DOCS.len();
// Find the visual index of the selected topic (including sections)
let selected_visual_idx = {
let mut visual = 0;
let mut topic_count = 0;
for entry in DOCS.iter() {
if let Topic(_, _) = entry {
if topic_count == app.ui.help_topic {
break;
}
topic_count += 1;
}
visual += 1;
}
visual
};
// Calculate scroll to keep selection visible (centered when possible)
let scroll = if selected_visual_idx < visible_height / 2 {
0
} else if selected_visual_idx > total_items.saturating_sub(visible_height / 2) {
total_items.saturating_sub(visible_height)
} else {
selected_visual_idx.saturating_sub(visible_height / 2)
};
// Count topics before the scroll offset to track topic_idx correctly
let mut topic_idx = DOCS
let items: Vec<CategoryItem> = DOCS
.iter()
.take(scroll)
.filter(|e| matches!(e, Topic(_, _)))
.count();
let items: Vec<ListItem> = DOCS
.iter()
.skip(scroll)
.take(visible_height)
.map(|entry| match entry {
Section(name) => {
let style = Style::new().fg(theme.ui.text_dim);
ListItem::new(format!("{name}")).style(style)
}
Topic(name, _) => {
let selected = topic_idx == app.ui.help_topic;
let style = if selected {
Style::new()
.fg(theme.dict.category_selected)
.add_modifier(Modifier::BOLD)
} else {
Style::new().fg(theme.ui.text_primary)
};
let prefix = if selected { "> " } else { " " };
topic_idx += 1;
ListItem::new(format!("{prefix}{name}")).style(style)
}
Section(name) => CategoryItem {
label: name,
is_section: true,
},
Topic(name, _) => CategoryItem {
label: name,
is_section: false,
},
})
.collect();
let focused = app.ui.help_focus == HelpFocus::Topics;
let border_color = if focused {
theme.dict.border_focused
} else {
theme.dict.border_normal
};
let list = List::new(items).block(
Block::default()
.borders(Borders::ALL)
.border_style(Style::new().fg(border_color))
.title("Topics"),
);
frame.render_widget(list, area);
CategoryList::new(&items, app.ui.help_topic)
.focused(focused)
.title("Topics")
.selected_color(theme.dict.category_selected)
.normal_color(theme.ui.text_primary)
.render(frame, area);
}
const WELCOME_TOPIC: usize = 0;
@@ -237,7 +186,7 @@ fn render_content(frame: &mut Frame, app: &App, area: Rect) {
let content_area = if has_search_bar {
let [content, search] =
Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).areas(md_area);
render_search_bar(frame, app, search);
render_search_bar(frame, search, &app.ui.help_search_query, app.ui.help_search_active);
content
} else {
md_area
@@ -292,18 +241,6 @@ fn wrapped_line_count(line: &RLine, width: usize) -> usize {
}
}
fn render_search_bar(frame: &mut Frame, app: &App, area: Rect) {
let theme = theme::get();
let style = if app.ui.help_search_active {
Style::new().fg(theme.search.active)
} else {
Style::new().fg(theme.search.inactive)
};
let cursor = if app.ui.help_search_active { "" } else { "" };
let text = format!(" /{}{cursor}", app.ui.help_search_query);
frame.render_widget(Paragraph::new(text).style(style), area);
}
fn highlight_line<'a>(line: RLine<'a>, query: &str) -> RLine<'a> {
let theme = theme::get();
let mut result: Vec<Span<'a>> = Vec::new();