node_launchpad/components/
help.rs1use super::header::SelectedMenuItem;
2use color_eyre::eyre::Result;
3use ratatui::{
4 layout::{Constraint, Direction, Layout, Rect},
5 style::{Style, Stylize},
6 text::Span,
7 widgets::{Block, Borders, Padding},
8 Frame,
9};
10use tokio::sync::mpsc::UnboundedSender;
11
12use super::Component;
13use crate::{
14 action::Action,
15 components::header::Header,
16 mode::{InputMode, Scene},
17 style::{COOL_GREY, GHOST_WHITE, VIVID_SKY_BLUE},
18 widgets::hyperlink::Hyperlink,
19};
20
21#[derive(Clone)]
22pub struct Help {
23 pub active: bool,
24 pub action_tx: Option<UnboundedSender<Action>>,
25}
26
27impl Help {
28 pub async fn new() -> Result<Self> {
29 Ok(Self {
30 active: false,
31 action_tx: None,
32 })
33 }
34}
35
36impl Component for Help {
37 fn init(&mut self, _area: Rect) -> Result<()> {
38 Ok(())
39 }
40
41 fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
42 if !self.active {
43 return Ok(());
44 }
45 let layout = Layout::default()
47 .direction(Direction::Vertical)
48 .constraints(vec![Constraint::Length(1), Constraint::Length(9)])
49 .split(area);
50
51 let header = Header::new();
53 f.render_stateful_widget(header, layout[0], &mut SelectedMenuItem::Help);
54
55 let columns_layout = Layout::default()
60 .direction(Direction::Horizontal)
61 .constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
62 .split(layout[1]);
63
64 let padded_area_left = Rect {
65 x: columns_layout[0].x + 2,
66 y: columns_layout[0].y + 2,
67 width: columns_layout[0].width - 2,
68 height: columns_layout[0].height - 2,
69 };
70
71 let left_column = Layout::default()
72 .direction(Direction::Vertical)
73 .constraints(vec![
74 Constraint::Max(1),
75 Constraint::Max(2),
76 Constraint::Max(1),
77 Constraint::Max(2),
78 ])
79 .split(padded_area_left);
80
81 let padded_area_right = Rect {
82 x: columns_layout[1].x + 2,
83 y: columns_layout[1].y + 2,
84 width: columns_layout[1].width - 2,
85 height: columns_layout[1].height - 2,
86 };
87 let right_column = Layout::default()
88 .direction(Direction::Vertical)
89 .constraints(vec![
90 Constraint::Max(1),
91 Constraint::Max(2),
92 Constraint::Max(1),
93 Constraint::Max(2),
94 ])
95 .split(padded_area_right);
96
97 let quickstart_guide_link = Hyperlink::new(
98 Span::styled(
99 "autonomi.com/getstarted",
100 Style::default().fg(VIVID_SKY_BLUE).underlined(),
101 ),
102 "https://autonomi.com/getstarted",
103 );
104 let terms_and_conditions_link = Hyperlink::new(
105 Span::styled(
106 "autonomi.com/terms",
107 Style::default().fg(VIVID_SKY_BLUE).underlined(),
108 ),
109 "https://autonomi.com/terms",
110 );
111 let get_direct_support_link = Hyperlink::new(
112 Span::styled(
113 "autonomi.com/support",
114 Style::default().fg(VIVID_SKY_BLUE).underlined(),
115 ),
116 "https://autonomi.com/support",
117 );
118 let download_latest_link = Hyperlink::new(
119 Span::styled(
120 "autonomi.com/downloads",
121 Style::default().fg(VIVID_SKY_BLUE).underlined(),
122 ),
123 "https://autonomi.com/downloads",
124 );
125
126 let block = Block::new()
127 .borders(Borders::ALL)
128 .border_style(Style::default().fg(COOL_GREY))
129 .padding(Padding::uniform(1))
130 .title(" Get Help & Support ")
131 .bold()
132 .title_style(Style::default().bold().fg(GHOST_WHITE));
133
134 f.render_widget(
136 Span::styled(
137 "Read the quick start guides:",
138 Style::default().fg(GHOST_WHITE),
139 ),
140 left_column[0],
141 );
142 f.render_widget_ref(quickstart_guide_link, left_column[1]);
143 f.render_widget(
144 Span::styled("Get Direct Support:", Style::default().fg(GHOST_WHITE)),
145 left_column[2],
146 );
147 f.render_widget_ref(get_direct_support_link, left_column[3]);
148 f.render_widget(
149 Span::styled(
150 "Download the latest launchpad:",
151 Style::default().fg(GHOST_WHITE),
152 ),
153 right_column[0],
154 );
155 f.render_widget_ref(download_latest_link, right_column[1]);
156 f.render_widget(
157 Span::styled("Terms & Conditions:", Style::default().fg(GHOST_WHITE)),
158 right_column[2],
159 );
160 f.render_widget_ref(terms_and_conditions_link, right_column[3]);
161
162 f.render_widget(block, layout[1]);
163
164 Ok(())
165 }
166
167 fn update(&mut self, action: Action) -> Result<Option<Action>> {
168 if let Action::SwitchScene(scene) = action {
169 if let Scene::Help = scene {
170 self.active = true;
171 return Ok(Some(Action::SwitchInputMode(InputMode::Navigation)));
173 } else {
174 self.active = false;
175 }
176 }
177 Ok(None)
178 }
179}