refactor: round borders, Y/N delete confirm, fix selected row styling
This commit is contained in:
@@ -25,7 +25,7 @@ pub fn draw_dialog(
|
||||
Block::default()
|
||||
.title(title.to_string())
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Plain)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(border_color))
|
||||
.bg(PANEL),
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn draw_input(
|
||||
Block::default()
|
||||
.title(title.to_string())
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Plain)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(if focused {
|
||||
Style::default().fg(ACCENT)
|
||||
} else {
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn panel(title: impl Into<String>) -> Block<'static> {
|
||||
Block::default()
|
||||
.title(Line::from(format!(" {} ", title.into())).fg(TEXT).bold())
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Plain)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(DIM_BORDER))
|
||||
.bg(PANEL)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ pub fn panel_accent(title: impl Into<String>) -> Block<'static> {
|
||||
Block::default()
|
||||
.title(Line::from(format!(" {} ", title.into())).fg(ACCENT).bold())
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Plain)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(ACCENT))
|
||||
.bg(PANEL)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::ui::{GREEN, PANEL_ALT, RED};
|
||||
use ratatui::{
|
||||
style::{Style, Stylize},
|
||||
widgets::{Block, Borders, Clear, Paragraph, Widget},
|
||||
widgets::{Block, BorderType, Borders, Clear, Paragraph, Widget},
|
||||
};
|
||||
|
||||
pub fn draw_toast(frame: &mut ratatui::Frame<'_>, message: &str, success: bool) {
|
||||
@@ -19,6 +19,7 @@ pub fn draw_toast(frame: &mut ratatui::Frame<'_>, message: &str, success: bool)
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(border_color))
|
||||
.bg(PANEL_ALT),
|
||||
)
|
||||
|
||||
@@ -12,6 +12,6 @@ pub fn draw_delete_confirm(frame: &mut ratatui::Frame<'_>, app: &App) {
|
||||
7,
|
||||
RED,
|
||||
" Confirm Delete ",
|
||||
&format!("Delete connection '{name}'?\n\n Enter confirm · Esc cancel"),
|
||||
&format!("Delete connection '{name}'?\n\n [Y] Yes · [N] No"),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ fn form_hints() -> Vec<Hint> {
|
||||
|
||||
fn delete_hints() -> Vec<Hint> {
|
||||
vec![
|
||||
Hint { key: "Enter", desc: "confirm" },
|
||||
Hint { key: "Esc", desc: "cancel" },
|
||||
Hint { key: "Y", desc: "yes" },
|
||||
Hint { key: "N", desc: "no" },
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
+22
-11
@@ -1,6 +1,5 @@
|
||||
use crate::app::{App, Mode};
|
||||
use crate::ui::component::common::layout::centered_rect;
|
||||
use crate::ui::{ACCENT, PANEL, SELECTED_BG, TEXT};
|
||||
use crate::ui::{ACCENT, MUTED, PANEL, SELECTED_BG, TEXT};
|
||||
|
||||
use super::View;
|
||||
|
||||
@@ -10,7 +9,8 @@ use ratatui::{
|
||||
Frame,
|
||||
layout::Rect,
|
||||
style::{Modifier, Style, Stylize},
|
||||
widgets::{Block, Borders, Clear, ListItem, ListState},
|
||||
text::{Line, Span},
|
||||
widgets::{Block, BorderType, Borders, Clear, ListState},
|
||||
};
|
||||
|
||||
const ACTIONS: &[(&str, &str)] = &[
|
||||
@@ -24,17 +24,27 @@ const ACTIONS: &[(&str, &str)] = &[
|
||||
pub struct ActionMenuView;
|
||||
|
||||
impl View for ActionMenuView {
|
||||
fn draw(&self, frame: &mut Frame<'_>, _app: &App, _area: Rect) {
|
||||
let width = 44u16;
|
||||
let height = (ACTIONS.len() as u16) + 4;
|
||||
let area = centered_rect(width, height, frame.area());
|
||||
fn draw(&self, frame: &mut Frame<'_>, _app: &App, area: Rect) {
|
||||
let list_width = 52u16.min(area.width.saturating_sub(4));
|
||||
let list_height = (ACTIONS.len() as u16 + 4).min(area.height);
|
||||
let x = area.x + (area.width.saturating_sub(list_width)) / 2;
|
||||
let y = area.y + (area.height.saturating_sub(list_height)) / 2;
|
||||
let list_area = Rect {
|
||||
x,
|
||||
y,
|
||||
width: list_width,
|
||||
height: list_height,
|
||||
};
|
||||
|
||||
frame.render_widget(Clear, area);
|
||||
frame.render_widget(Clear, list_area);
|
||||
|
||||
let items: Vec<ListItem<'_>> = ACTIONS
|
||||
let items: Vec<Line<'_>> = ACTIONS
|
||||
.iter()
|
||||
.map(|(label, desc)| {
|
||||
ListItem::new(format!(" {label:<14}{desc}"))
|
||||
Line::from(vec![
|
||||
Span::styled(format!(" {label:<14}"), Style::default().fg(TEXT)),
|
||||
Span::styled(desc.to_string(), Style::default().fg(MUTED)),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -44,6 +54,7 @@ impl View for ActionMenuView {
|
||||
.title(" Actions ")
|
||||
.title_style(Style::default().fg(ACCENT).bold())
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(ACCENT))
|
||||
.bg(PANEL),
|
||||
)
|
||||
@@ -58,7 +69,7 @@ impl View for ActionMenuView {
|
||||
let mut state = ListState::default();
|
||||
state.select(Some(_app.session.action_menu.cursor));
|
||||
|
||||
frame.render_stateful_widget(list, area, &mut state);
|
||||
frame.render_stateful_widget(list, list_area, &mut state);
|
||||
}
|
||||
|
||||
fn handle_key(&self, app: &mut App, key: KeyEvent) -> Result<()> {
|
||||
|
||||
@@ -74,7 +74,11 @@ fn draw_credentials(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
Row::new([
|
||||
Cell::from(format!("{} {}", if selected { ">" } else { " " }, (*name)))
|
||||
.style(style),
|
||||
Cell::from(format!("● {kind_text}")).style(Style::default().fg(dot_color)),
|
||||
Cell::from(format!("● {kind_text}")).style(if selected {
|
||||
Style::default().fg(dot_color).bg(SELECTED_BG)
|
||||
} else {
|
||||
Style::default().fg(dot_color)
|
||||
}),
|
||||
Cell::from(ref_text).style(style),
|
||||
])
|
||||
})
|
||||
@@ -95,7 +99,7 @@ fn draw_credentials(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
.style(Style::default().fg(BLUE).add_modifier(Modifier::BOLD)),
|
||||
)
|
||||
.block(panel("Credentials"))
|
||||
.column_spacing(2)
|
||||
.column_spacing(0)
|
||||
.row_highlight_style(Style::default().bg(SELECTED_BG));
|
||||
frame.render_widget(table, area);
|
||||
}
|
||||
|
||||
+21
-12
@@ -181,7 +181,7 @@ pub fn draw_connection_list(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
.style(Style::default().fg(BLUE).add_modifier(Modifier::BOLD)),
|
||||
)
|
||||
.block(panel(title))
|
||||
.column_spacing(2)
|
||||
.column_spacing(0)
|
||||
.row_highlight_style(Style::default().bg(SELECTED_BG));
|
||||
frame.render_widget(table, area);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ fn connection_row(
|
||||
Style::default().fg(TEXT)
|
||||
};
|
||||
let is_shell = matches!(profile.kind, ConnectionType::Shell { .. });
|
||||
let type_badge = if is_shell { "[SHL]" } else { "[SSH]" };
|
||||
let type_badge = if is_shell { "SHL" } else { "SSH" };
|
||||
let badge_color = if is_shell { PURPLE } else { ACCENT };
|
||||
|
||||
let target = match &profile.kind {
|
||||
@@ -259,16 +259,23 @@ fn connection_row(
|
||||
_ => MUTED,
|
||||
};
|
||||
|
||||
let badge_style = if selected {
|
||||
Style::default().fg(badge_color).bg(SELECTED_BG).add_modifier(Modifier::BOLD)
|
||||
} else {
|
||||
Style::default().fg(crate::ui::BG).bg(badge_color).add_modifier(Modifier::BOLD)
|
||||
};
|
||||
|
||||
Row::new([
|
||||
Cell::from(format!("{marker} {}", display_name(name))).style(row_style),
|
||||
Cell::from(type_badge).style(
|
||||
Style::default()
|
||||
.fg(crate::ui::BG)
|
||||
.bg(badge_color)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Cell::from(Line::from(vec![
|
||||
Span::styled(format!(" {} ", type_badge), badge_style),
|
||||
])).style(row_style),
|
||||
Cell::from(target).style(row_style),
|
||||
Cell::from(auth_state).style(Style::default().fg(auth_color)),
|
||||
Cell::from(auth_state).style(if selected {
|
||||
Style::default().fg(auth_color).bg(SELECTED_BG)
|
||||
} else {
|
||||
Style::default().fg(auth_color)
|
||||
}),
|
||||
])
|
||||
.height(1)
|
||||
}
|
||||
@@ -295,7 +302,7 @@ pub fn draw_detail_panel(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
let mut lines: Vec<Line> = Vec::new();
|
||||
|
||||
let is_shell = matches!(profile.kind, ConnectionType::Shell { .. });
|
||||
let badge = if is_shell { "[SHL]" } else { "[SSH]" };
|
||||
let badge = if is_shell { "SHL" } else { "SSH" };
|
||||
let badge_color = if is_shell { PURPLE } else { ACCENT };
|
||||
lines.push(Line::raw(""));
|
||||
lines.push(Line::from(vec![
|
||||
@@ -553,14 +560,16 @@ impl View for DeleteConfirmView {
|
||||
|
||||
fn handle_key(&self, app: &mut App, key: KeyEvent) -> Result<()> {
|
||||
match key.code {
|
||||
KeyCode::Esc => app.session.mode = Mode::Home,
|
||||
KeyCode::Enter => {
|
||||
KeyCode::Char('y') | KeyCode::Char('Y') => {
|
||||
match app.delete_selected() {
|
||||
Ok(()) => app.toast("deleted", true),
|
||||
Err(err) => app.toast(err.to_string(), false),
|
||||
}
|
||||
app.session.mode = Mode::Home;
|
||||
}
|
||||
KeyCode::Esc | KeyCode::Char('n') | KeyCode::Char('N') => {
|
||||
app.session.mode = Mode::Home;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
+14
-3
@@ -69,8 +69,13 @@ fn draw_import(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
.as_ref()
|
||||
.map(|c| format!("conflict: {}", c.name))
|
||||
.unwrap_or_else(|| "-".to_string());
|
||||
let check_cell_style = if selected_row {
|
||||
Style::default().bg(SELECTED_BG)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
rows.push(Row::new([
|
||||
Cell::from(if checked { " [x]" } else { " [ ]" }).style(check_style),
|
||||
Cell::from(if checked { " [x]" } else { " [ ]" }).style(check_style.patch(check_cell_style)),
|
||||
Cell::from(item.name.clone()).style(style),
|
||||
Cell::from(item.path.display().to_string()).style(style),
|
||||
Cell::from(status).style(style),
|
||||
@@ -98,8 +103,13 @@ fn draw_import(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
} else {
|
||||
Style::default().fg(MUTED)
|
||||
};
|
||||
let check_cell_style = if selected_row {
|
||||
Style::default().bg(SELECTED_BG)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
rows.push(Row::new([
|
||||
Cell::from(if checked { " [x]" } else { " [ ]" }).style(check_style),
|
||||
Cell::from(if checked { " [x]" } else { " [ ]" }).style(check_style.patch(check_cell_style)),
|
||||
Cell::from(item.name.clone()).style(style),
|
||||
Cell::from(format!("{}@{}:{}", item.user, item.host, item.port)).style(style),
|
||||
Cell::from(
|
||||
@@ -146,7 +156,8 @@ fn draw_import(frame: &mut Frame<'_>, app: &App, area: Rect) {
|
||||
"Import",
|
||||
"Space toggle a all A none Enter import Esc cancel",
|
||||
))
|
||||
.column_spacing(2);
|
||||
.column_spacing(0)
|
||||
.row_highlight_style(Style::default().bg(SELECTED_BG));
|
||||
frame.render_widget(table, area);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user