/ src / app / content.rs
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("&#9650;")}</a>
 88                      <a>{html::symbol("&#9660;")}</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  }