Wip: refacto

This commit is contained in:
2026-01-25 22:17:08 +01:00
parent 2d609f6b7a
commit 016d050678
11 changed files with 289 additions and 82 deletions

View File

@@ -32,8 +32,9 @@ pub fn render(frame: &mut Frame, app: &App, area: Rect) {
let [cat_area, words_area] =
Layout::horizontal([Constraint::Length(16), Constraint::Fill(1)]).areas(body_area);
render_categories(frame, app, cat_area);
render_words(frame, app, words_area);
let is_searching = !app.ui.dict_search_query.is_empty();
render_categories(frame, app, cat_area, is_searching);
render_words(frame, app, words_area, is_searching);
}
fn render_header(frame: &mut Frame, area: Rect) {
@@ -52,22 +53,24 @@ fn render_header(frame: &mut Frame, area: Rect) {
frame.render_widget(para, area);
}
fn render_categories(frame: &mut Frame, app: &App, area: Rect) {
let focused = app.ui.dict_focus == DictFocus::Categories;
fn render_categories(frame: &mut Frame, app: &App, area: Rect, dimmed: bool) {
let focused = app.ui.dict_focus == DictFocus::Categories && !dimmed;
let items: Vec<ListItem> = CATEGORIES
.iter()
.enumerate()
.map(|(i, name)| {
let is_selected = i == app.ui.dict_category;
let style = if is_selected && focused {
let style = if dimmed {
Style::new().fg(Color::Rgb(80, 80, 90))
} else if is_selected && focused {
Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD)
} else if is_selected {
Style::new().fg(Color::Cyan)
} else {
Style::new().fg(Color::White)
};
let prefix = if is_selected { "> " } else { " " };
let prefix = if is_selected && !dimmed { "> " } else { " " };
ListItem::new(format!("{prefix}{name}")).style(style)
})
.collect();
@@ -81,15 +84,40 @@ fn render_categories(frame: &mut Frame, app: &App, area: Rect) {
frame.render_widget(list, area);
}
fn render_words(frame: &mut Frame, app: &App, area: Rect) {
fn render_words(frame: &mut Frame, app: &App, area: Rect, is_searching: bool) {
let focused = app.ui.dict_focus == DictFocus::Words;
let category = CATEGORIES[app.ui.dict_category];
let words: Vec<&Word> = WORDS
.iter()
.filter(|w| word_category(w.name, &w.compile) == category)
.collect();
let content_width = area.width.saturating_sub(2) as usize;
// Filter words by search query or category
let words: Vec<&Word> = if is_searching {
let query = app.ui.dict_search_query.to_lowercase();
WORDS
.iter()
.filter(|w| w.name.to_lowercase().contains(&query))
.collect()
} else {
let category = CATEGORIES[app.ui.dict_category];
WORDS
.iter()
.filter(|w| word_category(w.name, &w.compile) == category)
.collect()
};
// Split area for search bar when search is active or has query
let show_search = app.ui.dict_search_active || is_searching;
let (search_area, content_area) = if show_search {
let [s, c] =
Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).areas(area);
(Some(s), c)
} else {
(None, area)
};
// Render search bar
if let Some(sa) = search_area {
render_search_bar(frame, app, sa);
}
let content_width = content_area.width.saturating_sub(2) as usize;
let mut lines: Vec<RLine> = Vec::new();
@@ -127,7 +155,7 @@ fn render_words(frame: &mut Frame, app: &App, area: Rect) {
lines.push(RLine::from(""));
}
let visible_height = area.height.saturating_sub(2) as usize;
let visible_height = content_area.height.saturating_sub(2) as usize;
let total_lines = lines.len();
let max_scroll = total_lines.saturating_sub(visible_height);
let scroll = app.ui.dict_scroll.min(max_scroll);
@@ -138,14 +166,31 @@ fn render_words(frame: &mut Frame, app: &App, area: Rect) {
.take(visible_height)
.collect();
let title = format!("{category} ({} words)", words.len());
let title = if is_searching {
format!("Search: {} matches", words.len())
} else {
let category = CATEGORIES[app.ui.dict_category];
format!("{category} ({} words)", words.len())
};
let border_color = if focused { Color::Yellow } else { Color::Rgb(60, 60, 70) };
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::new().fg(border_color))
.title(title);
let para = Paragraph::new(visible).block(block);
frame.render_widget(para, area);
frame.render_widget(para, content_area);
}
fn render_search_bar(frame: &mut Frame, app: &App, area: Rect) {
let style = if app.ui.dict_search_active {
Style::new().fg(Color::Yellow)
} else {
Style::new().fg(Color::DarkGray)
};
let cursor = if app.ui.dict_search_active { "_" } else { "" };
let text = format!(" /{}{}", app.ui.dict_search_query, cursor);
let line = RLine::from(Span::styled(text, style));
frame.render_widget(Paragraph::new(vec![line]), area);
}
fn word_category(name: &str, compile: &WordCompile) -> &'static str {