use crate::components::header::{Header, HeaderLink}; use crate::State; use axum::extract::{Query, State as AxumState}; use maud::{html, Markup, PreEscaped, DOCTYPE}; use regex::Regex; use serde::Deserialize; #[derive(Deserialize)] pub struct StoryParams { id: Option, chapter: Option, } pub async fn render( AxumState(state): AxumState, Query(params): Query, ) -> Markup { if let Some(id) = params.id { let story = state.wattpad.get_story(id.as_str()).await; if let Ok(story) = story { if let Some(part_idx) = params.chapter { let parts = story.get_parts().await.unwrap(); if let Some(part) = parts.get(part_idx) { let style_matching_regex = Regex::new("style=\"(.+?)\"").unwrap(); html! { (DOCTYPE) html { head { meta name="viewport" content="width=device-width, initial-scale=1.0"; style {(PreEscaped( grass::include!("./css/index.scss") ))} } body { (Header({ let mut story_parts: Vec = parts.iter().enumerate().map(|(idx, part)| HeaderLink { path: format!("/story?id={}&chapter={}", story.id, idx), name: part.title.clone(), prefix: None, postfix: None }).collect(); story_parts.insert(0, HeaderLink { path: format!("/story?id={}", story.id), name: "Details".to_string(), prefix: Some("|".to_string()), postfix: Some("|".to_string()) }); story_parts.insert(0, HeaderLink { path: "/".to_string(), name: "Homepage".to_string(), prefix: None, postfix: None }); story_parts }, format!("/story?id={}&chapter={}", story.id, part_idx))) div .story-content { @for paragraph in part.get_paragraphs().expect("Failed to get paragraphs of part") { p style=({ let attributes = paragraph.attributes.unwrap_or_default(); let captures = style_matching_regex.captures(attributes.as_str()); match captures { Some(e) => e.get(1).unwrap().as_str().to_string(), None => String::default() } }) { (PreEscaped(paragraph.html)) } } } } } } } else { html! { h1 { "Err: Chapter not found" } } } } else { let parts = story.get_parts().await.unwrap(); html! { (DOCTYPE) html { head { meta name="viewport" content="width=device-width, initial-scale=1.0"; style {(PreEscaped( grass::include!("./css/index.scss") ))} } body { (Header({ let mut story_parts: Vec = parts.iter().enumerate().map(|(idx, part)| HeaderLink { path: format!("/story?id={}&chapter={}", story.id, idx), name: part.title.clone(), prefix: None, postfix: None }).collect(); story_parts.insert(0, HeaderLink { path: format!("/story?id={}", story.id), name: "Details".to_string(), prefix: Some("|".to_string()), postfix: Some("|".to_string()) }); story_parts.insert(0, HeaderLink { path: "/".to_string(), name: "Homepage".to_string(), prefix: None, postfix: None }); story_parts }, format!("/story?id={}", story.id))) div .story-page-container { div .story-page { img .story-cover src=(story.cover); div .story-details { h3 #story-name { (story.title) } p { (PreEscaped(story.description.replace("\n", "
"))) } p { "Original URL: " a href=(story.url) { (story.url) } br; "Author: " a href=(format!("/user?name={}", story._user.fullname)) {(story._user.name)} br; "© " (story.copyright) } div .tag-container { @for tag in story.tags { div .tag { a href=(format!("/search?query={}&type=tag", tag)) { (tag) } } } } } } } } } } } } else { html! { h1 { "Err: Story not found" } } } } else { html! { h1 { "Err: Story not specified" } } } }