use crate::AppState; use crate::html::elements::{Anchor, Heading, Link, Paragraph}; use crate::html::layouts::Division; use crate::html::pages::BasePage; use crate::html::{Render, boxed_vec}; use actix_web::web::Data; use actix_web::{Responder, get, web}; use serde::Deserialize; use sqlx::query_as; #[derive(Deserialize)] struct Project { id: String, title: String, description: String, } #[get("/projects")] async fn projects(app_state: Data) -> impl Responder { let title = Heading::builder().text("My projects").build(); let desc = Heading::builder() .level(2) .text( "Here you will find all my projects which deserve to be shown
\ (I've done a lot of small projects but they are not worth it.)", ) .build(); let projects = match query_as!(Project, "SELECT id, title, description FROM Projects") .fetch_all(&app_state.pool) .await { Ok(projects) => projects, Err(_) => { vec![] } }; let items: Vec> = projects .into_iter() .map(|p| { let title = Heading::builder().text(p.title).build(); let description = Paragraph::builder() .classes(vec!["project-desc"]) .text(p.description) .build(); let view = Anchor::builder() .classes(vec!["project-view"]) .href(format!("/projects/{}", p.id)) .text("Learn More") .build(); let info = Division::builder() .classes(vec!["project-info"]) .elements(boxed_vec![description, view]) .build(); Box::new( Division::builder() .classes(vec!["project"]) .elements(boxed_vec![title, info]) .build(), ) as Box }) .collect(); let css = Link::builder() .rel("stylesheet") .href("/static/css/projects.css") .build(); let mut body = boxed_vec![title, desc]; body.extend(items); let page = BasePage::builder() .title("Projects") .head(boxed_vec![css]) .body(body) .build(); page.render() } #[derive(Deserialize)] struct ProjectDetail { id: String, title: String, git_url: String, git_title: String, description: String, } #[get("/projects/{project}")] async fn project(project: web::Path, app_state: Data) -> impl Responder { let project = project.into_inner(); let css = Link::builder() .rel("stylesheet") .href("/static/css/project.css") .build(); let mut page = BasePage::builder() .title(format!("Project-{}", project)) .head(boxed_vec![css]) .build(); let project = match query_as!( ProjectDetail, "SELECT * FROM Project_Detail WHERE id = $1", project ) .fetch_one(&app_state.pool) .await { Ok(project) => project, Err(error) => { // return not found page eprintln!("Error fetching project: {:?}", error); return page.render(); } }; let title = Heading::builder().text(project.title).build(); let gitea = Anchor::builder() .href(project.git_url) .text(project.git_title) .build(); let desc = Paragraph::builder() .classes(vec!["description"]) .text(format!( "{}

Wish to see more? Check out the gitea repository: {}", project.description, gitea.render() )) .build(); page.append_element_to_body(title); page.append_element_to_body(desc); page.render() }