Learning project: static site generator for ATproto PDS

Adds global context for template rendering #3

merged opened by hello.j23n.com targeting main from feature/global-context
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:enau5rzvrui4fx4dq5icgtle/sh.tangled.repo.pull/3m3podkovhp22
+62 -53
Diff #0
+5 -7
src/atproto/mod.rs
··· 29 29 pub name: String, 30 30 } 31 31 32 - #[derive(serde::Serialize)] 32 + #[derive(serde::Serialize, Clone)] 33 33 pub struct IndexPage { 34 34 pub content: Vec<ContentPage>, 35 35 pub template: String, ··· 111 111 } 112 112 113 113 impl Renderable for ContentPage { 114 - fn render(&self, tera: &Tera) -> Result<String, tera::Error> { 115 - let mut context = Context::new(); 114 + fn render(&self, context: &Context, tera: &Tera) -> Result<String, tera::Error> { 115 + let mut context = context.clone(); 116 116 match &self.content { 117 117 ContentType::Document(doc) => { 118 118 context.insert("document", doc); 119 - context.insert("host", &doc.host); 120 - context.insert("did", &doc.did); 121 119 } 122 120 ContentType::Post(post) => { 123 121 context.insert("post", post); ··· 131 129 } 132 130 133 131 impl Renderable for IndexPage { 134 - fn render(&self, tera: &Tera) -> Result<String, tera::Error> { 135 - let mut context = Context::new(); 132 + fn render(&self, context: &Context, tera: &Tera) -> Result<String, tera::Error> { 133 + let mut context = context.clone(); 136 134 context.insert("content", &self.content); 137 135 tera.render(&self.template, &context) 138 136 }
+2 -2
src/atproto/renderable.rs
··· 1 - use tera::Tera; 1 + use tera::{Context, Tera}; 2 2 3 3 pub trait Renderable { 4 - fn render(&self, tera: &Tera) -> Result<String, tera::Error>; 4 + fn render(&self, context: &Context, tera: &Tera) -> Result<String, tera::Error>; 5 5 }
-4
src/atproto/types/leaflet.rs
··· 14 14 pub publication: Unknown, 15 15 #[serde(rename = "publishedAt")] 16 16 pub published_at: String, 17 - #[serde(skip)] 18 - pub host: String, 19 - #[serde(skip)] 20 - pub did: String, 21 17 } 22 18 23 19 #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
+43 -34
src/generator.rs
··· 2 2 use atrium_api::types::string::AtIdentifier; 3 3 use atrium_api::{agent::atp_agent::AtpAgent, types::TryFromUnknown}; 4 4 use atrium_xrpc_client::reqwest::ReqwestClient; 5 - use tera::{Context, Tera}; 5 + use tera::Tera; 6 6 7 7 use crate::config::Config; 8 8 use crate::templates::filters; ··· 23 23 host: String, 24 24 } 25 25 26 + #[derive(serde::Serialize)] 27 + pub struct ContentTree { 28 + repos: Collection, 29 + documents: Collection, 30 + } 31 + 32 + #[derive(serde::Serialize)] 33 + pub struct Collection { 34 + index: IndexPage, 35 + pages: Vec<ContentPage>, 36 + } 37 + 26 38 pub async fn generate(config: &Config) -> Result<usize, Box<dyn std::error::Error>> { 27 39 let mut tera = match Tera::new("templates/**/*.html") { 28 40 Ok(t) => t, ··· 98 110 std::fs::create_dir_all(&output_root)?; 99 111 100 112 // Create ContentPages for content 101 - let post_pages: Vec<ContentPage> = posts 102 - .into_iter() 103 - .map(|i| ContentPage::new(ContentType::Post(i), "post.html", "posts")) 104 - .collect(); 105 - 106 113 let document_pages: Vec<ContentPage> = documents 107 114 .into_iter() 108 115 .map(|i| ContentPage::new(ContentType::Document(i), "document.html", "documents")) ··· 113 120 .map(|r| ContentPage::new(ContentType::Repo(r), "repo.html", "repos")) 114 121 .collect(); 115 122 123 + let repo_index = IndexPage::new(repo_pages.clone(), "index.html", "repos"); 124 + let document_index = IndexPage::new(document_pages.clone(), "index.html", "documents"); 125 + 126 + // create global context 127 + let content = ContentTree { 128 + repos: Collection { 129 + index: repo_index.clone(), 130 + pages: repo_pages.clone(), 131 + }, 132 + documents: Collection { 133 + index: document_index.clone(), 134 + pages: document_pages.clone(), 135 + }, 136 + }; 137 + let mut context = tera::Context::new(); 138 + context.insert("site", &site); 139 + context.insert("content", &content); 140 + 116 141 // Render individual pages 117 - for pages in [&document_pages, &post_pages, &repo_pages] { 142 + for pages in [&document_pages, &repo_pages] { 118 143 for page in pages.iter() { 119 - let html = page.render(tera)?; 144 + let html = page.render(&context, tera)?; 120 145 let mut path = PathBuf::from(output_root); 121 146 path.push(&page.filepath); 122 147 std::fs::create_dir_all(path.parent().expect("Invalid file path"))?; ··· 128 153 } 129 154 130 155 // Render index pages 131 - let document_index = generate_index(&document_pages, output_root, "documents", tera)?; 156 + generate_index(&document_index, &context, output_root, tera)?; 132 157 counter += 1; 133 158 134 - let repo_index = generate_index(&repo_pages, output_root, "repos", tera)?; 135 - counter += 1; 136 - 137 - let post_index = generate_index(&post_pages, output_root, "posts", tera)?; 159 + generate_index(&repo_index, &context, output_root, tera)?; 138 160 counter += 1; 139 161 140 162 // Render home page 141 - generate_home( 142 - &(document_index, document_pages), 143 - &(post_index, post_pages), 144 - &(repo_index, repo_pages), 145 - output_root, 146 - tera, 147 - )?; 163 + generate_home(&context, output_root, tera)?; 148 164 149 165 Ok(counter) 150 166 } 151 167 152 168 fn generate_home( 153 - documents: &(IndexPage, Vec<ContentPage>), 154 - posts: &(IndexPage, Vec<ContentPage>), 155 - repos: &(IndexPage, Vec<ContentPage>), 169 + context: &tera::Context, 156 170 output_root: &Path, 157 171 tera: &Tera, 158 172 ) -> Result<(), tera::Error> { 159 173 let mut output_path = PathBuf::from(output_root); 160 174 output_path.push("index.html"); 161 175 162 - let mut context = Context::new(); 163 - context.insert("documents", documents); 164 - context.insert("posts", posts); 165 - context.insert("repos", repos); 166 - let html = tera.render("home.html", &context)?; 176 + let html = tera.render("home.html", context)?; 167 177 168 178 std::fs::write(output_path, html)?; 169 179 ··· 171 181 } 172 182 173 183 fn generate_index( 174 - pages: &Vec<ContentPage>, 184 + index_page: &IndexPage, 185 + context: &tera::Context, 175 186 output_root: &Path, 176 - collection: &str, 177 187 tera: &Tera, 178 - ) -> Result<IndexPage, tera::Error> { 179 - let index_page = IndexPage::new(pages.clone(), "index.html", collection); 188 + ) -> Result<(), tera::Error> { 180 189 let mut output_path = PathBuf::from(output_root); 181 190 output_path.push(&index_page.filepath); 182 191 183 - let html = index_page.render(tera)?; 192 + let html = index_page.render(context, tera)?; 184 193 std::fs::write(output_path, html)?; 185 194 186 - Ok(index_page) 195 + Ok(()) 187 196 }
+5 -5
templates/home.html
··· 1 1 {% extends "base.html" %} 2 2 3 - {% block title %}j23n{% endblock %} 3 + {% block title %}{% endblock %} 4 4 5 5 {% block content %} 6 6 {% include "home-blurb.html" ignore missing %} 7 7 8 8 <section id="documents"> 9 - {% set index = documents.0 %} 10 - {% set pages = documents.1 %} 9 + {% set index = content.documents.index %} 10 + {% set pages = content.documents.pages %} 11 11 <h2><a href="{{ index.url | safe }}">{{ index.name | title }}</a></h2> 12 12 <ul> 13 13 {% for document in pages %} ··· 17 17 </section> 18 18 19 19 <section id="repos"> 20 - {% set index = repos.0 %} 21 - {% set pages = repos.1 %} 20 + {% set index = content.repos.index %} 21 + {% set pages = content.repos.pages %} 22 22 <h2><a href="{{ index.url | safe }}">{{ index.name | title }}</a></h2> 23 23 <ul> 24 24 {% for repo in pages %}
+7 -1
templates/macros.html
··· 8 8 {%- elif type == "pub.leaflet.blocks.code" %} 9 9 <pre><code class="{{ block.language }}">{{ block.plaintext }}</code></pre> 10 10 {%- elif type == "pub.leaflet.blocks.image" %} 11 - <p><img src="{{ block.image | blob_to_url(host=host, did=did) | safe }}"></img></p> 11 + <p><img src="{{ block.image | blob_to_url(host=site.host, did=site.did) | safe }}"></img></p> 12 12 {% if block.alt %}<small>{{ block.alt }}</small>{% endif %} 13 13 {%- elif type == "pub.leaflet.blocks.header" %} 14 14 {%- set level = block.level | default(value="3") %} ··· 19 19 <li>{{ self::render_block(block=child.content) }}</li> 20 20 {%- endfor %} 21 21 </ul> 22 + {%- elif type == "pub.leaflet.blocks.blockquote" %} 23 + <blockquote> 24 + <p>{{ block.plaintext }}</p> 25 + </blockquote> 26 + {%- elif type == "pub.leaflet.blocks.horizontalRule" %} 27 + <hr /> 22 28 {%- else %} 23 29 <p>Unknown block type: {{ type }}</p> 24 30 {%- endif %}

History

1 round 0 comments
sign up or login to add to the discussion
hello.j23n.com submitted #0
1 commit
expand
add global context for template rendering
expand 0 comments
pull request successfully merged