repo initialized
This commit is contained in:
168
src/ui.rs
Normal file
168
src/ui.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
use ratatui::{
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph, Clear},
|
||||
Frame,
|
||||
};
|
||||
|
||||
use crate::app::{App, InputMode};
|
||||
|
||||
pub fn ui(f: &mut Frame, app: &mut App) {
|
||||
let size = f.size();
|
||||
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(0), Constraint::Length(3)].as_ref())
|
||||
.split(size);
|
||||
|
||||
let items: Vec<ListItem> = app
|
||||
.servers
|
||||
.iter()
|
||||
.map(|s| {
|
||||
let content = format!("{} ({}) - {}:{}", s.name, s.user, s.host, s.port);
|
||||
ListItem::new(content).style(Style::default())
|
||||
})
|
||||
.collect();
|
||||
|
||||
let list = List::new(items)
|
||||
.block(Block::default().borders(Borders::ALL).title(" SSHX - Servers "))
|
||||
.highlight_style(Style::default().add_modifier(Modifier::BOLD).fg(Color::Yellow))
|
||||
.highlight_symbol("> ");
|
||||
|
||||
f.render_stateful_widget(list, chunks[0], &mut app.state);
|
||||
|
||||
// Help text
|
||||
let help_text = match app.input_mode {
|
||||
InputMode::Normal => "Enter: Connect | m: Mosh | n: New | Shift+n: Copy ID | i: Edit | d: Delete | q: Quit | j/k: Up/Down",
|
||||
InputMode::Adding(_) => "Enter: Save | Esc: Cancel | Tab: Next Field",
|
||||
InputMode::Editing(_) => "Enter: Save | Esc: Cancel | Tab: Next Field",
|
||||
};
|
||||
let help = Paragraph::new(help_text)
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.block(Block::default().borders(Borders::ALL).title(" Help "));
|
||||
f.render_widget(help, chunks[1]);
|
||||
|
||||
// Popup for Adding Server
|
||||
if let InputMode::Adding(state) = &app.input_mode {
|
||||
let block = Block::default().borders(Borders::ALL).title(" Add New Connection ");
|
||||
let area = centered_rect(60, 40, size);
|
||||
f.render_widget(Clear, area); // Clear the background
|
||||
f.render_widget(block, area);
|
||||
|
||||
let input_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(2)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3), // Name
|
||||
Constraint::Length(3), // User
|
||||
Constraint::Length(3), // Host
|
||||
Constraint::Length(3), // Port
|
||||
Constraint::Min(1),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(area);
|
||||
|
||||
let fields = [
|
||||
("Name", &state.name),
|
||||
("User (default: root)", &state.user),
|
||||
("Host/IP", &state.host),
|
||||
("Port (default: 22)", &state.port),
|
||||
];
|
||||
|
||||
for (i, (label, value)) in fields.iter().enumerate() {
|
||||
let mut style = Style::default();
|
||||
if state.field_idx == i {
|
||||
style = style.fg(Color::Yellow);
|
||||
}
|
||||
let input = Paragraph::new(value.as_str())
|
||||
.style(style)
|
||||
.block(Block::default().borders(Borders::ALL).title(*label));
|
||||
f.render_widget(input, input_layout[i]);
|
||||
|
||||
// Show cursor in the active input field
|
||||
if state.field_idx == i {
|
||||
f.set_cursor(
|
||||
input_layout[i].x + value.len() as u16 + 1, // Position after the text
|
||||
input_layout[i].y + 1, // Middle of the input area
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Popup for Editing Server
|
||||
if let InputMode::Editing(state) = &app.input_mode {
|
||||
let block = Block::default().borders(Borders::ALL).title(" Edit Connection ");
|
||||
let area = centered_rect(60, 40, size);
|
||||
f.render_widget(Clear, area); // Clear the background
|
||||
f.render_widget(block, area);
|
||||
|
||||
let input_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(2)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3), // Name
|
||||
Constraint::Length(3), // User
|
||||
Constraint::Length(3), // Host
|
||||
Constraint::Length(3), // Port
|
||||
Constraint::Min(1),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(area);
|
||||
|
||||
let fields = [
|
||||
("Name", &state.name),
|
||||
("User (default: root)", &state.user),
|
||||
("Host/IP", &state.host),
|
||||
("Port (default: 22)", &state.port),
|
||||
];
|
||||
|
||||
for (i, (label, value)) in fields.iter().enumerate() {
|
||||
let mut style = Style::default();
|
||||
if state.field_idx == i {
|
||||
style = style.fg(Color::Yellow);
|
||||
}
|
||||
let input = Paragraph::new(value.as_str())
|
||||
.style(style)
|
||||
.block(Block::default().borders(Borders::ALL).title(*label));
|
||||
f.render_widget(input, input_layout[i]);
|
||||
|
||||
// Show cursor in the active input field
|
||||
if state.field_idx == i {
|
||||
f.set_cursor(
|
||||
input_layout[i].x + value.len() as u16 + 1, // Position after the text
|
||||
input_layout[i].y + 1, // Middle of the input area
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
||||
let popup_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
Constraint::Percentage(percent_y),
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(r);
|
||||
|
||||
Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
Constraint::Percentage(percent_x),
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(popup_layout[1])[1]
|
||||
}
|
||||
Reference in New Issue
Block a user