First
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
1692
Cargo.lock
generated
Normal file
1692
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "cj-jftui"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
authors = ["Christopher Warren Johnson III"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ratatui = "0.30.0"
|
||||||
|
color-eyre = "0.6.3"
|
||||||
|
crossterm = "0.29.0"
|
||||||
72
src/main.rs
Normal file
72
src/main.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
use std::{io, time::{Duration, Instant}};
|
||||||
|
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
|
||||||
|
use ratatui::{DefaultTerminal, Frame};
|
||||||
|
use ratatui::layout::{Constraint, Layout, Spacing};
|
||||||
|
use ratatui::symbols::merge::MergeStrategy;
|
||||||
|
use ratatui::widgets::Block;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct App {
|
||||||
|
should_exit: bool,
|
||||||
|
// navigation state goes here (selected index, velocity, etc.)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let tick_rate = Duration::from_millis(16); // ~60Hz
|
||||||
|
let mut last_tick = Instant::now();
|
||||||
|
|
||||||
|
ratatui::run(|terminal: &mut DefaultTerminal| {
|
||||||
|
let mut app = App::default();
|
||||||
|
|
||||||
|
while !app.should_exit {
|
||||||
|
terminal.draw(|f| render(f))?;
|
||||||
|
|
||||||
|
// Non-blocking input with timeout until next tick
|
||||||
|
let timeout = tick_rate.saturating_sub(last_tick.elapsed());
|
||||||
|
if event::poll(timeout)? {
|
||||||
|
if let Event::Key(key) = event::read()? {
|
||||||
|
if key.kind == KeyEventKind::Press {
|
||||||
|
match key.code {
|
||||||
|
KeyCode::Char('q') => app.should_exit = true,
|
||||||
|
|
||||||
|
// KeyCode::Up/Down etc => update nav intent/state
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tick for time-based navigation / animations
|
||||||
|
if last_tick.elapsed() >= tick_rate {
|
||||||
|
// app.on_tick(last_tick.elapsed());
|
||||||
|
last_tick = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(frame: &mut Frame) {
|
||||||
|
use Constraint::{Fill};
|
||||||
|
|
||||||
|
let [top_area, rest_area] = Layout::vertical([Fill(1), Fill(12)]).areas(frame.area());
|
||||||
|
|
||||||
|
let [main_area, output_area] = Layout::vertical([Fill(9), Fill(3)])
|
||||||
|
.spacing(Spacing::Overlap(1))
|
||||||
|
.areas(rest_area);
|
||||||
|
|
||||||
|
let [left_main_area, right_main_area] = Layout::horizontal([Fill(2), Fill(5)])
|
||||||
|
.spacing(Spacing::Overlap(1))
|
||||||
|
.areas(main_area);
|
||||||
|
|
||||||
|
let [left_output_area, right_output_area] = Layout::horizontal([Fill(5), Fill(1)])
|
||||||
|
.spacing(Spacing::Overlap(1))
|
||||||
|
.areas(output_area);
|
||||||
|
|
||||||
|
frame.render_widget(Block::bordered(), top_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), left_output_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), right_output_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), left_main_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), right_main_area);
|
||||||
|
}
|
||||||
66
src/old_main.rs
Normal file
66
src/old_main.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||||
|
|
||||||
|
use ratatui::{
|
||||||
|
buffer::Buffer,
|
||||||
|
layout::{Rect, Constraint, Layout, Spacing},
|
||||||
|
style::Stylize,
|
||||||
|
symbols::{border, merge::MergeStrategy},
|
||||||
|
text::{Line, Text},
|
||||||
|
widgets::{Block, Paragraph, Widget},
|
||||||
|
DefaultTerminal, Frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
ratatui::run(|terminal| {
|
||||||
|
loop {
|
||||||
|
terminal.draw(render)?;
|
||||||
|
|
||||||
|
let should_exit: bool = exit_app()?;
|
||||||
|
if should_exit { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(frame: &mut Frame) {
|
||||||
|
use Constraint::{Fill, Length, Min};
|
||||||
|
|
||||||
|
let [top_area, rest_area] =
|
||||||
|
Layout::vertical([Fill(1), Fill(12)]).areas(frame.area());
|
||||||
|
|
||||||
|
let [main_area, output_area] =
|
||||||
|
Layout::vertical([Fill(9), Fill(3)])
|
||||||
|
.spacing(Spacing::Overlap(1))
|
||||||
|
.areas(rest_area);
|
||||||
|
|
||||||
|
let [left_main_area, right_main_area] =
|
||||||
|
Layout::horizontal([Fill(2), Fill(5)])
|
||||||
|
.spacing(Spacing::Overlap(1))
|
||||||
|
.areas(main_area);
|
||||||
|
|
||||||
|
let [left_output_area, right_output_area] =
|
||||||
|
Layout::horizontal([Fill(5), Fill(1)])
|
||||||
|
.spacing(Spacing::Overlap(1))
|
||||||
|
.areas(output_area);
|
||||||
|
|
||||||
|
frame.render_widget(Block::bordered(), top_area);
|
||||||
|
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), left_output_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), right_output_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), left_main_area);
|
||||||
|
frame.render_widget(Block::bordered().merge_borders(MergeStrategy::Exact), right_main_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_app() -> io::Result<bool> {
|
||||||
|
match event::read()? {
|
||||||
|
Event::Key(key) if key.kind == KeyEventKind::Press => match key.code {
|
||||||
|
KeyCode::Char('q') => return Ok(true),
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user