(&self, frame: &mut Frame, area: Rect)
| 134 | } |
| 135 | |
| 136 | fn render_tips(&self, frame: &mut Frame, area: Rect) { |
| 137 | if area.width == 0 || area.height == 0 { |
| 138 | return; |
| 139 | } |
| 140 | let theme = self.context.theme.read(); |
| 141 | let tip_width = area.width.min(HOME_MAX_CONTENT_WIDTH); |
| 142 | let left_pad = (area.width.saturating_sub(tip_width)) / 2; |
| 143 | let tip_area = Rect { |
| 144 | x: area.x + left_pad, |
| 145 | y: area.y, |
| 146 | width: tip_width, |
| 147 | height: area.height, |
| 148 | }; |
| 149 | if tip_area.height == 0 || tip_area.width == 0 { |
| 150 | return; |
| 151 | } |
| 152 | |
| 153 | let top_padding = 3u16.min(tip_area.height.saturating_sub(1)); |
| 154 | let tip_render_area = Rect { |
| 155 | x: tip_area.x, |
| 156 | y: tip_area.y.saturating_add(top_padding), |
| 157 | width: tip_area.width, |
| 158 | height: tip_area.height.saturating_sub(top_padding).max(1), |
| 159 | }; |
| 160 | |
| 161 | let slot = chrono::Utc::now() |
| 162 | .timestamp() |
| 163 | .div_euclid(TIP_ROTATE_SECONDS); |
| 164 | let tip_idx = slot.rem_euclid(HOME_TIPS.len() as i64) as usize; |
| 165 | let tip = HOME_TIPS |
| 166 | .get(tip_idx) |
| 167 | .copied() |
| 168 | .unwrap_or("Use /help to open command guide"); |
| 169 | let mut spans = vec![Span::styled("● Tip ", Style::default().fg(theme.warning))]; |
| 170 | spans.extend(parse_tip_highlights(tip, &theme)); |
| 171 | let paragraph = Paragraph::new(Line::from(spans)); |
| 172 | |
| 173 | frame.render_widget(paragraph, tip_render_area); |
| 174 | } |
| 175 | |
| 176 | fn render_footer(&self, frame: &mut Frame, area: Rect) { |
| 177 | if area.width == 0 || area.height == 0 { |
no test coverage detected