node_launchpad/components/
header.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use crate::style::{GHOST_WHITE, LIGHT_PERIWINKLE, VIVID_SKY_BLUE};
10use ratatui::{prelude::*, widgets::*};
11
12pub enum SelectedMenuItem {
13    Status,
14    Options,
15    Help,
16}
17
18pub struct Header {
19    launchpad_version_str: String,
20}
21
22impl Default for Header {
23    fn default() -> Self {
24        let version_str = env!("CARGO_PKG_VERSION");
25        Self {
26            launchpad_version_str: version_str.to_string(),
27        }
28    }
29}
30
31impl Header {
32    pub fn new() -> Self {
33        Self::default()
34    }
35}
36
37impl StatefulWidget for Header {
38    type State = SelectedMenuItem;
39
40    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
41        let layout = Layout::default()
42            .direction(Direction::Vertical)
43            .constraints(vec![Constraint::Length(1)])
44            .split(area);
45
46        // Define content of the header
47        let application_text = Span::styled(
48            format!(" Autonomi Node Launchpad (v{})", self.launchpad_version_str),
49            Style::default().fg(LIGHT_PERIWINKLE),
50        );
51
52        // Determine the color for each part of the menu based on the state
53        let status_color = if matches!(state, SelectedMenuItem::Status) {
54            VIVID_SKY_BLUE
55        } else {
56            GHOST_WHITE
57        };
58
59        let options_color = if matches!(state, SelectedMenuItem::Options) {
60            VIVID_SKY_BLUE
61        } else {
62            GHOST_WHITE
63        };
64
65        let help_color = if matches!(state, SelectedMenuItem::Help) {
66            VIVID_SKY_BLUE
67        } else {
68            GHOST_WHITE
69        };
70
71        // Create styled spans for each part of the menu
72        let status = Span::styled("[S]tatus", Style::default().fg(status_color));
73        let options = Span::styled("[O]ptions", Style::default().fg(options_color));
74        let help = Span::styled("[H]elp", Style::default().fg(help_color));
75
76        // Combine the menu parts with separators
77        let menu = vec![
78            status,
79            Span::raw(" | ").fg(VIVID_SKY_BLUE),
80            options,
81            Span::raw(" | ").fg(VIVID_SKY_BLUE),
82            help,
83        ];
84
85        // Calculate spacing between title and menu items
86        let total_width = (layout[0].width - 1) as usize;
87        let spaces = " ".repeat(total_width.saturating_sub(
88            application_text.content.len() + menu.iter().map(|s| s.width()).sum::<usize>(),
89        ));
90
91        // Create a line with left and right text
92        let line = Line::from(
93            vec![application_text, Span::raw(spaces)]
94                .into_iter()
95                .chain(menu)
96                .collect::<Vec<_>>(),
97        );
98
99        // Create a Paragraph widget to display the line
100        let paragraph = Paragraph::new(line).block(Block::default().borders(Borders::NONE));
101
102        paragraph.render(layout[0], buf);
103    }
104}