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