Feat: UI / UX
This commit is contained in:
@@ -4,7 +4,7 @@ use std::time::Duration;
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Cell, Clear, Padding, Paragraph, Row, Table};
|
||||
use ratatui::widgets::{Block, Borders, Cell, Clear, Padding, Paragraph, Row, Table, Wrap};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
@@ -418,13 +418,20 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
("Space", "Play"),
|
||||
("?", "Keys"),
|
||||
],
|
||||
Page::Help => vec![
|
||||
("↑↓", "Scroll"),
|
||||
("Tab", "Topic"),
|
||||
("PgUp/Dn", "Page"),
|
||||
("/", "Search"),
|
||||
("?", "Keys"),
|
||||
],
|
||||
Page::Help => match app.ui.help_focus {
|
||||
crate::state::HelpFocus::Content => vec![
|
||||
("n", "Next Example"),
|
||||
("p", "Previous Example"),
|
||||
("Enter", "Evaluate"),
|
||||
("Tab", "Topics"),
|
||||
],
|
||||
crate::state::HelpFocus::Topics => vec![
|
||||
("↑↓", "Navigate"),
|
||||
("Tab", "Content"),
|
||||
("/", "Search"),
|
||||
("?", "Keys"),
|
||||
],
|
||||
},
|
||||
Page::Dict => vec![
|
||||
("Tab", "Focus"),
|
||||
("↑↓", "Navigate"),
|
||||
@@ -594,6 +601,60 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
|
||||
inner
|
||||
}
|
||||
Modal::Onboarding => {
|
||||
let (desc, keys) = app.page.onboarding();
|
||||
let text_width = 51usize; // inner width minus 2 for padding
|
||||
let desc_lines = {
|
||||
let mut lines = 0u16;
|
||||
for line in desc.split('\n') {
|
||||
lines += (line.len() as u16).max(1).div_ceil(text_width as u16);
|
||||
}
|
||||
lines
|
||||
};
|
||||
let key_lines = keys.len() as u16;
|
||||
let modal_height = (3 + desc_lines + 1 + key_lines + 2).min(term.height.saturating_sub(4)); // border + pad + desc + gap + keys + pad + hint
|
||||
|
||||
let inner = ModalFrame::new(&format!(" {} ", app.page.name()))
|
||||
.width(57)
|
||||
.height(modal_height)
|
||||
.border_color(theme.modal.confirm)
|
||||
.render_centered(frame, term);
|
||||
|
||||
let content_width = inner.width.saturating_sub(4);
|
||||
let mut y = inner.y + 1;
|
||||
|
||||
let desc_area = Rect::new(inner.x + 2, y, content_width, desc_lines);
|
||||
let body = Paragraph::new(desc)
|
||||
.style(Style::new().fg(theme.ui.text_primary))
|
||||
.wrap(Wrap { trim: true });
|
||||
frame.render_widget(body, desc_area);
|
||||
y += desc_lines + 1;
|
||||
|
||||
for &(key, action) in keys {
|
||||
if y >= inner.y + inner.height - 1 {
|
||||
break;
|
||||
}
|
||||
let line = Line::from(vec![
|
||||
Span::raw(" "),
|
||||
Span::styled(
|
||||
format!("{:>8}", key),
|
||||
Style::new().fg(theme.hint.key),
|
||||
),
|
||||
Span::styled(
|
||||
format!(" {action}"),
|
||||
Style::new().fg(theme.hint.text),
|
||||
),
|
||||
]);
|
||||
frame.render_widget(Paragraph::new(line), Rect::new(inner.x + 1, y, inner.width.saturating_sub(2), 1));
|
||||
y += 1;
|
||||
}
|
||||
|
||||
let hint_area = Rect::new(inner.x, inner.y + inner.height - 1, inner.width, 1);
|
||||
let hints = hint_line(&[("Enter", "don't show again"), ("any key", "dismiss")]);
|
||||
frame.render_widget(Paragraph::new(hints).alignment(Alignment::Center), hint_area);
|
||||
|
||||
inner
|
||||
}
|
||||
Modal::KeybindingsHelp { scroll } => render_modal_keybindings(frame, app, *scroll, term),
|
||||
Modal::EuclideanDistribution {
|
||||
source_step,
|
||||
|
||||
Reference in New Issue
Block a user