Add adaptive drill intro, refactor key hints

This commit is contained in:
2026-04-17 20:35:23 +00:00
parent f855fa5606
commit b5ba61a3a3
29 changed files with 1611 additions and 1165 deletions

View File

@@ -6,6 +6,7 @@ use ratatui::widgets::{Block, Paragraph, Widget};
use crate::i18n::t;
use crate::session::result::DrillResult;
use crate::ui::hint;
use crate::ui::layout::pack_hint_lines;
use crate::ui::theme::Theme;
@@ -44,17 +45,17 @@ impl Widget for Dashboard<'_> {
let footer_line_count = if self.input_lock_remaining_ms.is_some() {
1u16
} else {
let hint_continue = t!("dashboard.hint_continue");
let hint_retry = t!("dashboard.hint_retry");
let hint_menu = t!("dashboard.hint_menu");
let hint_stats = t!("dashboard.hint_stats");
let hint_delete = t!("dashboard.hint_delete");
let hint_continue = hint::hint(hint::K_C_ENTER_SPACE, t!("dashboard.hint_continue").as_ref());
let hint_retry = hint::hint(hint::K_R, t!("dashboard.hint_retry").as_ref());
let hint_menu = hint::hint(hint::K_Q, t!("dashboard.hint_menu").as_ref());
let hint_stats = hint::hint(hint::K_S, t!("dashboard.hint_stats").as_ref());
let hint_delete = hint::hint(hint::K_X, t!("dashboard.hint_delete").as_ref());
let hints = [
hint_continue.as_ref(),
hint_retry.as_ref(),
hint_menu.as_ref(),
hint_stats.as_ref(),
hint_delete.as_ref(),
hint_continue.as_str(),
hint_retry.as_str(),
hint_menu.as_str(),
hint_stats.as_str(),
hint_delete.as_str(),
];
pack_hint_lines(&hints, inner.width as usize).len().max(1) as u16
};
@@ -167,17 +168,17 @@ impl Widget for Dashboard<'_> {
),
]))
} else {
let hint_continue = t!("dashboard.hint_continue");
let hint_retry = t!("dashboard.hint_retry");
let hint_menu = t!("dashboard.hint_menu");
let hint_stats = t!("dashboard.hint_stats");
let hint_delete = t!("dashboard.hint_delete");
let hint_continue = hint::hint(hint::K_C_ENTER_SPACE, t!("dashboard.hint_continue").as_ref());
let hint_retry = hint::hint(hint::K_R, t!("dashboard.hint_retry").as_ref());
let hint_menu = hint::hint(hint::K_Q, t!("dashboard.hint_menu").as_ref());
let hint_stats = hint::hint(hint::K_S, t!("dashboard.hint_stats").as_ref());
let hint_delete = hint::hint(hint::K_X, t!("dashboard.hint_delete").as_ref());
let hints = [
hint_continue.as_ref(),
hint_retry.as_ref(),
hint_menu.as_ref(),
hint_stats.as_ref(),
hint_delete.as_ref(),
hint_continue.as_str(),
hint_retry.as_str(),
hint_menu.as_str(),
hint_stats.as_str(),
hint_delete.as_str(),
];
let lines: Vec<Line> = pack_hint_lines(&hints, inner.width as usize)
.into_iter()

View File

@@ -9,6 +9,7 @@ use crate::engine::key_stats::KeyStatsStore;
use crate::engine::skill_tree::{
BranchId, BranchStatus, DrillScope, SkillTree as SkillTreeEngine, get_branch_definition,
};
use crate::ui::hint;
use crate::ui::layout::{pack_hint_lines, wrapped_line_count};
use crate::ui::theme::Theme;
@@ -137,11 +138,11 @@ impl Widget for SkillTreeWidget<'_> {
// Layout: main split (branch list + detail) and footer (adaptive height)
let branches = selectable_branches();
let h_navigate = t!("skill_tree.hint_navigate").to_string();
let h_scroll = t!("skill_tree.hint_scroll").to_string();
let h_back = t!("skill_tree.hint_back").to_string();
let h_unlock = t!("skill_tree.hint_unlock").to_string();
let h_start_drill = t!("skill_tree.hint_start_drill").to_string();
let h_navigate = hint::hint(hint::K_UD_JK, t!("skill_tree.hint_navigate").as_ref());
let h_scroll = hint::hint(hint::K_SCROLL_KEYS, t!("skill_tree.hint_scroll").as_ref());
let h_back = hint::hint(hint::K_Q_ESC, t!("skill_tree.hint_back").as_ref());
let h_unlock = hint::hint(hint::K_ENTER, t!("skill_tree.hint_unlock").as_ref());
let h_start_drill = hint::hint(hint::K_ENTER, t!("skill_tree.hint_start_drill").as_ref());
let (footer_hints, footer_notice): (Vec<&str>, Option<String>) =
if self.selected < branches.len() {
let bp = self.skill_tree.branch_progress(branches[self.selected]);

View File

@@ -13,6 +13,7 @@ use crate::keyboard::model::KeyboardModel;
use crate::session::result::DrillResult;
use crate::ui::components::activity_heatmap::ActivityHeatmap;
use crate::i18n::t;
use crate::ui::hint;
use crate::ui::layout::pack_hint_lines;
use crate::ui::theme::Theme;
@@ -1673,20 +1674,20 @@ const TAB_SEPARATOR: &str = " ";
fn footer_hints_default() -> Vec<String> {
vec![
t!("stats.hint_back").to_string(),
t!("stats.hint_next_tab").to_string(),
t!("stats.hint_switch_tab").to_string(),
hint::hint(hint::K_Q_ESC, t!("stats.hint_back").as_ref()),
hint::hint(hint::K_TAB, t!("stats.hint_next_tab").as_ref()),
hint::hint(hint::K_1_6, t!("stats.hint_switch_tab").as_ref()),
]
}
fn footer_hints_history() -> Vec<String> {
vec![
t!("stats.hint_back").to_string(),
t!("stats.hint_next_tab").to_string(),
t!("stats.hint_switch_tab").to_string(),
t!("stats.hint_navigate").to_string(),
t!("stats.hint_page").to_string(),
t!("stats.hint_delete").to_string(),
hint::hint(hint::K_Q_ESC, t!("stats.hint_back").as_ref()),
hint::hint(hint::K_TAB, t!("stats.hint_next_tab").as_ref()),
hint::hint(hint::K_1_6, t!("stats.hint_switch_tab").as_ref()),
hint::hint(hint::K_J_K, t!("stats.hint_navigate").as_ref()),
hint::hint(hint::K_PGUP_PGDN, t!("stats.hint_page").as_ref()),
hint::hint(hint::K_X, t!("stats.hint_delete").as_ref()),
]
}