···1+use ratatui::layout::{Constraint, Direction, Layout, Rect};
2+3+/// Layout manager for slide presentation
4+///
5+/// Calculates screen layout with main slide area, optional notes panel, and status bar.
6+pub struct SlideLayout {
7+ show_notes: bool,
8+}
9+10+impl SlideLayout {
11+ pub fn new(show_notes: bool) -> Self {
12+ Self { show_notes }
13+ }
14+15+ /// Calculate layout areas for the slide viewer
16+ ///
17+ /// Returns (main_area, notes_area, status_area) where notes_area is None if notes are hidden.
18+ pub fn calculate(&self, area: Rect) -> (Rect, Option<Rect>, Rect) {
19+ let vertical_chunks = Layout::default()
20+ .direction(Direction::Vertical)
21+ .constraints([Constraint::Min(3), Constraint::Length(1)])
22+ .split(area);
23+24+ let content_area = vertical_chunks[0];
25+ let status_area = vertical_chunks[1];
26+27+ if self.show_notes {
28+ let horizontal_chunks = Layout::default()
29+ .direction(Direction::Horizontal)
30+ .constraints([Constraint::Percentage(60), Constraint::Percentage(40)])
31+ .split(content_area);
32+33+ (horizontal_chunks[0], Some(horizontal_chunks[1]), status_area)
34+ } else {
35+ (content_area, None, status_area)
36+ }
37+ }
38+39+ /// Update notes visibility
40+ pub fn set_show_notes(&mut self, show: bool) {
41+ self.show_notes = show;
42+ }
43+44+ /// Check if notes are visible
45+ pub fn is_showing_notes(&self) -> bool {
46+ self.show_notes
47+ }
48+}
49+50+impl Default for SlideLayout {
51+ fn default() -> Self {
52+ Self { show_notes: false }
53+ }
54+}
55+56+#[cfg(test)]
57+mod tests {
58+ use super::*;
59+60+ #[test]
61+ fn layout_without_notes() {
62+ let layout = SlideLayout::new(false);
63+ let area = Rect::new(0, 0, 100, 50);
64+ let (main, notes, status) = layout.calculate(area);
65+66+ assert!(notes.is_none());
67+ assert_eq!(status.height, 1);
68+ assert!(main.height > status.height);
69+ }
70+71+ #[test]
72+ fn layout_with_notes() {
73+ let layout = SlideLayout::new(true);
74+ let area = Rect::new(0, 0, 100, 50);
75+ let (main, notes, status) = layout.calculate(area);
76+77+ assert!(notes.is_some());
78+ let notes_area = notes.unwrap();
79+ assert!(main.width > notes_area.width);
80+ assert_eq!(main.height, notes_area.height);
81+ assert_eq!(status.height, 1);
82+ }
83+84+ #[test]
85+ fn layout_toggle_notes() {
86+ let mut layout = SlideLayout::default();
87+ assert!(!layout.is_showing_notes());
88+89+ layout.set_show_notes(true);
90+ assert!(layout.is_showing_notes());
91+92+ layout.set_show_notes(false);
93+ assert!(!layout.is_showing_notes());
94+ }
95+96+ #[test]
97+ fn layout_small_terminal() {
98+ let layout = SlideLayout::new(false);
99+ let area = Rect::new(0, 0, 20, 10);
100+ let (main, _notes, status) = layout.calculate(area);
101+102+ assert_eq!(status.height, 1);
103+ assert!(main.height >= 3);
104+ }
105+106+ #[test]
107+ fn layout_proportions_with_notes() {
108+ let layout = SlideLayout::new(true);
109+ let area = Rect::new(0, 0, 100, 50);
110+ let (main, notes, _status) = layout.calculate(area);
111+112+ let notes_area = notes.unwrap();
113+ let main_percentage = (main.width as f32 / area.width as f32) * 100.0;
114+ let notes_percentage = (notes_area.width as f32 / area.width as f32) * 100.0;
115+116+ assert!(main_percentage >= 55.0 && main_percentage <= 65.0);
117+ assert!(notes_percentage >= 35.0 && notes_percentage <= 45.0);
118+ }
119+}
+10-12
ui/src/lib.rs
···1-pub fn add(left: u64, right: u64) -> u64 {
2- left + right
3-}
45-#[cfg(test)]
6-mod tests {
7- use super::*;
89- #[test]
10- fn it_works() {
11- let result = add(2, 2);
12- assert_eq!(result, 4);
13- }
14-}
···1+pub mod layout;
2+pub mod renderer;
3+pub mod viewer;
45+pub use layout::SlideLayout;
6+pub use renderer::render_slide_content;
7+pub use viewer::SlideViewer;
89+pub use slides_core::{
10+ slide::{Block, Slide, TextSpan},
11+ theme::ThemeColors,
12+};
00