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:
97
src/main.rs
97
src/main.rs
@@ -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))}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user