Feat: collapsible help
This commit is contained in:
@@ -9,7 +9,7 @@ use crate::model::categories::{get_category_name, CatEntry, CATEGORIES};
|
||||
use crate::model::{Word, WORDS};
|
||||
use crate::state::DictFocus;
|
||||
use crate::theme;
|
||||
use crate::widgets::{render_search_bar, CategoryItem, CategoryList};
|
||||
use crate::widgets::{render_search_bar, CategoryItem, CategoryList, Selection};
|
||||
|
||||
use CatEntry::{Category, Section};
|
||||
|
||||
@@ -51,21 +51,38 @@ fn render_categories(frame: &mut Frame, app: &App, area: Rect, dimmed: bool) {
|
||||
let theme = theme::get();
|
||||
let focused = app.ui.dict_focus == DictFocus::Categories && !dimmed;
|
||||
|
||||
let mut section_idx = 0usize;
|
||||
let items: Vec<CategoryItem> = CATEGORIES
|
||||
.iter()
|
||||
.map(|entry| match entry {
|
||||
Section(name) => CategoryItem {
|
||||
label: name,
|
||||
is_section: true,
|
||||
},
|
||||
Section(name) => {
|
||||
let collapsed = app
|
||||
.ui
|
||||
.dict_collapsed
|
||||
.get(section_idx)
|
||||
.copied()
|
||||
.unwrap_or(false);
|
||||
section_idx += 1;
|
||||
CategoryItem {
|
||||
label: name,
|
||||
is_section: true,
|
||||
collapsed,
|
||||
}
|
||||
}
|
||||
Category(name) => CategoryItem {
|
||||
label: name,
|
||||
is_section: false,
|
||||
collapsed: false,
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut list = CategoryList::new(&items, app.ui.dict_category)
|
||||
let selection = match app.ui.dict_on_section {
|
||||
Some(s) => Selection::Section(s),
|
||||
None => Selection::Item(app.ui.dict_category),
|
||||
};
|
||||
|
||||
let mut list = CategoryList::new(&items, selection)
|
||||
.focused(focused)
|
||||
.title("Categories");
|
||||
|
||||
@@ -91,23 +108,24 @@ fn render_words(frame: &mut Frame, app: &App, area: Rect, is_searching: bool) {
|
||||
.collect()
|
||||
} else {
|
||||
let category = get_category_name(app.ui.dict_category);
|
||||
WORDS
|
||||
.iter()
|
||||
.filter(|w| w.category == category)
|
||||
.collect()
|
||||
WORDS.iter().filter(|w| w.category == category).collect()
|
||||
};
|
||||
|
||||
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);
|
||||
let [s, c] = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).areas(area);
|
||||
(Some(s), c)
|
||||
} else {
|
||||
(None, area)
|
||||
};
|
||||
|
||||
if let Some(sa) = search_area {
|
||||
render_search_bar(frame, sa, &app.ui.dict_search_query, app.ui.dict_search_active);
|
||||
render_search_bar(
|
||||
frame,
|
||||
sa,
|
||||
&app.ui.dict_search_query,
|
||||
app.ui.dict_search_active,
|
||||
);
|
||||
}
|
||||
|
||||
let content_width = content_area.width.saturating_sub(2) as usize;
|
||||
@@ -172,7 +190,11 @@ fn render_words(frame: &mut Frame, app: &App, area: Rect, is_searching: bool) {
|
||||
let category = get_category_name(app.ui.dict_category);
|
||||
format!("{category} ({} words)", words.len())
|
||||
};
|
||||
let border_color = if focused { theme.dict.border_focused } else { theme.dict.border_normal };
|
||||
let border_color = if focused {
|
||||
theme.dict.border_focused
|
||||
} else {
|
||||
theme.dict.border_normal
|
||||
};
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::new().fg(border_color))
|
||||
|
||||
@@ -11,7 +11,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 crate::widgets::{render_search_bar, CategoryItem, CategoryList, Selection};
|
||||
|
||||
use DocEntry::{Section, Topic};
|
||||
|
||||
@@ -105,21 +105,38 @@ fn render_topics(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let focused = app.ui.help_focus == HelpFocus::Topics;
|
||||
|
||||
let mut section_idx = 0usize;
|
||||
let items: Vec<CategoryItem> = DOCS
|
||||
.iter()
|
||||
.map(|entry| match entry {
|
||||
Section(name) => CategoryItem {
|
||||
label: name,
|
||||
is_section: true,
|
||||
},
|
||||
Section(name) => {
|
||||
let collapsed = app
|
||||
.ui
|
||||
.help_collapsed
|
||||
.get(section_idx)
|
||||
.copied()
|
||||
.unwrap_or(false);
|
||||
section_idx += 1;
|
||||
CategoryItem {
|
||||
label: name,
|
||||
is_section: true,
|
||||
collapsed,
|
||||
}
|
||||
}
|
||||
Topic(name, _) => CategoryItem {
|
||||
label: name,
|
||||
is_section: false,
|
||||
collapsed: false,
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
|
||||
CategoryList::new(&items, app.ui.help_topic)
|
||||
let selection = match app.ui.help_on_section {
|
||||
Some(s) => Selection::Section(s),
|
||||
None => Selection::Item(app.ui.help_topic),
|
||||
};
|
||||
|
||||
CategoryList::new(&items, selection)
|
||||
.focused(focused)
|
||||
.title("Topics")
|
||||
.selected_color(theme.dict.category_selected)
|
||||
@@ -172,7 +189,8 @@ fn render_content(frame: &mut Frame, app: &App, area: Rect) {
|
||||
{
|
||||
let mut cache = app.ui.help_parsed.borrow_mut();
|
||||
if cache[app.ui.help_topic].is_none() {
|
||||
cache[app.ui.help_topic] = Some(cagire_markdown::parse(md, &AppTheme, &ForthHighlighter));
|
||||
cache[app.ui.help_topic] =
|
||||
Some(cagire_markdown::parse(md, &AppTheme, &ForthHighlighter));
|
||||
}
|
||||
}
|
||||
let cache = app.ui.help_parsed.borrow();
|
||||
@@ -182,7 +200,12 @@ 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, search, &app.ui.help_search_query, app.ui.help_search_active);
|
||||
render_search_bar(
|
||||
frame,
|
||||
search,
|
||||
&app.ui.help_search_query,
|
||||
app.ui.help_search_active,
|
||||
);
|
||||
content
|
||||
} else {
|
||||
md_area
|
||||
@@ -295,4 +318,3 @@ fn highlight_line<'a>(line: RLine<'a>, query: &str) -> RLine<'a> {
|
||||
fn find_bytes(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
||||
haystack.windows(needle.len()).position(|w| w == needle)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user