diff --git a/client/config.toml b/client/config.toml index be88752..a10e1e7 100644 --- a/client/config.toml +++ b/client/config.toml @@ -54,5 +54,5 @@ save_and_quit = ["wq"] revert = ["r"] [colors] -theme = "light" +theme = "dark" # Options: "light", "dark", "high_contrast" diff --git a/client/src/components1/handlers.rs b/client/src/components/handlers.rs similarity index 88% rename from client/src/components1/handlers.rs rename to client/src/components/handlers.rs index db0803e..fe27cea 100644 --- a/client/src/components1/handlers.rs +++ b/client/src/components/handlers.rs @@ -3,8 +3,10 @@ pub mod form; pub mod preview_card; pub mod command_line; pub mod status_line; +pub mod canvas; pub use command_line::render_command_line; pub use form::render_form; pub use preview_card::render_preview_card; pub use status_line::render_status_line; +pub use canvas::*; diff --git a/client/src/components/handlers/canvas.rs b/client/src/components/handlers/canvas.rs new file mode 100644 index 0000000..1afd085 --- /dev/null +++ b/client/src/components/handlers/canvas.rs @@ -0,0 +1,51 @@ +// src/components/handlers/canvas.rs +use ratatui::{ + widgets::{Paragraph, Block, Borders}, + layout::{Rect, Margin}, + style::Style, + text::Text, + Frame, +}; +use crate::config::colors::Theme; + +pub struct CanvasState<'a> { + pub content: Text<'a>, + pub cursor_position: (u16, u16), + pub scroll_offset: u16, +} + +pub fn render_canvas( + f: &mut Frame, + area: Rect, + state: &CanvasState, + theme: &Theme, + is_active: bool, + is_edit_mode: bool, + border_style: Style, +) { + // Render the container block + let container = Block::default() + .borders(Borders::ALL) + .border_style(border_style) + .style(Style::default().bg(theme.bg)); + + f.render_widget(container, area); + + // Inner content area + let inner_area = area.inner(Margin { + horizontal: 1, + vertical: 1, + }); + + // Render the content + let content = Paragraph::new(state.content.clone()) + .scroll((state.scroll_offset, 0)); + f.render_widget(content, inner_area); + + // Set cursor position if active + if is_active && is_edit_mode { + let cursor_x = inner_area.x + state.cursor_position.0; + let cursor_y = inner_area.y + state.cursor_position.1; + f.set_cursor_position((cursor_x, cursor_y)); + } +} diff --git a/client/src/components1/handlers/command_line.rs b/client/src/components/handlers/command_line.rs similarity index 100% rename from client/src/components1/handlers/command_line.rs rename to client/src/components/handlers/command_line.rs diff --git a/client/src/components/handlers/form.rs b/client/src/components/handlers/form.rs new file mode 100644 index 0000000..a5c7ca0 --- /dev/null +++ b/client/src/components/handlers/form.rs @@ -0,0 +1,154 @@ +// src/components/handlers/form.rs +use ratatui::{ + widgets::{Paragraph, Block, Borders}, + layout::{Layout, Constraint, Direction, Rect, Margin, Alignment}, + style::Style, + text::{Line, Span, Text}, + Frame, +}; +use crate::config::colors::Theme; +use crate::ui::form::FormState; +use crate::components::canvas::{self, CanvasState}; + +pub fn render_form( + f: &mut Frame, + area: Rect, + form_state: &FormState, + fields: &[&str], + current_field: &usize, + inputs: &[&String], + theme: &Theme, + is_edit_mode: bool, + total_count: u64, + current_position: u64, +) { + // Split the main area into canvas and container sections + let main_layout = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(3), // For header and controls + Constraint::Min(1), // For canvas + ]) + .split(area); + + // Render the header section + render_header(f, main_layout[0], theme, total_count, current_position); + + // Render the canvas area + render_canvas_area( + f, + main_layout[1], + form_state, + fields, + current_field, + inputs, + theme, + is_edit_mode, + ); +} + +fn render_header( + f: &mut Frame, + area: Rect, + theme: &Theme, + total_count: u64, + current_position: u64, +) { + // Create Adresar card + let adresar_card = Block::default() + .borders(Borders::ALL) + .border_style(Style::default().fg(theme.border)) + .title(" Adresar ") + .style(Style::default().bg(theme.bg).fg(theme.fg)); + + f.render_widget(adresar_card, area); + + // Define the inner area for the header content + let inner_area = area.inner(Margin { + horizontal: 1, + vertical: 1, + }); + + // Render the count and position + let count_position_text = format!("Total: {} | Current Position: {}", total_count, current_position); + let count_position_paragraph = Paragraph::new(count_position_text) + .style(Style::default().fg(theme.fg)) + .alignment(Alignment::Left); + f.render_widget(count_position_paragraph, inner_area); +} + +fn render_canvas_area( + f: &mut Frame, + area: Rect, + form_state: &FormState, + fields: &[&str], + current_field: &usize, + inputs: &[&String], + theme: &Theme, + is_edit_mode: bool, +) { + // Split canvas area into labels and inputs + let columns = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) + .split(area); + + // Render labels + for (i, field) in fields.iter().enumerate() { + let label = Paragraph::new(Line::from(Span::styled( + format!("{}:", field), + Style::default().fg(theme.fg), + ))); + f.render_widget(label, Rect { + x: columns[0].x, + y: columns[0].y + i as u16, + width: columns[0].width, + height: 1, + }); + } + + // Create canvas states for each input field + let canvas_states: Vec = inputs.iter().enumerate().map(|(i, input)| { + CanvasState { + content: Text::raw(input.as_str()), + cursor_position: if i == *current_field { + (form_state.current_cursor_pos as u16, 0) + } else { + (0, 0) + }, + scroll_offset: 0, + } + }).collect(); + + // Render input canvases + let input_height = area.height / fields.len() as u16; + for (i, state) in canvas_states.iter().enumerate() { + let is_active = i == *current_field; + let border_style = if is_edit_mode { + if form_state.has_unsaved_changes { + Style::default().fg(theme.warning) + } else { + Style::default().fg(theme.accent) + } + } else { + Style::default().fg(theme.secondary) + }; + + let canvas_area = Rect { + x: columns[1].x, + y: columns[1].y + i as u16 * input_height, + width: columns[1].width, + height: input_height, + }; + + canvas::render_canvas( + f, + canvas_area, + state, + theme, + is_active, + is_edit_mode, + border_style, + ); + } +} diff --git a/client/src/components1/handlers/preview_card.rs b/client/src/components/handlers/preview_card.rs similarity index 100% rename from client/src/components1/handlers/preview_card.rs rename to client/src/components/handlers/preview_card.rs diff --git a/client/src/components1/handlers/status_line.rs b/client/src/components/handlers/status_line.rs similarity index 98% rename from client/src/components1/handlers/status_line.rs rename to client/src/components/handlers/status_line.rs index e199418..efdc6f8 100644 --- a/client/src/components1/handlers/status_line.rs +++ b/client/src/components/handlers/status_line.rs @@ -1,4 +1,4 @@ -// src/client/components1/handlers/status_line.rs +// src/client/components/handlers/status_line.rs use ratatui::{ widgets::Paragraph, style::Style, diff --git a/client/src/components1/mod.rs b/client/src/components/mod.rs similarity index 68% rename from client/src/components1/mod.rs rename to client/src/components/mod.rs index 194f5cc..cbb0d2a 100644 --- a/client/src/components1/mod.rs +++ b/client/src/components/mod.rs @@ -1,4 +1,4 @@ -// src/components1/mod.rs +// src/components/mod.rs pub mod models; pub mod handlers; diff --git a/client/src/components1/models.rs b/client/src/components/models.rs similarity index 100% rename from client/src/components1/models.rs rename to client/src/components/models.rs diff --git a/client/src/components1/handlers/form.rs b/client/src/components1/handlers/form.rs deleted file mode 100644 index f390c15..0000000 --- a/client/src/components1/handlers/form.rs +++ /dev/null @@ -1,142 +0,0 @@ -// src/client/components1/handlers/form.rs -use ratatui::{ - widgets::{Paragraph, Block, Borders}, - layout::{Layout, Constraint, Direction, Rect, Margin, Alignment}, - style::Style, - text::{Line, Span}, - Frame, -}; -use crate::config::colors::Theme; -use crate::ui::form::FormState; - -pub fn render_form( - f: &mut Frame, - area: Rect, - form_state: &FormState, - fields: &[&str], - current_field: &usize, - inputs: &[&String], - theme: &Theme, - is_edit_mode: bool, - total_count: u64, - current_position: u64, -) { - // Create Adresar card - let adresar_card = Block::default() - .borders(Borders::ALL) - .border_style(Style::default().fg(theme.border)) - .title(" Adresar ") - .style(Style::default().bg(theme.bg).fg(theme.fg)); - - f.render_widget(adresar_card, area); - - // Define the inner area for the form (inside the card) - let inner_area = area.inner(Margin { - horizontal: 1, - vertical: 1, - }); - - // Create a vertical layout for the entire form content - let main_layout = Layout::default() - .direction(Direction::Vertical) - .constraints([ - Constraint::Length(1), // For count and position - Constraint::Min(1), // For form fields - ]) - .split(inner_area); - - // Render the count and position at the very top - let count_position_text = format!("Total: {} | Current Position: {}", total_count, current_position); - let count_position_paragraph = Paragraph::new(count_position_text) - .style(Style::default().fg(theme.fg)) - .alignment(Alignment::Left); - f.render_widget(count_position_paragraph, main_layout[0]); - - // Split the remaining space into label and input columns - let columns = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) - .split(main_layout[1]); - - // Create compact input container - let input_container = Block::default() - .borders(Borders::ALL) - .border_style(if is_edit_mode { - if form_state.has_unsaved_changes { - Style::default().fg(theme.warning) // Red color - } else { - Style::default().fg(theme.accent) // Blue color - } - } else { - Style::default().fg(theme.secondary) // Yellow color - }) - .style(Style::default().bg(theme.bg)); - - // Place the input container at the top - let input_container_area = Rect { - x: columns[1].x, - y: columns[1].y, - width: columns[1].width, - height: fields.len() as u16 + 2, // +2 for borders - }; - - f.render_widget(&input_container, input_container_area); - - // Input area inside borders - let input_area = input_container.inner(input_container_area); - - // Split the remaining area for the form inputs - let input_rows = Layout::default() - .direction(Direction::Vertical) - .constraints(vec![Constraint::Length(1); fields.len()]) - .split(input_area); - - // Render labels close to the border - for (i, field) in fields.iter().enumerate() { - let label = Paragraph::new(Line::from(Span::styled( - format!("{}:", field), - Style::default().fg(theme.fg), - ))); - f.render_widget(label, Rect { - x: columns[0].x, - y: input_container_area.y + 1 + i as u16, // Align with input rows - width: columns[0].width, - height: 1, - }); - } - - // Render inputs with left-aligned text and free cursor movement - for (i, input) in inputs.iter().enumerate() { - let is_active = i == *current_field; - - let input_display = Paragraph::new(input.as_str()) - .alignment(Alignment::Left) - .style(if is_active { - Style::default().fg(theme.highlight) - } else { - Style::default().fg(theme.fg) - }); - - f.render_widget(input_display, input_rows[i]); - - // Position cursor at the correct position in the active field - if is_active && is_edit_mode { // Move cursor logic inside the loop - let cursor_x = input_rows[i].x + input.len() as u16; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); // Updated to set_cursor_position - } - if is_active { - if is_edit_mode { - // Edit mode: cursor at current_cursor_pos instead of end - let cursor_x = input_rows[i].x + form_state.current_cursor_pos as u16; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); // Updated to set_cursor_position - } else { - // Read-only mode: cursor at current_cursor_pos - let cursor_x = input_rows[i].x + form_state.current_cursor_pos as u16; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); // Updated to set_cursor_position - } - } - } -} diff --git a/client/src/lib.rs b/client/src/lib.rs index 6b5e822..6a65abe 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -3,7 +3,7 @@ pub mod ui; pub mod tui; pub mod config; pub mod state; -pub mod components1; +pub mod components; pub mod modes; pub use ui::run_ui; diff --git a/client/src/ui/handlers/form.rs b/client/src/ui/handlers/form.rs index 5b0fae4..cf37bb5 100644 --- a/client/src/ui/handlers/form.rs +++ b/client/src/ui/handlers/form.rs @@ -1,6 +1,6 @@ // src/client/ui/handlers/form.rs -use crate::components1::render_form; +use crate::components::render_form; use crate::config::colors::Theme; use ratatui::layout::Rect; use ratatui::Frame; diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index 24bae58..c92f033 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -1,6 +1,6 @@ // src/client/ui/handlers/render.rs -use crate::components1::{render_command_line, render_preview_card, render_status_line}; +use crate::components::{render_command_line, render_preview_card, render_status_line}; use crate::config::colors::Theme; use ratatui::layout::{Constraint, Direction, Layout}; use ratatui::Frame;