chore: updated TUI interface 4a904432
Steve · 2026-02-20 00:00 1 file(s) · +94 −17
src/tui.rs +94 −17
2 2
use crossterm::event::{self, Event, KeyCode, KeyModifiers};
3 3
use ratatui::{
4 4
    DefaultTerminal,
5 -
    layout::{Constraint, Layout},
5 +
    layout::{Alignment, Constraint, Layout},
6 6
    style::{Color, Modifier, Style},
7 7
    text::{Line, Span, Text},
8 8
    widgets::{Block, Borders, Clear, List, ListItem, ListState, Paragraph, Widget},
33 33
    focus: Focus,
34 34
    content_scroll: u16,
35 35
    show_help: bool,
36 +
    confirm_delete: bool,
36 37
    syntax_set: SyntaxSet,
37 38
    theme: Theme,
38 39
    create_name: String,
60 61
            focus: Focus::List,
61 62
            content_scroll: 0,
62 63
            show_help: false,
64 +
            confirm_delete: false,
63 65
            syntax_set,
64 66
            theme,
65 67
            create_name: String::new(),
439 441
                    let form_layout = Layout::vertical([
440 442
                        Constraint::Length(3),
441 443
                        Constraint::Min(1),
442 -
                        Constraint::Length(1),
443 444
                    ])
444 445
                    .split(inner);
445 446
495 496
                        _ => {}
496 497
                    }
497 498
498 -
                    let hint = Paragraph::new(Line::from(vec![
499 -
                        Span::styled("Tab", Style::default().fg(Color::Yellow)),
500 -
                        Span::raw(" switch field  "),
501 -
                        Span::styled("Ctrl+S", Style::default().fg(Color::Yellow)),
502 -
                        Span::raw(" save  "),
503 -
                        Span::styled("Esc", Style::default().fg(Color::Yellow)),
504 -
                        Span::raw(" cancel"),
505 -
                    ]));
506 -
                    frame.render_widget(hint, form_layout[2]);
507 499
                }
508 500
                _ => {
509 501
                    let highlighted = match app.selected_snippet() {
524 516
                }
525 517
            }
526 518
519 +
            let hints = match app.focus {
520 +
                Focus::List => Line::from(vec![
521 +
                    Span::styled("j/k", Style::default().fg(Color::Yellow)),
522 +
                    Span::raw(": Navigate  "),
523 +
                    Span::styled("Enter", Style::default().fg(Color::Yellow)),
524 +
                    Span::raw(": View  "),
525 +
                    Span::styled("y", Style::default().fg(Color::Yellow)),
526 +
                    Span::raw(": Copy  "),
527 +
                    Span::styled("d", Style::default().fg(Color::Yellow)),
528 +
                    Span::raw(": Delete  "),
529 +
                    Span::styled("c", Style::default().fg(Color::Yellow)),
530 +
                    Span::raw(": Create  "),
531 +
                    Span::styled("?", Style::default().fg(Color::Yellow)),
532 +
                    Span::raw(": Help  "),
533 +
                    Span::styled("q", Style::default().fg(Color::Yellow)),
534 +
                    Span::raw(": Quit"),
535 +
                ]),
536 +
                Focus::Content => Line::from(vec![
537 +
                    Span::styled("j/k", Style::default().fg(Color::Yellow)),
538 +
                    Span::raw(": Scroll  "),
539 +
                    Span::styled("y", Style::default().fg(Color::Yellow)),
540 +
                    Span::raw(": Copy  "),
541 +
                    Span::styled("Esc", Style::default().fg(Color::Yellow)),
542 +
                    Span::raw(": Back  "),
543 +
                    Span::styled("?", Style::default().fg(Color::Yellow)),
544 +
                    Span::raw(": Help"),
545 +
                ]),
546 +
                Focus::CreateName | Focus::CreateContent => Line::from(vec![
547 +
                    Span::styled("Tab", Style::default().fg(Color::Yellow)),
548 +
                    Span::raw(": Switch field  "),
549 +
                    Span::styled("Ctrl+S", Style::default().fg(Color::Yellow)),
550 +
                    Span::raw(": Save  "),
551 +
                    Span::styled("Esc", Style::default().fg(Color::Yellow)),
552 +
                    Span::raw(": Cancel"),
553 +
                ]),
554 +
            };
555 +
            frame.render_widget(Paragraph::new(hints), outer[1]);
