node_launchpad/components/
header.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2024 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

use crate::style::{GHOST_WHITE, LIGHT_PERIWINKLE, VIVID_SKY_BLUE};
use ratatui::{prelude::*, widgets::*};

pub enum SelectedMenuItem {
    Status,
    Options,
    Help,
}

pub struct Header {
    launchpad_version_str: String,
}

impl Default for Header {
    fn default() -> Self {
        let version_str = env!("CARGO_PKG_VERSION");
        Self {
            launchpad_version_str: version_str.to_string(),
        }
    }
}

impl Header {
    pub fn new() -> Self {
        Self::default()
    }
}

impl StatefulWidget for Header {
    type State = SelectedMenuItem;

    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
        let layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(vec![Constraint::Length(1)])
            .split(area);

        // Define content of the header
        let application_text = Span::styled(
            format!(" Autonomi Node Launchpad (v{})", self.launchpad_version_str),
            Style::default().fg(LIGHT_PERIWINKLE),
        );

        // Determine the color for each part of the menu based on the state
        let status_color = if matches!(state, SelectedMenuItem::Status) {
            VIVID_SKY_BLUE
        } else {
            GHOST_WHITE
        };

        let options_color = if matches!(state, SelectedMenuItem::Options) {
            VIVID_SKY_BLUE
        } else {
            GHOST_WHITE
        };

        let help_color = if matches!(state, SelectedMenuItem::Help) {
            VIVID_SKY_BLUE
        } else {
            GHOST_WHITE
        };

        // Create styled spans for each part of the menu
        let status = Span::styled("[S]tatus", Style::default().fg(status_color));
        let options = Span::styled("[O]ptions", Style::default().fg(options_color));
        let help = Span::styled("[H]elp", Style::default().fg(help_color));

        // Combine the menu parts with separators
        let menu = vec![
            status,
            Span::raw(" | ").fg(VIVID_SKY_BLUE),
            options,
            Span::raw(" | ").fg(VIVID_SKY_BLUE),
            help,
        ];

        // Calculate spacing between title and menu items
        let total_width = (layout[0].width - 1) as usize;
        let spaces = " ".repeat(total_width.saturating_sub(
            application_text.content.len() + menu.iter().map(|s| s.width()).sum::<usize>(),
        ));

        // Create a line with left and right text
        let line = Line::from(
            vec![application_text, Span::raw(spaces)]
                .into_iter()
                .chain(menu)
                .collect::<Vec<_>>(),
        );

        // Create a Paragraph widget to display the line
        let paragraph = Paragraph::new(line).block(Block::default().borders(Borders::NONE));

        paragraph.render(layout[0], buf);
    }
}