This commit is contained in:
181
src/generator.rs
181
src/generator.rs
@ -94,6 +94,46 @@ impl Generator {
|
||||
fs::copy(path, &dest_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy files from atproto-auth-widget dist (if available)
|
||||
let widget_dist = self.base_path.join("atproto-auth-widget/dist");
|
||||
if widget_dist.exists() {
|
||||
for entry in WalkDir::new(&widget_dist).min_depth(1) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
let relative_path = path.strip_prefix(&widget_dist)?;
|
||||
let dest_path = public_dir.join(relative_path);
|
||||
|
||||
if path.is_dir() {
|
||||
fs::create_dir_all(&dest_path)?;
|
||||
} else {
|
||||
if let Some(parent) = dest_path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
fs::copy(path, &dest_path)?;
|
||||
}
|
||||
}
|
||||
println!("{} widget files from dist", "Copied".yellow());
|
||||
}
|
||||
|
||||
// Handle client-metadata.json based on environment (fallback)
|
||||
let is_production = std::env::var("PRODUCTION").unwrap_or_default() == "true";
|
||||
let metadata_dest = public_dir.join("client-metadata.json");
|
||||
|
||||
// First try to get from widget dist (preferred)
|
||||
let widget_metadata = widget_dist.join("client-metadata.json");
|
||||
if widget_metadata.exists() {
|
||||
fs::copy(&widget_metadata, &metadata_dest)?;
|
||||
println!("{} client-metadata.json from widget", "Using".yellow());
|
||||
} else if is_production {
|
||||
// Fallback to local static files
|
||||
let prod_metadata = static_dir.join("client-metadata-prod.json");
|
||||
if prod_metadata.exists() {
|
||||
fs::copy(&prod_metadata, &metadata_dest)?;
|
||||
println!("{} production client-metadata.json (fallback)", "Using".yellow());
|
||||
}
|
||||
}
|
||||
|
||||
println!("{} static files", "Copied".cyan());
|
||||
}
|
||||
|
||||
@ -144,11 +184,16 @@ impl Generator {
|
||||
|
||||
let html_content = self.markdown_processor.render(&content)?;
|
||||
|
||||
let slug = path
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("post")
|
||||
.to_string();
|
||||
// Use slug from frontmatter if available, otherwise derive from filename
|
||||
let slug = frontmatter.get("slug")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
path.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("post")
|
||||
.to_string()
|
||||
});
|
||||
|
||||
let mut post = Post {
|
||||
title: frontmatter.get("title")
|
||||
@ -211,7 +256,34 @@ impl Generator {
|
||||
}
|
||||
|
||||
async fn generate_index(&self, posts: &[Post]) -> Result<()> {
|
||||
let context = self.template_engine.create_context(&self.config, posts)?;
|
||||
// Enhance posts with additional metadata for timeline view
|
||||
let enhanced_posts: Vec<serde_json::Value> = posts.iter().map(|post| {
|
||||
let excerpt = self.extract_excerpt(&post.content);
|
||||
let markdown_url = format!("/posts/{}.md", post.slug);
|
||||
let translation_url = if let Some(ref translations) = post.translations {
|
||||
translations.first().map(|t| t.url.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
serde_json::json!({
|
||||
"title": post.title,
|
||||
"date": post.date,
|
||||
"content": post.content,
|
||||
"slug": post.slug,
|
||||
"url": post.url,
|
||||
"tags": post.tags,
|
||||
"excerpt": excerpt,
|
||||
"markdown_url": markdown_url,
|
||||
"translation_url": translation_url,
|
||||
"language": self.config.site.language
|
||||
})
|
||||
}).collect();
|
||||
|
||||
let mut context = tera::Context::new();
|
||||
context.insert("config", &self.config.site);
|
||||
context.insert("posts", &enhanced_posts);
|
||||
|
||||
let html = self.template_engine.render("index.html", &context)?;
|
||||
|
||||
let output_path = self.base_path.join("public/index.html");
|
||||
@ -223,7 +295,33 @@ impl Generator {
|
||||
async fn generate_post_page(&self, post: &Post) -> Result<()> {
|
||||
let mut context = tera::Context::new();
|
||||
context.insert("config", &self.config.site);
|
||||
context.insert("post", post);
|
||||
|
||||
// Create enhanced post with additional URLs
|
||||
let mut enhanced_post = post.clone();
|
||||
enhanced_post.url = format!("/posts/{}.html", post.slug);
|
||||
|
||||
// Add markdown view URL
|
||||
let markdown_url = format!("/posts/{}.md", post.slug);
|
||||
|
||||
// Add translation URLs if available
|
||||
let translation_urls: Vec<String> = if let Some(ref translations) = post.translations {
|
||||
translations.iter().map(|t| t.url.clone()).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
context.insert("post", &serde_json::json!({
|
||||
"title": enhanced_post.title,
|
||||
"date": enhanced_post.date,
|
||||
"content": enhanced_post.content,
|
||||
"slug": enhanced_post.slug,
|
||||
"url": enhanced_post.url,
|
||||
"tags": enhanced_post.tags,
|
||||
"ai_comment": enhanced_post.ai_comment,
|
||||
"markdown_url": markdown_url,
|
||||
"translation_url": translation_urls.first(),
|
||||
"language": self.config.site.language
|
||||
}));
|
||||
|
||||
let html = self.template_engine.render_with_context("post.html", &context)?;
|
||||
|
||||
@ -232,6 +330,9 @@ impl Generator {
|
||||
|
||||
let output_path = output_dir.join(format!("{}.html", post.slug));
|
||||
fs::write(output_path, html)?;
|
||||
|
||||
// Generate markdown view
|
||||
self.generate_markdown_view(post).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -260,6 +361,72 @@ impl Generator {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_excerpt(&self, html_content: &str) -> String {
|
||||
// Simple excerpt extraction - take first 200 characters of text content
|
||||
let text_content = html_content
|
||||
.replace("<p>", "")
|
||||
.replace("</p>", " ")
|
||||
.replace("<br>", " ")
|
||||
.replace("<br/>", " ");
|
||||
|
||||
// Remove HTML tags with a simple regex-like approach
|
||||
let mut text = String::new();
|
||||
let mut in_tag = false;
|
||||
for ch in text_content.chars() {
|
||||
match ch {
|
||||
'<' => in_tag = true,
|
||||
'>' => in_tag = false,
|
||||
_ if !in_tag => text.push(ch),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let excerpt = text.trim().chars().take(200).collect::<String>();
|
||||
if text.len() > 200 {
|
||||
format!("{}...", excerpt)
|
||||
} else {
|
||||
excerpt
|
||||
}
|
||||
}
|
||||
|
||||
async fn generate_markdown_view(&self, post: &Post) -> Result<()> {
|
||||
// Find original markdown file
|
||||
let posts_dir = self.base_path.join("content/posts");
|
||||
|
||||
// Try to find the markdown file by checking all files in posts directory
|
||||
for entry in fs::read_dir(&posts_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if let Some(extension) = path.extension() {
|
||||
if extension == "md" {
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let (frontmatter, _) = self.markdown_processor.parse_frontmatter(&content)?;
|
||||
|
||||
// Check if this file has the same slug
|
||||
let file_slug = frontmatter.get("slug")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or_else(|| {
|
||||
path.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("")
|
||||
});
|
||||
|
||||
if file_slug == post.slug {
|
||||
let output_dir = self.base_path.join("public/posts");
|
||||
fs::create_dir_all(&output_dir)?;
|
||||
|
||||
let output_path = output_dir.join(format!("{}.md", post.slug));
|
||||
fs::write(output_path, content)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
|
Reference in New Issue
Block a user