Feat: UI / UX

This commit is contained in:
2026-02-16 01:22:40 +01:00
parent b23dd85d0f
commit af6732db1c
37 changed files with 1045 additions and 64 deletions

View File

@@ -3,7 +3,7 @@ use std::sync::atomic::Ordering;
use super::{InputContext, InputResult};
use crate::commands::AppCommand;
use crate::state::{ConfirmAction, DictFocus, HelpFocus, Modal};
use crate::state::{ConfirmAction, DictFocus, FlashKind, HelpFocus, Modal};
pub(super) fn handle_help_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
@@ -26,7 +26,22 @@ pub(super) fn handle_help_page(ctx: &mut InputContext, key: KeyEvent) -> InputRe
KeyCode::Esc if !ctx.app.ui.help_search_query.is_empty() => {
ctx.dispatch(AppCommand::HelpClearSearch);
}
KeyCode::Esc if ctx.app.ui.help_focused_block.is_some() => {
ctx.app.ui.help_focused_block = None;
}
KeyCode::Tab => ctx.dispatch(AppCommand::HelpToggleFocus),
KeyCode::Char('n') if ctx.app.ui.help_focus == HelpFocus::Content => {
navigate_code_block(ctx, true);
}
KeyCode::Char('p') if ctx.app.ui.help_focus == HelpFocus::Content => {
navigate_code_block(ctx, false);
}
KeyCode::Enter
if ctx.app.ui.help_focus == HelpFocus::Content
&& ctx.app.ui.help_focused_block.is_some() =>
{
execute_focused_block(ctx);
}
KeyCode::Char('j') | KeyCode::Down if ctrl => {
ctx.dispatch(AppCommand::HelpNextTopic(5));
}
@@ -49,6 +64,8 @@ pub(super) fn handle_help_page(ctx: &mut InputContext, key: KeyEvent) -> InputRe
selected: false,
}));
}
KeyCode::Char('s') => super::open_save(ctx),
KeyCode::Char('l') => super::open_load(ctx),
KeyCode::Char('?') => {
ctx.dispatch(AppCommand::OpenModal(Modal::KeybindingsHelp { scroll: 0 }));
}
@@ -62,6 +79,57 @@ pub(super) fn handle_help_page(ctx: &mut InputContext, key: KeyEvent) -> InputRe
InputResult::Continue
}
fn navigate_code_block(ctx: &mut InputContext, forward: bool) {
let cache = ctx.app.ui.help_parsed.borrow();
let Some(parsed) = cache[ctx.app.ui.help_topic].as_ref() else {
return;
};
let count = parsed.code_blocks.len();
if count == 0 {
return;
}
let next = match ctx.app.ui.help_focused_block {
Some(cur) if forward => (cur + 1) % count,
Some(0) if !forward => count - 1,
Some(cur) if !forward => cur - 1,
_ if forward => 0,
_ => count - 1,
};
let scroll_to = parsed.code_blocks[next].start_line.saturating_sub(2);
drop(cache);
ctx.app.ui.help_focused_block = Some(next);
*ctx.app.ui.help_scroll_mut() = scroll_to;
}
fn execute_focused_block(ctx: &mut InputContext) {
let source = {
let cache = ctx.app.ui.help_parsed.borrow();
let Some(parsed) = cache[ctx.app.ui.help_topic].as_ref() else {
return;
};
let idx = ctx.app.ui.help_focused_block.unwrap();
let Some(block) = parsed.code_blocks.get(idx) else {
return;
};
block.source.clone()
};
let cleaned: String = source
.lines()
.map(|l| l.split(" => ").next().unwrap_or(l))
.collect::<Vec<_>>()
.join("\n");
match ctx
.app
.execute_script_oneshot(&cleaned, ctx.link, ctx.audio_tx)
{
Ok(()) => ctx.app.ui.flash("Executed", 100, FlashKind::Info),
Err(e) => ctx
.app
.ui
.flash(&format!("Error: {e}"), 200, FlashKind::Error),
}
}
pub(super) fn handle_dict_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
@@ -100,6 +168,8 @@ pub(super) fn handle_dict_page(ctx: &mut InputContext, key: KeyEvent) -> InputRe
selected: false,
}));
}
KeyCode::Char('s') => super::open_save(ctx),
KeyCode::Char('l') => super::open_load(ctx),
KeyCode::Char('?') => {
ctx.dispatch(AppCommand::OpenModal(Modal::KeybindingsHelp { scroll: 0 }));
}