556 +
527 557
            if let Some((msg, _)) = &app.status_message {
528 -
                let status = Paragraph::new(Text::raw(msg.as_str()))
529 -
                    .style(Style::default().fg(Color::Green).add_modifier(Modifier::BOLD));
530 -
                frame.render_widget(status, outer[1]);
558 +
                let area = frame.area();
559 +
                let msg_width = (msg.len() as u16 + 4).max(20).min(area.width.saturating_sub(4));
560 +
                let popup_area = ratatui::layout::Rect {
561 +
                    x: (area.width.saturating_sub(msg_width)) / 2,
562 +
                    y: (area.height.saturating_sub(3)) / 2,
563 +
                    width: msg_width,
564 +
                    height: 3,
565 +
                };
566 +
                Clear.render(popup_area, frame.buffer_mut());
567 +
                let status_popup = Paragraph::new(Line::from(msg.as_str()))
568 +
                    .style(Style::default().fg(Color::Green).add_modifier(Modifier::BOLD))
569 +
                    .alignment(Alignment::Center)
570 +
                    .block(
571 +
                        Block::default()
572 +
                            .borders(Borders::ALL)
573 +
                            .border_style(Style::default().fg(Color::Green)),
574 +
                    );
575 +
                frame.render_widget(status_popup, popup_area);
576 +
            }
577 +
578 +
            if app.confirm_delete {
579 +
                let delete_msg = match app.selected_snippet() {
580 +
                    Some(s) => format!("Delete {}? (y/n)", s.name),
581 +
                    None => "Delete snippet? (y/n)".to_string(),
582 +
                };
583 +
                let area = frame.area();
584 +
                let msg_width = (delete_msg.len() as u16 + 4).max(24).min(area.width.saturating_sub(4));
585 +
                let popup_area = ratatui::layout::Rect {
586 +
                    x: (area.width.saturating_sub(msg_width)) / 2,
587 +
                    y: (area.height.saturating_sub(3)) / 2,
588 +
                    width: msg_width,
589 +
                    height: 3,
590 +
                };
591 +
                Clear.render(popup_area, frame.buffer_mut());
592 +
                let confirm_popup = Paragraph::new(Line::from(delete_msg))
593 +
                    .style(Style::default().fg(Color::Red).add_modifier(Modifier::BOLD))
594 +
                    .alignment(Alignment::Center)
595 +
                    .block(
596 +
                        Block::default()
597 +
                            .borders(Borders::ALL)
598 +
                            .border_style(Style::default().fg(Color::Red)),
599 +
                    );
600 +
                frame.render_widget(confirm_popup, popup_area);
531 601
            }
532 602
533 603
            if app.show_help {
534 604
                let area = frame.area();
535 -
                let popup_width = 44u16.min(area.width.saturating_sub(4));
536 -
                let popup_height = 20u16.min(area.height.saturating_sub(4));
605 +
                let popup_width = 34u16.min(area.width.saturating_sub(4));
606 +
                let popup_height = 17u16.min(area.height.saturating_sub(4));
537 607
                let popup_area = ratatui::layout::Rect {
538 608
                    x: (area.width.saturating_sub(popup_width)) / 2,
539 609
                    y: (area.height.saturating_sub(popup_height)) / 2,
681 751
            if let Event::Key(key) = event::read()? {
682 752
                if app.show_help {
683 753
                    app.show_help = false;
754 +
                } else if app.status_message.is_some() {
755 +
                    app.status_message = None;
756 +
                } else if app.confirm_delete {
757 +
                    if key.code == KeyCode::Char('y') {
758 +
                        app.delete_selected(backend);
759 +
                    }
760 +
                    app.confirm_delete = false;
684 761
                } else {
685 762
                    match app.focus {
686 763
                        Focus::List => match key.code {
689 766
                            KeyCode::Char('k') | KeyCode::Up => app.move_up(),
690 767
                            KeyCode::Char('y') => app.copy_selected(),
691 768
                            KeyCode::Char('Y') => app.copy_link(),
692 -
                            KeyCode::Char('d') => app.delete_selected(backend),
769 +
                            KeyCode::Char('d') => app.confirm_delete = true,
693 770
                            KeyCode::Char('c') => app.start_create(),
694 771
                            KeyCode::Char('o') => app.open_in_browser(),
695 772
                            KeyCode::Char('r') if app.is_remote => app.refresh(backend),