My personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: widgets for title + tag search

+108 -11
+13
Cargo.lock
··· 2306 2306 "pulldown-cmark", 2307 2307 "rand 0.10.0", 2308 2308 "ratatui", 2309 + "ratatui-textarea", 2309 2310 "rayon", 2310 2311 "serde", 2311 2312 "signal-hook 0.4.3", ··· 5803 5804 dependencies = [ 5804 5805 "ratatui-core", 5805 5806 "termwiz", 5807 + ] 5808 + 5809 + [[package]] 5810 + name = "ratatui-textarea" 5811 + version = "0.8.0" 5812 + source = "registry+https://github.com/rust-lang/crates.io-index" 5813 + checksum = "de236b7cc74b3f7dea227b3fbad97bf459cddf552b6503d888fb9a106eda59ab" 5814 + dependencies = [ 5815 + "ratatui-core", 5816 + "ratatui-crossterm", 5817 + "ratatui-widgets", 5818 + "unicode-width 0.2.2", 5806 5819 ] 5807 5820 5808 5821 [[package]]
+1
Cargo.toml
··· 79 79 rayon = "1.11.0" 80 80 rand = "0.10.0" 81 81 pulldown-cmark = { version = "0.13.3", features = ["simd"] } 82 + ratatui-textarea = "0.8.0" 82 83 83 84 [build-dependencies] 84 85 anyhow = "1.0.102"
+23 -11
src/tui/components/zk/mod.rs
··· 1 1 use async_trait::async_trait; 2 2 use color_eyre::eyre::Result; 3 + use crossterm::event::KeyEvent; 3 4 use dto::{QueryOrder, TagEntity, ZettelColumns, ZettelEntity}; 4 - use ratatui::{ 5 - prelude::*, 6 - widgets::{Block, ListState}, 7 - }; 5 + use ratatui::{prelude::*, widgets::ListState}; 8 6 use tokio::sync::mpsc::UnboundedSender; 9 7 10 8 use crate::{ ··· 13 11 }; 14 12 15 13 mod preview; 14 + mod search; 16 15 mod zettel_list; 17 16 mod zettel_view; 18 17 19 18 use preview::Preview; 19 + use search::Search; 20 20 use zettel_list::ZettelList; 21 21 use zettel_view::ZettelView; 22 22 ··· 29 29 // handle or is a workspace clone enough? 30 30 kh: KastenHandle, 31 31 layouts: Layouts, 32 + search: Search<'text>, 32 33 zettel_list: ZettelList<'text>, 33 34 zettel_view: ZettelView<'text>, 34 35 preview: Preview<'text>, ··· 47 48 Constraint::Percentage(50), 48 49 Constraint::Percentage(50), 49 50 ]), 50 - search_zl: Layout::vertical(vec![ 51 - Constraint::Percentage(10), 52 - Constraint::Percentage(90), 53 - ]), 54 - z_preview: Layout::vertical(vec![Constraint::Max(6), Constraint::Percentage(80)]), 51 + search_zl: Layout::vertical(vec![Constraint::Min(6), Constraint::Fill(95)]), 52 + z_preview: Layout::vertical(vec![Constraint::Min(6), Constraint::Fill(95)]), 55 53 } 56 54 } 57 55 } ··· 113 111 zettel_list, 114 112 zettel_view, 115 113 preview, 114 + search: Search::default(), 116 115 }) 117 116 } 118 117 ··· 160 159 // im being a good boy and dropping this as soon as im done with the db 161 160 drop(kt); 162 161 162 + // for now we are going to just read that shit every time... 163 + 163 164 let zettels: Vec<Zettel> = models.into_iter().map(Into::into).collect(); 164 165 Ok(zettels) 165 166 } ··· 251 252 self.zettel_list.width, 252 253 ); 253 254 255 + // we have to select the first one because when 256 + // the zettels from the db get fetched, they are ordered 257 + // by most recently modified 258 + self.zettel_list.state.select_first(); 259 + 254 260 self.zettel_view = ZettelView::from(node.payload()); 255 261 self.preview = Preview::from(node.payload().content(&kt.ws).await?); 256 262 drop(kt); ··· 261 267 Ok(None) 262 268 } 263 269 270 + fn handle_key_event(&mut self, key: KeyEvent) -> color_eyre::Result<Option<Signal>> { 271 + // ok so we get the text here too 272 + // self.search.title.input(key); 273 + 274 + Ok(None) 275 + } 276 + 264 277 fn draw( 265 278 &mut self, 266 279 frame: &mut ratatui::Frame, ··· 278 291 (l_rects[0], l_rects[1], r_rects[0], r_rects[1]) 279 292 }; 280 293 281 - frame.render_widget(Block::new().bg(Color::Red), search_layout); 294 + frame.render_widget(self.search.clone(), search_layout); 282 295 283 296 frame.render_stateful_widget( 284 297 &self.zettel_list.render_list, ··· 288 301 289 302 frame.render_widget(self.zettel_view.clone(), zettel_layout); 290 303 frame.render_widget(self.preview.clone(), preview_layout); 291 - // frame.render_widget(Block::new().bg(Color::Red), preview_layout); 292 304 293 305 Ok(()) 294 306 }
+71
src/tui/components/zk/search.rs
··· 1 + use ratatui::{ 2 + layout::{Constraint, Layout}, 3 + style::Style, 4 + widgets::{Block, BorderType, Borders, Widget}, 5 + }; 6 + use ratatui_textarea::TextArea; 7 + 8 + #[derive(Clone)] 9 + pub struct Search<'text> { 10 + pub title: TextArea<'text>, 11 + pub tag: TextArea<'text>, 12 + layouts: Layouts, 13 + } 14 + 15 + impl Default for Search<'_> { 16 + fn default() -> Self { 17 + let mut title = TextArea::default(); 18 + 19 + title.set_style(Style::default()); 20 + title.set_block( 21 + Block::new() 22 + .border_type(BorderType::Plain) 23 + .borders(Borders::all()) 24 + .title("Search Titles"), 25 + ); 26 + 27 + let mut tag = TextArea::default(); 28 + tag.set_style(Style::default()); 29 + tag.set_block( 30 + Block::new() 31 + .border_type(BorderType::Plain) 32 + .borders(Borders::all()) 33 + .title("Search Tags"), 34 + ); 35 + 36 + Self { 37 + title, 38 + tag, 39 + layouts: Layouts::default(), 40 + } 41 + } 42 + } 43 + 44 + #[derive(Clone)] 45 + struct Layouts { 46 + title_tag: Layout, 47 + } 48 + 49 + impl Default for Layouts { 50 + fn default() -> Self { 51 + Self { 52 + title_tag: Layout::vertical(vec![Constraint::Min(3), Constraint::Min(3)]), 53 + } 54 + } 55 + } 56 + 57 + impl Widget for Search<'_> { 58 + fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) 59 + where 60 + Self: Sized, 61 + { 62 + let (title_search_rect, tag_search_rect) = { 63 + let rects = self.layouts.title_tag.split(area); 64 + 65 + (rects[0], rects[1]) 66 + }; 67 + 68 + self.title.render(title_search_rect, buf); 69 + self.tag.render(tag_search_rect, buf); 70 + } 71 + }