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: note preview!

+85 -35
+2
src/tui/app.rs
··· 234 234 235 235 self.signal_tx.send(Signal::ClosedZettel { zid })?; 236 236 237 + self.signal_tx.send(Signal::Refresh)?; 238 + 237 239 tui.terminal.clear()?; 238 240 tui.enter()?; 239 241 }
+19 -8
src/tui/components/todo/inspector/groupview.rs
··· 5 5 }; 6 6 use ratatui_textarea::TextArea; 7 7 8 - use crate::types::Group; 8 + use crate::{ 9 + tui::components::preview::Preview, 10 + types::{Group, Index}, 11 + }; 9 12 10 13 #[derive(Debug, Clone)] 11 14 pub struct GroupView<'text> { 12 15 pub name: TextArea<'text>, 13 16 pub priority: TextArea<'text>, 14 17 created_at: Paragraph<'text>, 18 + preview: Preview<'text>, 15 19 layouts: Layouts, 16 20 } 17 21 ··· 26 30 Self { 27 31 left_content: Layout::horizontal(vec![ 28 32 Constraint::Percentage(30), 33 + Constraint::Min(1), 29 34 Constraint::Fill(100), 30 35 ]), 31 36 name_priority_created_at: Layout::vertical(vec![ ··· 38 43 } 39 44 } 40 45 41 - impl From<&Group> for GroupView<'_> { 42 - fn from(value: &Group) -> Self { 43 - let mut name = TextArea::new(vec![value.name.clone()]); 46 + impl From<(&Group, &Index)> for GroupView<'_> { 47 + fn from(value: (&Group, &Index)) -> Self { 48 + let group = value.0; 49 + let idx = value.1; 50 + let mut name = TextArea::new(vec![group.name.clone()]); 44 51 name.set_block(Block::bordered().title("[N]ame")); 45 52 name.set_cursor_style(Style::reset()); 46 53 name.set_cursor_line_style(Style::reset()); 47 54 48 - let mut priority = TextArea::new(vec![value.priority.to_string()]); 55 + let mut priority = TextArea::new(vec![group.priority.to_string()]); 49 56 priority.set_block(Block::bordered().title("[P]riority")); 50 57 priority.set_cursor_style(Style::reset()); 51 58 priority.set_cursor_line_style(Style::reset()); 52 59 60 + let preview = idx.get_zod(&group.zettel.id).body.clone().into(); 61 + 53 62 Self { 54 63 name, 55 64 priority, 56 - created_at: Paragraph::new(value.created_at()) 65 + created_at: Paragraph::new(group.created_at()) 57 66 .block(Block::bordered().title("Created At")), 67 + preview, 58 68 layouts: Layouts::default(), 59 69 } 60 70 } ··· 65 75 where 66 76 Self: Sized, 67 77 { 68 - let (name_rect, priority_rect, created_at, _content_rect) = { 78 + let (name_rect, priority_rect, created_at, content_rect) = { 69 79 let rects = self.layouts.left_content.split(area); 70 80 let l_rects = self.layouts.name_priority_created_at.split(rects[0]); 71 81 72 - (l_rects[0], l_rects[1], l_rects[2], rects[1]) 82 + (l_rects[0], l_rects[1], l_rects[2], rects[2]) 73 83 }; 74 84 75 85 self.name.render(name_rect, buf); 76 86 self.priority.render(priority_rect, buf); 77 87 self.created_at.render(created_at, buf); 88 + self.preview.render(content_rect, buf); 78 89 } 79 90 }
+20 -7
src/tui/components/todo/inspector/mod.rs
··· 46 46 } 47 47 48 48 impl Inspector<'_> { 49 - pub fn new(kh: KastenHandle, node: &TodoNode) -> Self { 49 + pub async fn new(kh: KastenHandle, node: &TodoNode) -> Self { 50 50 let margins = Layout::new(Direction::Horizontal, [Constraint::Percentage(100)]) 51 51 .horizontal_margin(3) 52 52 .vertical_margin(2); ··· 59 59 .border_type(BorderType::Rounded); 60 60 61 61 let mut nanoid = None; 62 + let kt = kh.read().await; 62 63 63 64 let render_data = match node.kind { 64 65 TodoNodeKind::Root => RenderData::Root { ··· 68 69 nanoid = Some(group.id.clone()); 69 70 70 71 RenderData::Group { 71 - widget: Box::new(GroupView::from(&**group)), 72 + widget: Box::new(GroupView::from((&**group, &kt.index))), 72 73 } 73 74 } 74 75 TodoNodeKind::Task(ref task) => { 75 76 nanoid = Some(task.id.clone()); 76 77 77 78 RenderData::Task { 78 - widget: Box::new(TaskView::from(&**task)), 79 + widget: Box::new(TaskView::from((&**task, &kt.index))), 79 80 } 80 81 } 81 82 }; 82 83 84 + drop(kt); 85 + 83 86 Self { 84 87 render_data, 85 88 margins, ··· 113 116 .border_type(BorderType::Rounded); 114 117 } 115 118 116 - pub fn inspect(&mut self, node: &TodoNode) { 119 + pub async fn inspect(&mut self, node: &TodoNode) { 120 + let kt = self.kh.read().await; 121 + 117 122 self.render_data = match node.kind { 118 123 TodoNodeKind::Root => { 119 124 self.inspecting = None; ··· 124 129 TodoNodeKind::Group(ref group) => { 125 130 self.inspecting = Some(group.id.clone()); 126 131 RenderData::Group { 127 - widget: Box::new(GroupView::from(&**group)), 132 + widget: Box::new(GroupView::from((&**group, &kt.index))), 128 133 } 129 134 } 130 135 TodoNodeKind::Task(ref task) => { 131 136 self.inspecting = Some(task.id.clone()); 132 137 RenderData::Task { 133 - widget: Box::new(TaskView::from(&**task)), 138 + widget: Box::new(TaskView::from((&**task, &kt.index))), 134 139 } 135 140 } 136 141 } ··· 145 150 return; 146 151 }; 147 152 let node = kt.todo_tree.get_node_by_nano_id(inspecting).data(); 148 - self.inspect(node); 153 + self.inspect(node).await; 149 154 150 155 drop(kt); 151 156 } ··· 166 171 167 172 async fn update(&mut self, signal: Signal) -> color_eyre::Result<Option<Signal>> { 168 173 match signal { 174 + Signal::SwitchTo { 175 + page: crate::tui::Page::Zk, 176 + } => { 177 + self.is_active = false; 178 + 179 + self.set_inactive(); 180 + } 181 + 169 182 Signal::EditName => { 170 183 let name = match &mut self.render_data { 171 184 RenderData::Root { widget: _ } => return Ok(None),
+24 -10
src/tui/components/todo/inspector/taskview.rs
··· 5 5 }; 6 6 use ratatui_textarea::TextArea; 7 7 8 - use crate::types::Task; 8 + use crate::{ 9 + tui::components::preview::Preview, 10 + types::{Index, Task}, 11 + }; 9 12 10 13 #[derive(Debug, Clone)] 11 14 pub struct TaskView<'text> { ··· 13 16 pub priority: TextArea<'text>, 14 17 pub due_finished_at: TextArea<'text>, 15 18 parent_group: Paragraph<'text>, 19 + preview: Preview<'text>, 16 20 layouts: Layouts, 17 21 } 18 22 ··· 27 31 Self { 28 32 left_content: Layout::horizontal(vec![ 29 33 Constraint::Percentage(30), 34 + Constraint::Min(1), 30 35 Constraint::Fill(100), 31 36 ]), 37 + // .horizontal_margin(2), 32 38 name_priority_due_group: Layout::vertical(vec![ 33 39 Constraint::Min(3), 34 40 Constraint::Min(3), ··· 39 45 } 40 46 } 41 47 42 - impl From<&Task> for TaskView<'_> { 43 - fn from(value: &Task) -> Self { 44 - let mut name = TextArea::new(vec![value.name.clone()]); 48 + impl From<(&Task, &Index)> for TaskView<'_> { 49 + fn from(value: (&Task, &Index)) -> Self { 50 + let task = value.0; 51 + let idx = value.1; 52 + 53 + let mut name = TextArea::new(vec![task.name.clone()]); 45 54 name.set_block(Block::bordered().title("[N]ame")); 46 55 name.set_cursor_style(Style::reset()); 47 56 name.set_cursor_line_style(Style::reset()); 48 57 49 - let mut priority = TextArea::new(vec![value.priority.to_string()]); 58 + let mut priority = TextArea::new(vec![task.priority.to_string()]); 50 59 priority.set_block(Block::bordered().title("[P]riority")); 51 60 priority.set_cursor_style(Style::reset()); 52 61 priority.set_cursor_line_style(Style::reset()); 53 62 54 63 let due_finished_at = { 55 - let (title, content) = value.finished_at().map_or_else( 56 - || ("[D]ue", value.due.to_string()), 64 + let (title, content) = task.finished_at().map_or_else( 65 + || ("[D]ue", task.due.to_string()), 57 66 |finished| ("[F]inished At", finished), 58 67 ); 59 68 ··· 63 72 textarea.set_cursor_line_style(Style::reset()); 64 73 textarea 65 74 }; 75 + 76 + let preview = idx.get_zod(&task.zettel.id).body.clone().into(); 77 + 66 78 Self { 67 79 name, 68 80 priority, 69 81 due_finished_at, 70 - parent_group: Paragraph::new(value.group.name.clone()) 82 + parent_group: Paragraph::new(task.group.name.clone()) 71 83 .block(Block::bordered().title("Group")), 72 84 layouts: Layouts::default(), 85 + preview, 73 86 } 74 87 } 75 88 } ··· 79 92 where 80 93 Self: Sized, 81 94 { 82 - let (name_rect, priority_rect, due_rect, group_rect, _content_rect) = { 95 + let (name_rect, priority_rect, due_rect, group_rect, content_rect) = { 83 96 let rects = self.layouts.left_content.split(area); 84 97 let l_rects = self.layouts.name_priority_due_group.split(rects[0]); 85 98 86 - (l_rects[0], l_rects[1], l_rects[2], l_rects[3], rects[1]) 99 + (l_rects[0], l_rects[1], l_rects[2], l_rects[3], rects[2]) 87 100 }; 88 101 89 102 self.name.render(name_rect, buf); 90 103 self.priority.render(priority_rect, buf); 91 104 self.due_finished_at.render(due_rect, buf); 92 105 self.parent_group.render(group_rect, buf); 106 + self.preview.render(content_rect, buf); 93 107 } 94 108 }
+8 -6
src/tui/components/todo/mod.rs
··· 165 165 }; 166 166 let tree = &self.kh.read().await.todo_tree.tree; 167 167 168 - inspector.inspect( 169 - tree.get(selected_node_id) 170 - .expect("Nodeid must be valid") 171 - .data(), 172 - ); 168 + inspector 169 + .inspect( 170 + tree.get(selected_node_id) 171 + .expect("Nodeid must be valid") 172 + .data(), 173 + ) 174 + .await; 173 175 } 174 176 } 175 177 ··· 233 235 ) 234 236 .expect("Node id must be valid"); 235 237 236 - let mut inspector: Inspector<'_> = Inspector::new(self.kh.clone(), first.data()); 238 + let mut inspector: Inspector<'_> = Inspector::new(self.kh.clone(), first.data()).await; 237 239 238 240 explorer.set_inactive(); 239 241 inspector.set_inactive();
+1 -1
src/tui/components/zk/mod.rs
··· 11 11 types::{KastenHandle, Zettel}, 12 12 }; 13 13 14 - mod preview; 14 + pub mod preview; 15 15 mod search; 16 16 mod zettel_list; 17 17 mod zettel_view;
+11 -3
src/tui/components/zk/preview.rs
··· 1 - use ratatui::{text::Text, widgets::Widget}; 1 + use ratatui::{ 2 + text::Text, 3 + widgets::{Block, BorderType, Borders, Paragraph, Widget}, 4 + }; 2 5 3 6 #[derive(Debug, Clone)] 4 7 pub struct Preview<'text> { 5 - content: Text<'text>, 8 + content: Paragraph<'text>, 6 9 } 7 10 8 11 impl From<String> for Preview<'_> { 9 12 fn from(value: String) -> Self { 10 13 Self { 11 - content: Text::from(value), 14 + content: Paragraph::new(Text::from(value)).block( 15 + Block::new() 16 + .borders(Borders::TOP | Borders::LEFT) 17 + .border_type(BorderType::Rounded) 18 + .title("Preview"), 19 + ), 12 20 } 13 21 } 14 22 }