1
0
mirror of https://gitlab.com/Anson-Projects/zine.git synced 2025-07-27 08:41:25 +00:00

Make site look (more) like a newspaper

This commit is contained in:
2024-02-10 20:12:38 +00:00
parent 150b4aa059
commit e77d2b9ab6
5 changed files with 660 additions and 28 deletions

View File

@@ -6,6 +6,7 @@ use feed_rs::model::Entry;
use feed_rs::parser;
use maud::{html, Markup};
use reqwest::blocking::get;
use scraper::{Html, Selector};
use std::cmp::Reverse;
use std::error::Error;
use std::fs;
@@ -16,36 +17,96 @@ use std::path::Path;
fn fetch_feed(url: &str) -> Result<Vec<Entry>, Box<dyn Error>> {
let content = get(url)?.text()?;
let feed = parser::parse(content.as_bytes())?;
println!("Feed {} returned {} items", url, feed.entries.len());
Ok(feed.entries)
}
fn create_html_card(entry: &Entry) -> Markup {
let title = entry
.title
.as_ref()
.map_or_else(|| "".to_string(), |t| t.content.clone());
let link = entry.links.first().unwrap();
// Attempt to find the first thumbnail URL in the media content
let image_src = entry
.media
.iter()
.flat_map(|media| &media.thumbnails)
.map(|thumbnail| &thumbnail.image.uri)
.next()
.map_or_else(|| "".to_string(), |uri| uri.to_string());
let description = entry.content.as_ref().map_or_else(
|| {
entry
.summary
.as_ref()
.map_or_else(|| "".to_string(), |summary| summary.content.clone())
},
|content| {
content
.body
.as_ref()
.map_or_else(|| "".to_string(), |body| body.clone())
},
);
let cleaned_description = strip_html_tags(&description);
let truncated_description = truncate_description(&cleaned_description, 500); // Truncate description to 100 characters
html! {
a.card-link href=(link.href) target=("_blank") {
div.card {
h2 { (title) }
@if !image_src.is_empty() {
img src=(image_src) alt="Entry image";
}
p { (truncated_description) }
}
}
}
}
fn truncate_description(description: &str, max_length: usize) -> String {
let description_trimmed = description.trim();
if description_trimmed.len() > max_length {
format!("{}...", &description_trimmed[..max_length])
} else {
description_trimmed.to_string()
}
}
fn strip_html_tags(html: &str) -> String {
let document = Html::parse_document(html);
// Use the wildcard selector to select all nodes and extract their text.
let selector = Selector::parse("*").unwrap();
let mut text_content = String::new();
for element in document.select(&selector) {
let text = element.text().collect::<Vec<_>>().join(" ");
text_content.push_str(&text);
text_content.push(' ');
}
text_content.trim().to_string()
}
fn generate_html(entries: Vec<Entry>) -> Markup {
html! {
(maud::DOCTYPE)
html {
head {
title { "Anson Zine" }
title { "Anson's Zine" }
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css";
link rel="stylesheet" href="style.css";
}
body {
h1 { "Aggregated Feed" }
ul {
h1 { "Anson's Aggregated Feed" }
div class="cards-container" {
@for entry in entries {
li {
@if let Some(link) = entry.links.first() {
a href=(link.href) {
@if let Some(title) = entry.title {
(title.content)
}
}
}
p {
({
entry.published.unwrap_or(entry.updated.unwrap_or_default())
})
}
}
{(create_html_card(&entry))}
}
}
}