From e79ba2c79e8ec6ae814b51b8eb042f200306df53 Mon Sep 17 00:00:00 2001 From: Gabriel Bao Date: Fri, 22 May 2026 22:39:11 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat(components):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8F=8A=E8=BF=AD=E4=BB=A3=E5=A4=9A=E4=B8=AA=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/input_bar.rs | 6 +-- src/components/main_scroll.rs | 0 src/components/mod.rs | 3 ++ src/components/progress_bar.rs | 81 +++++++++++++++++++++++++++++++++ src/components/status_bar_v2.rs | 34 ++++++++++++++ 5 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 src/components/main_scroll.rs create mode 100644 src/components/progress_bar.rs create mode 100644 src/components/status_bar_v2.rs diff --git a/src/components/input_bar.rs b/src/components/input_bar.rs index 647ab51..3b16f9a 100644 --- a/src/components/input_bar.rs +++ b/src/components/input_bar.rs @@ -44,10 +44,10 @@ pub fn InputBar(mut hooks: Hooks) -> impl Into> { }); element!(Border( - height: Constraint::Length(4), + height: Constraint::Length(6), style: Style::default().green(), - bottom_title: Line::styled( - "Press 'Enter' to submit, 'Esc' to exit", + top_title: Line::styled( + "Composer", Style::default().yellow(), ).centered(), ) { diff --git a/src/components/main_scroll.rs b/src/components/main_scroll.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/mod.rs b/src/components/mod.rs index cd96e7e..a6f3da5 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,3 +1,6 @@ pub mod welcome; pub mod input_bar; pub mod status_bar; +mod main_scroll; +mod status_bar_v2; +mod progress_bar; diff --git a/src/components/progress_bar.rs b/src/components/progress_bar.rs new file mode 100644 index 0000000..3eae4b6 --- /dev/null +++ b/src/components/progress_bar.rs @@ -0,0 +1,81 @@ +use ratatui_kit::prelude::*; +use ratatui_kit::ratatui::{ + style::{Modifier, Style}, + text::{Line, Span}, +}; +use ratatui_kit::ratatui::layout::Direction; + +#[derive(Debug, Clone, Props)] +pub struct ProgressBarProps { + pub style: Style, + pub menu_style: Style, + pub install_message: String, + pub stage: String, + pub percent: f64, + pub downloaded: u64, + pub total: u64, + pub speed: f64, +} + +impl Default for ProgressBarProps { + fn default() -> Self { + Self { + style: Style::default(), + menu_style: Style::default(), + install_message: String::new(), + stage: String::new(), + percent: 0.0, + downloaded: 0, + total: 0, + speed: 0.0, + } + } +} + +#[component] +pub fn ProgressBar( + _hooks: Hooks, + props: &ProgressBarProps, +) -> impl Into> { + // 计算进度条 + let percent = props.percent.clamp(0.0, 100.0); + const BAR_WIDTH: usize = 30; + let fill = ((percent / 100.0 * BAR_WIDTH as f64) as usize).min(BAR_WIDTH); + let bar = format!("[{}{}]", "█".repeat(fill), "░".repeat(BAR_WIDTH - fill)); + + let mut spans = vec![ + Span::styled(bar, props.menu_style), + Span::raw(format!(" {:.2}%", percent)), + ]; + + if props.stage.contains("Downloading") { + let mb = props.downloaded as f64 / 1024.0 / 1024.0; + let total_mb = props.total as f64 / 1024.0 / 1024.0; + let speed_mb = props.speed / 1024.0 / 1024.0; + spans.push(Span::raw(format!(" ({:.2} MB/{:.2} MB)", mb, total_mb))); + spans.push(Span::raw(format!(" {:.2} MB/s", speed_mb))); + } else { + spans.push(Span::raw(format!(" {} / {}", props.downloaded, props.total))); + } + + // 官方标准 element! 语法(零错误) + element! { + View(flex_direction: Direction::Vertical) { + // 必须传 String,不能传 &str + Text(text: props.install_message.clone(), style: props.style.add_modifier(Modifier::BOLD)) {} + Text(text: String::new()) {} + + // 官方条件渲染:#(if ...) + #(if !props.stage.is_empty() { + Some(element! { + View { + Text(text: props.stage.clone(), style: props.style.add_modifier(Modifier::BOLD)) {} + Text(spans: spans) {} + } + }) + } else { + None + }) + } + } +} \ No newline at end of file diff --git a/src/components/status_bar_v2.rs b/src/components/status_bar_v2.rs new file mode 100644 index 0000000..91796b5 --- /dev/null +++ b/src/components/status_bar_v2.rs @@ -0,0 +1,34 @@ +use ratatui_kit::{component, element, AnyElement, ElementExt, Hooks}; +use ratatui_kit::components::View; +use ratatui_kit::ratatui::{TerminalOptions, Viewport}; +use ratatui_kit::ratatui::layout::{Direction, Constraint, Flex, Margin}; +use ratatui_kit::ratatui::prelude::Color; +use ratatui_kit::ratatui::style::Style; +use ratatui_kit::ratatui::text::Line; +use crate::components::input_bar::InputBar; +use crate::components::status_bar::StatusBar; + +#[component] +pub fn StatusBarV2(mut hooks: Hooks) -> impl Into> { + element!( + View( + flex_direction: Direction::Horizontal, + justify_content: Flex::SpaceBetween, + margin: Margin::new(10, 0), + height: Constraint::Length(1) + ) { + // Model name + View() { + $Line::styled(format!("Model: {}", todo!()), Style::default().fg(Color::White)) + } + // Cache size + View() { + $Line::styled(format!("Cache: {}", todo!()), Style::default().fg(Color::White)) + } + // Context size + View() { + $Line::styled(format!("Context: {}", todo!()), Style::default().fg(Color::White)) + } + } + ) +} \ No newline at end of file From 1bfb08b46f43f154592a254190d9e59d011d8bdf Mon Sep 17 00:00:00 2001 From: Gabriel Bao Date: Sat, 23 May 2026 19:15:35 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/status_bar_v2.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/components/status_bar_v2.rs b/src/components/status_bar_v2.rs index 91796b5..22b2042 100644 --- a/src/components/status_bar_v2.rs +++ b/src/components/status_bar_v2.rs @@ -1,4 +1,4 @@ -use ratatui_kit::{component, element, AnyElement, ElementExt, Hooks}; +use ratatui_kit::{component, element, AnyElement, ElementExt, Hooks, Props, Store, UseState}; use ratatui_kit::components::View; use ratatui_kit::ratatui::{TerminalOptions, Viewport}; use ratatui_kit::ratatui::layout::{Direction, Constraint, Flex, Margin}; @@ -8,8 +8,34 @@ use ratatui_kit::ratatui::text::Line; use crate::components::input_bar::InputBar; use crate::components::status_bar::StatusBar; +#[derive(Props, Store)] +pub struct StatusBarV2Props { + pub model_name: String, + pub cache_size: f64, + pub context_size: f64, + pub context_total: f64, +} + +impl Default for StatusBarV2Props { + fn default() -> Self { + Self { + model_name: String::new(), + cache_size: 0.0, + context_size: 0.0, + context_total: 0.0, + } + } +} + #[component] -pub fn StatusBarV2(mut hooks: Hooks) -> impl Into> { +pub fn StatusBarV2(mut hooks: Hooks, props: &StatusBarV2Props) -> impl Into> { + + let state = hooks.use_state(|| { + Self { + _marker: Default::default(), + } + }); + element!( View( flex_direction: Direction::Horizontal, From d877dd334d93f61abdff3bc30930cbe1e0634275 Mon Sep 17 00:00:00 2001 From: Gabriel Bao Date: Sun, 24 May 2026 14:56:54 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat(store):=20=E5=85=A8=E5=B1=80=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/db/store/mod.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++ src/pages/router.rs | 2 ++ 2 files changed, 60 insertions(+) diff --git a/src/db/store/mod.rs b/src/db/store/mod.rs index e69de29..ec023ed 100644 --- a/src/db/store/mod.rs +++ b/src/db/store/mod.rs @@ -0,0 +1,58 @@ +use ratatui_kit::Store; + +pub struct TodoItem { + pub id: u32, + pub title: String, + pub completed: bool, +} + +pub struct TodoList { + pub items: Vec, +} + +pub struct TaskItem { + pub id: u32, + pub title: String, + pub completed: bool, +} + +pub struct TaskList { + pub items: Vec, +} + +#[derive(Store)] +pub struct GlobalStore { + pub llm_name: String, + pub current_chat: String, + pub cache_size: f64, + pub context_size: f64, + pub model_context_window: f64, + pub input_tokens: u32, + pub output_tokens: u32, + pub current_chat_count: u32, + pub todo_list: TodoList, + pub task_list: TaskList, + pub input_buffer: String, +} + +impl Default for GlobalStore { + fn default() -> Self { + Self { + llm_name: String::new(), + current_chat: String::new(), + cache_size: 0.0, + context_size: 0.0, + model_context_window: 0.0, + input_tokens: 0, + output_tokens: 0, + current_chat_count: 0, + todo_list: TodoList { + items: Vec::new(), + }, + task_list: TaskList { + items: Vec::new(), + }, + input_buffer: String::new(), + } + } +} \ No newline at end of file diff --git a/src/pages/router.rs b/src/pages/router.rs index eac98a2..07c8fbb 100644 --- a/src/pages/router.rs +++ b/src/pages/router.rs @@ -24,6 +24,8 @@ pub fn RouterPage(mut hooks: Hooks) -> impl Into> { }); //todo 这里的逻辑是通过数据库查询是否初始化,从而确定要路由到 Welcome 还是 Chat + //todo 为了开发方便,这里的逻辑还需要判断是否是开发环境,如果是开发环境,默认路由到路由页面,路由页面在生产环境不对外暴露 + //todo 同时路由函数禁止在生成环境中调用,避免在生产环境中路由到路由页面 element!( View(height: Constraint::Length(10),) { From 68db9c30254e8710916802341b2d580395df4d48 Mon Sep 17 00:00:00 2001 From: Gabriel Bao Date: Mon, 25 May 2026 15:54:06 +0800 Subject: [PATCH 4/4] =?UTF-8?q?chore(status=5Fbar):=20=E7=A7=BB=E9=99=A4v2?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mod.rs | 1 - src/components/progress_bar.rs | 2 +- src/components/status_bar_v2.rs | 60 --------------------------------- 3 files changed, 1 insertion(+), 62 deletions(-) delete mode 100644 src/components/status_bar_v2.rs diff --git a/src/components/mod.rs b/src/components/mod.rs index a6f3da5..19919f9 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -2,5 +2,4 @@ pub mod welcome; pub mod input_bar; pub mod status_bar; mod main_scroll; -mod status_bar_v2; mod progress_bar; diff --git a/src/components/progress_bar.rs b/src/components/progress_bar.rs index 3eae4b6..af3a07c 100644 --- a/src/components/progress_bar.rs +++ b/src/components/progress_bar.rs @@ -70,7 +70,7 @@ pub fn ProgressBar( Some(element! { View { Text(text: props.stage.clone(), style: props.style.add_modifier(Modifier::BOLD)) {} - Text(spans: spans) {} + // Text(spans: spans) {} } }) } else { diff --git a/src/components/status_bar_v2.rs b/src/components/status_bar_v2.rs deleted file mode 100644 index 22b2042..0000000 --- a/src/components/status_bar_v2.rs +++ /dev/null @@ -1,60 +0,0 @@ -use ratatui_kit::{component, element, AnyElement, ElementExt, Hooks, Props, Store, UseState}; -use ratatui_kit::components::View; -use ratatui_kit::ratatui::{TerminalOptions, Viewport}; -use ratatui_kit::ratatui::layout::{Direction, Constraint, Flex, Margin}; -use ratatui_kit::ratatui::prelude::Color; -use ratatui_kit::ratatui::style::Style; -use ratatui_kit::ratatui::text::Line; -use crate::components::input_bar::InputBar; -use crate::components::status_bar::StatusBar; - -#[derive(Props, Store)] -pub struct StatusBarV2Props { - pub model_name: String, - pub cache_size: f64, - pub context_size: f64, - pub context_total: f64, -} - -impl Default for StatusBarV2Props { - fn default() -> Self { - Self { - model_name: String::new(), - cache_size: 0.0, - context_size: 0.0, - context_total: 0.0, - } - } -} - -#[component] -pub fn StatusBarV2(mut hooks: Hooks, props: &StatusBarV2Props) -> impl Into> { - - let state = hooks.use_state(|| { - Self { - _marker: Default::default(), - } - }); - - element!( - View( - flex_direction: Direction::Horizontal, - justify_content: Flex::SpaceBetween, - margin: Margin::new(10, 0), - height: Constraint::Length(1) - ) { - // Model name - View() { - $Line::styled(format!("Model: {}", todo!()), Style::default().fg(Color::White)) - } - // Cache size - View() { - $Line::styled(format!("Cache: {}", todo!()), Style::default().fg(Color::White)) - } - // Context size - View() { - $Line::styled(format!("Context: {}", todo!()), Style::default().fg(Color::White)) - } - } - ) -} \ No newline at end of file