Feat: documentation, UI/UX
This commit is contained in:
@@ -228,8 +228,8 @@ fn render_content(frame: &mut Frame, app: &App, area: Rect) {
|
||||
|
||||
let mut lines = parsed.lines.clone();
|
||||
|
||||
// Highlight focused code block with background tint
|
||||
if let Some(block_idx) = app.ui.help_focused_block {
|
||||
// Highlight focused code block with background tint and border
|
||||
let border_lines_inserted = if let Some(block_idx) = app.ui.help_focused_block {
|
||||
if let Some(block) = parsed.code_blocks.get(block_idx) {
|
||||
let tint_bg = theme.ui.surface;
|
||||
for line in lines.iter_mut().take(block.end_line).skip(block.start_line) {
|
||||
@@ -242,6 +242,31 @@ fn render_content(frame: &mut Frame, app: &App, area: Rect) {
|
||||
*span = Span::styled(span.content.clone(), style);
|
||||
}
|
||||
}
|
||||
let border = "─".repeat(content_width.saturating_sub(1));
|
||||
let border_line = RLine::from(Span::styled(
|
||||
format!(" {border}"),
|
||||
Style::new().fg(theme.ui.accent),
|
||||
));
|
||||
lines.insert(block.end_line, border_line.clone());
|
||||
lines.insert(block.start_line, border_line);
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// Insert print output line after the executed code block
|
||||
if let Some((topic, block_idx, ref output)) = app.ui.help_block_output {
|
||||
if topic == app.ui.help_topic {
|
||||
if let Some(block) = parsed.code_blocks.get(block_idx) {
|
||||
let output_line = RLine::from(vec![
|
||||
Span::styled(" → ", Style::new().fg(theme.markdown.code_border)),
|
||||
Span::styled(output.clone(), Style::new().fg(theme.markdown.code)),
|
||||
]);
|
||||
lines.insert(block.end_line + border_lines_inserted, output_line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//! Main page view — sequencer grid, visualizations (scope/spectrum), script previews.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Instant;
|
||||
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
@@ -361,6 +363,26 @@ fn render_sequencer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot,
|
||||
}
|
||||
}
|
||||
|
||||
fn pulse_phase() -> f32 {
|
||||
static EPOCH: OnceLock<Instant> = OnceLock::new();
|
||||
let t = EPOCH.get_or_init(Instant::now).elapsed().as_secs_f32();
|
||||
(1.0 + (t * std::f32::consts::TAU).sin()) * 0.5
|
||||
}
|
||||
|
||||
fn pulse_color(color: Color) -> Color {
|
||||
let Color::Rgb(r, g, b) = color else { return color };
|
||||
let lum = 0.299 * r as f32 + 0.587 * g as f32 + 0.114 * b as f32;
|
||||
let amp = pulse_phase() * 0.12;
|
||||
let shift = |c: u8| -> u8 {
|
||||
if lum < 128.0 {
|
||||
(c as f32 + (255.0 - c as f32) * amp) as u8
|
||||
} else {
|
||||
(c as f32 * (1.0 - amp)) as u8
|
||||
}
|
||||
};
|
||||
Color::Rgb(shift(r), shift(g), shift(b))
|
||||
}
|
||||
|
||||
fn render_tile(
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
@@ -417,6 +439,7 @@ fn render_tile(
|
||||
(false, false, _, _, true) => (theme.selection.in_range, theme.selection.cursor_fg),
|
||||
(false, false, false, _, _) => (theme.tile.inactive_bg, theme.tile.inactive_fg),
|
||||
};
|
||||
let bg = if is_selected && !is_playing { pulse_color(bg) } else { bg };
|
||||
|
||||
let bg_fill = Paragraph::new("").style(Style::new().bg(bg));
|
||||
frame.render_widget(bg_fill, area);
|
||||
|
||||
@@ -197,7 +197,7 @@ pub fn render(
|
||||
}
|
||||
|
||||
if !perf {
|
||||
render_footer(frame, app, footer_area);
|
||||
render_footer(frame, app, snapshot, footer_area);
|
||||
}
|
||||
let modal_area = render_modal(frame, app, snapshot, term);
|
||||
|
||||
@@ -512,7 +512,7 @@ fn render_header(
|
||||
);
|
||||
}
|
||||
|
||||
fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
fn render_footer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
@@ -539,6 +539,15 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
Span::raw(" "),
|
||||
Span::styled(msg.clone(), Style::new().fg(theme.modal.confirm)),
|
||||
])
|
||||
} else if let Some(ref text) = snapshot.print_output {
|
||||
Line::from(vec![
|
||||
Span::styled(
|
||||
page_indicator.to_string(),
|
||||
Style::new().bg(theme.view_badge.bg).fg(theme.view_badge.fg),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::styled(text.clone(), Style::new().fg(theme.hint.text)),
|
||||
])
|
||||
} else {
|
||||
let bindings: Vec<(&str, &str)> = match app.page {
|
||||
Page::Main => vec![
|
||||
@@ -593,7 +602,6 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
("Esc", "Save & Back"),
|
||||
("C-e", "Eval"),
|
||||
("[ ]", "Speed"),
|
||||
("C-s", "Stack"),
|
||||
("?", "Keys"),
|
||||
],
|
||||
};
|
||||
@@ -1071,33 +1079,12 @@ fn render_modal_editor(
|
||||
if app.editor_ctx.editor.search_active() {
|
||||
let hints = hint_line(&[("Enter", "confirm"), ("Esc", "cancel")]);
|
||||
frame.render_widget(Paragraph::new(hints).alignment(Alignment::Right), hint_area);
|
||||
} else if app.editor_ctx.show_stack {
|
||||
let stack_text = app
|
||||
.editor_ctx
|
||||
.stack_cache
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|c| c.result.clone())
|
||||
.unwrap_or_else(|| "Stack: []".to_string());
|
||||
let hints = hint_line(&[("Esc", "save"), ("C-e", "eval"), ("C-s", "hide")]);
|
||||
let [hint_left, stack_right] = Layout::horizontal([
|
||||
Constraint::Length(hints.width() as u16),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(hint_area);
|
||||
frame.render_widget(Paragraph::new(hints), hint_left);
|
||||
let dim = Style::default().fg(theme.hint.text);
|
||||
frame.render_widget(
|
||||
Paragraph::new(Span::styled(stack_text, dim)).alignment(Alignment::Right),
|
||||
stack_right,
|
||||
);
|
||||
} else {
|
||||
let hints = hint_line(&[
|
||||
("Esc", "save"),
|
||||
("C-e", "eval"),
|
||||
("C-f", "find"),
|
||||
("C-b", "samples"),
|
||||
("C-s", "stack"),
|
||||
("C-u", "/"),
|
||||
("C-r", "undo/redo"),
|
||||
]);
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::collections::HashSet;
|
||||
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::Span;
|
||||
use ratatui::widgets::{Block, Borders, Paragraph};
|
||||
use ratatui::Frame;
|
||||
|
||||
@@ -93,31 +92,10 @@ fn render_editor(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, are
|
||||
("?", "keys"),
|
||||
]);
|
||||
frame.render_widget(Paragraph::new(hints).alignment(Alignment::Right), hint_area);
|
||||
} else if app.script_editor.show_stack {
|
||||
let stack_text = app
|
||||
.script_editor
|
||||
.stack_cache
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|c| c.result.clone())
|
||||
.unwrap_or_else(|| "Stack: []".to_string());
|
||||
let hints = hint_line(&[("Esc", "unfocus"), ("C-e", "eval"), ("C-s", "hide stack")]);
|
||||
let [hint_left, stack_right] = Layout::horizontal([
|
||||
Constraint::Length(hints.width() as u16),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(hint_area);
|
||||
frame.render_widget(Paragraph::new(hints), hint_left);
|
||||
let dim = Style::default().fg(theme.hint.text);
|
||||
frame.render_widget(
|
||||
Paragraph::new(Span::styled(stack_text, dim)).alignment(Alignment::Right),
|
||||
stack_right,
|
||||
);
|
||||
} else {
|
||||
let hints = hint_line(&[
|
||||
("Esc", "unfocus"),
|
||||
("C-e", "eval"),
|
||||
("C-s", "stack"),
|
||||
]);
|
||||
frame.render_widget(Paragraph::new(hints).alignment(Alignment::Right), hint_area);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user