content.rs
1 use crate::app; 2 use crate::types::{Comment, StoryItem, StoryPageData, UserData}; 3 use sauron::prelude::*; 4 use serde::{Deserialize, Serialize}; 5 //use sauron::safe_html; 6 7 #[derive( 8 Debug, Deserialize, Serialize, PartialEq, Clone, derive_more::From, 9 )] 10 pub enum Content { 11 Stories(Vec<StoryItem>), 12 StoryPage(StoryPageData), 13 CommentPermalink(Comment), 14 UserPage(UserData), 15 } 16 17 impl Content { 18 pub fn view(&self) -> Node<app::Msg> { 19 match self { 20 Content::Stories(stories) => { 21 node! { 22 <div class="index-page"> 23 {self.view_story_preview_list(stories)} 24 </div> 25 } 26 } 27 Content::StoryPage(story_page) => { 28 node! { 29 <div class="story-page"> 30 { self.view_story_page(story_page) } 31 </div> 32 } 33 } 34 Content::UserPage(user_data) => { 35 node! { 36 <div class="user-details"> 37 <h4>{ text!("{}:",user_data.id) }</h4> 38 <div>{ for node in crate::util::parse_html_to_nodes(&user_data.about) { node } }</div> 39 <span>{ text!("{} karma", user_data.karma) }</span> 40 <div class="submissions"> 41 {self.view_story_preview_list(&user_data.stories)} 42 </div> 43 </div> 44 } 45 } 46 Content::CommentPermalink(comment) => { 47 node! { 48 <div class="comment-permalink"> 49 {self.view_comment(comment)} 50 </div> 51 } 52 } 53 } 54 } 55 56 fn view_story_preview_list(&self, stories: &[StoryItem]) -> Node<app::Msg> { 57 node! { 58 <ol> 59 { 60 for (i, story_preview) in stories.iter().enumerate() { 61 node! { 62 <li> 63 <div class="item-number">{text!("{}. ",i+1)}</div> 64 <div class="preview-wrapper"> 65 {self.view_story_preview(story_preview)} 66 </div> 67 </li> 68 } 69 } 70 } 71 </ol> 72 } 73 } 74 75 fn view_story_preview(&self, story_preview: &StoryItem) -> Node<app::Msg> { 76 // we copy story_preview_id here because it will be moved into the `on_click` event 77 // listener in the links to the comments. 78 // 79 // This is needed since on_click requires an `Fn` where it needs to take variables from 80 // it's environment that can last a lifetime of 'static. Therefore we need to create a copy 81 // of dynamic variables and move it. 82 let story_preview_id = story_preview.id; 83 let story_preview_by = story_preview.by.clone(); 84 node! { 85 <div class="story-preview"> 86 <div class="buttons"> 87 <a>{html::symbol("▲")}</a> 88 <a>{html::symbol("▼")}</a> 89 </div> 90 <div> 91 <h2> 92 { 93 if let Some(url) = &story_preview.url{ 94 node!{ 95 <a href=url target="_blank" rel="noopener noreferrer">{text(&story_preview.title)}</a> 96 } 97 }else{ 98 text(&story_preview.title) 99 } 100 } 101 </h2> 102 <span class="story-details"> 103 { text!("{} points | ",story_preview.score) } 104 <a href=format!("/user/{}", story_preview.by) 105 on_click=move|e|{ 106 e.prevent_default(); 107 app::Msg::ShowUserPage(story_preview_by.clone()) 108 }> 109 { text!(" by {}",story_preview.by) } 110 </a> 111 <span title="time">{ text!(" | {} ago |", crate::util::time_ago(story_preview.time)) }</span> 112 <a href=format!("/item/{}", story_preview.id) 113 on_click=move|e|{ 114 e.prevent_default(); 115 app::Msg::OpenStory(story_preview_id) 116 }> 117 { text!(" {} comments", story_preview.descendants) } 118 </a> 119 </span> 120 </div> 121 </div> 122 } 123 } 124 125 fn view_story_page(&self, story_page: &StoryPageData) -> Node<app::Msg> { 126 node! { 127 <div> 128 { self.view_story_preview(&story_page.preview()) } 129 <ul class="comment-component"> 130 { 131 for comment in story_page.comments.iter(){ 132 self.view_comment(comment) 133 } 134 } 135 </ul> 136 </div> 137 } 138 } 139 140 fn view_comment(&self, comment: &Comment) -> Node<app::Msg> { 141 let comment_id = comment.id; 142 let comment_by = comment.by.clone(); 143 node! { 144 <li class="comment-item"> 145 <div class="comment-details"> 146 <a href=format!("/user/{}",comment.by) 147 on_click=move|e|{ 148 e.prevent_default(); 149 app::Msg::ShowUserPage(comment_by.clone()) 150 }>{text(&comment.by)} 151 </a> 152 <a href=format!("/comment/{}",comment.id) 153 on_click=move|e|{ 154 e.prevent_default(); 155 app::Msg::ShowCommentPermalink(comment_id) 156 }>{text!(" {} ago", crate::util::time_ago(comment.time))} 157 </a> 158 </div> 159 <div class="comment">{ for node in crate::util::parse_html_to_nodes(&comment.text) { node } }</div> 160 <ul class="sub-comments"> 161 { 162 for sub in &comment.sub_comments{ 163 node!{ 164 <li> 165 {self.view_comment(sub)} 166 </li> 167 } 168 } 169 } 170 </ul> 171 </li> 172 } 173 } 174 }