blog post thumbnails

This commit is contained in:
Michal Vanko 2024-08-16 20:22:19 +02:00
parent fdfa69c4b4
commit 9b81d70ae2
28 changed files with 178 additions and 32 deletions

View File

@ -5,6 +5,7 @@ segments:
- blog - blog
published: true published: true
date: 2022-02-20T17:50:56.214Z date: 2022-02-20T17:50:56.214Z
thumbnail: /images/uploads/laptopbattery.jpg
tags: tags:
- News - News
- Weekly - Weekly

View File

@ -5,6 +5,7 @@ segments:
- broadcasts - broadcasts
published: true published: true
date: 2022-04-26T20:22:21.191Z date: 2022-04-26T20:22:21.191Z
thumbnail: /images/uploads/deeevbreak2.jpeg
tags: tags:
- DevBreak - DevBreak
--- ---

View File

@ -5,6 +5,7 @@ segments:
- broadcasts - broadcasts
published: true published: true
date: 2022-06-09T20:22:21.191Z date: 2022-06-09T20:22:21.191Z
thumbnail: /images/uploads/deevbreakdoninik.jpeg
tags: tags:
- DevBreak - DevBreak
--- ---

View File

@ -1,16 +1,17 @@
--- ---
layout: blog
title: "Our attempt at Rusty game jam - Weekly #25-2022"
segments: segments:
- blog - blog
- featured - featured
notes: ""
layout: blog
title: "Our attempt at Rusty game jam - Weekly #25-2022"
published: true published: true
date: 2022-06-26T20:02:47.419Z date: 2022-06-26T20:02:47.419Z
thumbnail: /images/uploads/screenshot-from-2022-06-26-22-37-16.png
tags: tags:
- News - News
- Weekly - Weekly
- Development - Development
notes: ""
--- ---
Long time no see! Long time no see!

View File

@ -5,6 +5,7 @@ segments:
- blog - blog
published: true published: true
date: 2022-11-27T19:49:09.204Z date: 2022-11-27T19:49:09.204Z
thumbnail: /images/uploads/image_7115.jpg
tags: tags:
- News - News
- Travel - Travel

View File

@ -5,6 +5,7 @@ segments:
- broadcasts - broadcasts
published: true published: true
date: 2023-01-21T20:22:21.191Z date: 2023-01-21T20:22:21.191Z
thumbnail: /images/uploads/devbreak-4-3-.png
tags: tags:
- DevBreak - DevBreak
--- ---

View File

@ -5,6 +5,7 @@ segments:
- broadcasts - broadcasts
published: true published: true
date: 2023-02-04T20:22:21.191Z date: 2023-02-04T20:22:21.191Z
thumbnail: /images/uploads/devbreak.jpeg
tags: tags:
- DevBreak - DevBreak
--- ---

View File

@ -6,6 +6,7 @@ segments:
- featured - featured
published: true published: true
date: 2023-04-27T21:22:21.191Z date: 2023-04-27T21:22:21.191Z
thumbnail: /images/uploads/teta.png
tags: tags:
- Presentation - Presentation
- Keyboards - Keyboards

View File

@ -5,6 +5,7 @@ segments:
- blog - blog
published: true published: true
date: 2023-06-24T16:34:45.527Z date: 2023-06-24T16:34:45.527Z
thumbnail: /images/uploads/img_9715-rotated.jpg
tags: tags:
- News - News
- Personal - Personal
@ -44,4 +45,4 @@ Don't believe someone just their words. Believe in actions. And if you have a ha
You've been so healthy that you've been released home early. Your first day at home has been great. You thought me that 5 AM is a great time to wake up. The sun is already up and shining so we can shine as well. Your whole family loves you. I love your Mom. I love You. Thank you for coming into our lives. We will always love you. You've been so healthy that you've been released home early. Your first day at home has been great. You thought me that 5 AM is a great time to wake up. The sun is already up and shining so we can shine as well. Your whole family loves you. I love your Mom. I love You. Thank you for coming into our lives. We will always love you.
![Your first day at home. You shared the happiness with us.](/images/uploads/20230621_204051.jpg "Your first day at home. You shared the happiness with us.") ![Your first day at home. You shared the happiness with us.](/images/uploads/20230621_204051.jpg "Your first day at home. You shared the happiness with us.")

View File

@ -6,6 +6,7 @@ segments:
- featured - featured
published: true published: true
date: 2023-08-29T19:34:17.071Z date: 2023-08-29T19:34:17.071Z
thumbnail: /images/uploads/20230226_130037.jpg
tags: tags:
- News - News
- Keyboards - Keyboards

View File

@ -14,6 +14,10 @@ layout {
pane { pane {
command "just" command "just"
args "tailwind" args "tailwind"
}
pane {
command "just"
args "decap_server"
} }
} }
pane size=2 borderless=true { pane size=2 borderless=true {

View File

@ -30,3 +30,6 @@ opt-level = 1
lto = "thin" lto = "thin"
panic = "unwind" panic = "unwind"
strip = false strip = false
[profile.dev.package.askama_derive]
opt-level = 3

View File

@ -7,7 +7,6 @@ pub const BLOG_POST_PATH: &str = "../_posts/blog";
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct BlogPostMetadata { pub struct BlogPostMetadata {
pub layout: String,
pub title: String, pub title: String,
pub segments: Vec<String>, pub segments: Vec<String>,
pub published: bool, pub published: bool,

View File

@ -5,12 +5,11 @@ use crate::post_utils::{post_listing::get_post_list, post_parser::ParseResult};
use super::blog_post_model::{BlogPostMetadata, BLOG_POST_PATH}; use super::blog_post_model::{BlogPostMetadata, BLOG_POST_PATH};
pub async fn get_featured_blog_posts() -> Result<Vec<ParseResult<BlogPostMetadata>>, StatusCode> { pub async fn get_featured_blog_posts() -> Result<Vec<ParseResult<BlogPostMetadata>>, StatusCode> {
let post_list = get_post_list::<BlogPostMetadata>(BLOG_POST_PATH).await?; let mut post_list = get_post_list::<BlogPostMetadata>(BLOG_POST_PATH).await?;
post_list.retain(|post| post.metadata.segments.contains(&"featured".to_string()));
post_list.retain(|post| post.metadata.published);
post_list.sort_by_key(|post| post.metadata.date);
post_list.reverse();
let featured_posts = post_list Ok(post_list)
.into_iter()
.filter(|post| post.metadata.segments.contains(&"featured".to_string()))
.collect();
Ok(featured_posts)
} }

View File

@ -8,6 +8,7 @@ mod components;
mod feed; mod feed;
mod filters; mod filters;
mod pages; mod pages;
mod picture_generator;
mod post_utils; mod post_utils;
mod projects; mod projects;
mod router; mod router;

View File

@ -30,6 +30,7 @@ pub async fn render_blog_post_list(
let site_footer = render_site_footer().await?; let site_footer = render_site_footer().await?;
let mut post_list = get_post_list::<BlogPostMetadata>(BLOG_POST_PATH).await?; let mut post_list = get_post_list::<BlogPostMetadata>(BLOG_POST_PATH).await?;
post_list.sort_by_key(|post| post.metadata.date); post_list.sort_by_key(|post| post.metadata.date);
post_list.retain(|post| post.metadata.published);
post_list.reverse(); post_list.reverse();
let posts = match &tag { let posts = match &tag {

View File

@ -0,0 +1,24 @@
/*!
This is going to be an attempt for creating HTML markup for serving and generating images
for the most common PIXEL_DENSITIES.
It should create `<picture>` elements with following features:
- least amount of needed arguments
- for each pixel density it should have a definition in `srcset`
- create a `avif` type for the image for each pixel_density
- create an image in the original format for each pixel_density
- support case of `svg` therefore not doing any of the pixel_density logic
These features might be considered later:
- support case for art direction (different pictures for different screen sizes)
TODO: figure wether `height` or `width` have to be known ahead of time
## Usage
It can be used from the rust code
It should be used from the templates as well
*/
pub mod picture_markup_generator;

View File

@ -0,0 +1,101 @@
use std::path::Path;
pub const PIXEL_DENSITIES: [f64; 5] = [1., 1.5, 2., 3., 4.];
#[derive(Debug, PartialEq)]
pub enum ExportFormat {
JPG,
AVIF,
SVG,
PNG,
}
pub fn generate_picture_markup(orig_img_path: &str, width: u32, height: u32) -> String {
let exported_formats = get_export_formats(&orig_img_path);
for export_format in exported_formats {
// TODO get original img resolution and determine how many exports are going to be needed
// let orig_img_resolution =
// let resolutions = get_resolutions(width, height);
let resolutions = vec![(300, 200), (450, 300), (600, 400), (900, 600), (1200, 800)];
let generated_paths = get_generated_paths(orig_img_path, resolutions);
}
let result = format!("<picture></picture>");
result
}
fn get_generated_paths(orig_img_path: &str, &resolutions: Vec<(i32, i32)>) -> Vec<String> {
}
#[test]
fn test_get_generated_paths {
let orig_img_path = "./images/uploads/img_name.jpg";
let resolutions = vec![(300, 200), (450, 300), (600, 400), (900, 600), (1200, 800)];
assert_eq!(get_generated_paths(orig_img_path,&resolutions), vec![])
}
// TODO get original img resolution and determine how many exports are going to be needed
fn get_resolutions(orig_width: i32, orig_height: i32, width: i32, height: i32) -> Vec<(i32, i32)> {
todo!("get original img resolution and determine how many exports are going to be needed")
}
fn generate_srcset(new_path: &str, width: u32, height: u32) -> &str {
todo!("generate srcset")
}
fn get_export_formats(orig_img_path: &str) -> Vec<ExportFormat> {
let path = Path::new(&orig_img_path).extension().and_then(|ext| ext.to_str());
match path {
Some("jpg" | "jpeg") => vec![ExportFormat::AVIF, ExportFormat::JPG]
Some("png") => vec![ExportFormat::AVIF, ExportFormat::PNG]
Some(_) | None => vec![]
}
}
#[test]
fn test_get_export_formats {
assert_eq!(get_export_formats("./images/uploads/img_name.jpg"), vec![ExportFormat::AVIF, ExportFormat::JPG])
}
#[test]
fn test_generate_srcset() {
let width = 400;
let height = 200;
let orig_img_path = "./images/uploads/img_name.jpg";
let result = "./generated_images/images/uploads/img_name_400x200.avif 1x, ./generated_images/images/uploads/img_name_500x300.avif 1.5x, ./generated_images/images/uploads/img_name_800x400.avif 2x, ./generated_images/images/uploads/img_name_1200x600.avif 3x, ./generated_images/images/uploads/img_name_1600x800.avif 4x";
assert_eq!(generate_srcset(orig_img_path, width, height), result)
}
#[test]
fn test_generate_picture_markup() {
let width = 300;
let height = 200;
let orig_img_path = "./images/uploads/img_name.jpg";
let result = r#"""
<picture>
<source
srcset="./generated_images/images/uploads/img_name_300x200.avif 1x, ./generated_images/images/uploads/img_name_450x300.avif 1.5x, ./generated_images/images/uploads/img_name_600x400.avif 2x, ./generated_images/images/uploads/img_name_900x600.avif 3x, ./generated_images/images/uploads/img_name_1200x800.avif 4x"
type="image/avif"
>
<source
srcset="./generated_images/images/uploads/img_name_300x200.jpg 1x, ./generated_images/images/uploads/img_name_450x300.jpg 1.5x, ./generated_images/images/uploads/img_name_600x400.jpg 2x, ./generated_images/images/uploads/img_name_900x600.jpg 3x, ./generated_images/images/uploads/img_name_1200x800.jpg 4x"
type="image/jpeg"
>
<img
src="./generated_images/images/uploads/img_name_300x200.jpg"
width="300"
height="200"
>
</picture>
"""#;
assert_eq!(
generate_picture_markup(orig_img_path, width, height),
result
);
}

View File

@ -30,11 +30,8 @@ pub async fn get_post_list<'de, Metadata: DeserializeOwned>(
.unwrap_or_else(|_| "DEV".to_owned()) .unwrap_or_else(|_| "DEV".to_owned())
.eq("PROD") .eq("PROD")
{ {
posts = posts posts.retain(|post| !post.slug.starts_with("dev"))
.into_iter()
.filter(|post| !post.slug.starts_with("dev"))
.collect()
} }
return Ok(posts); Ok(posts)
} }

View File

@ -1,5 +1,5 @@
/* /*
! tailwindcss v3.4.7 | MIT License | https://tailwindcss.com ! tailwindcss v3.4.9 | MIT License | https://tailwindcss.com
*/ */
/* /*
@ -672,10 +672,6 @@ video {
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
} }
.aspect-\[4\/3\] {
aspect-ratio: 4/3;
}
.h-0 { .h-0 {
height: 0px; height: 0px;
} }
@ -832,11 +828,6 @@ video {
object-fit: contain; object-fit: contain;
} }
.object-cover {
-o-object-fit: cover;
object-fit: cover;
}
.p-0 { .p-0 {
padding: 0px; padding: 0px;
} }

View File

@ -1,9 +1,11 @@
<article class="grid grid-cols-[1fr_2fr] grid-flow-col gap-4"> <article class="grid grid-cols-[1fr_2fr] grid-flow-col gap-4">
<aside class="row-span-3"> <aside class="row-span-3">
<!-- TODO <figure> --> <!-- TODO <figure> -->
<svg aria-hidden="true" class="h-12 w-12 fill-blue-950"> <!-- TODO Thumbnail -->
<use xlink:href="/svg/icons-sprite.svg#mail" /> <!-- <svg aria-hidden="true" class="h-12 w-12 fill-blue-950"> -->
</svg> <!-- <use xlink:href="/svg/icons-sprite.svg#mail" /> -->
<!-- </svg> -->
<figure>
</aside> </aside>
<header> <header>
<h3 class="text-lg font-bold mb-1">{{post.metadata.title}}</h3> <h3 class="text-lg font-bold mb-1">{{post.metadata.title}}</h3>

View File

@ -54,7 +54,7 @@
<ul class="mx-5"> <ul class="mx-5">
{% for post in featured_blog_posts %} {% for post in featured_blog_posts %}
<li> <li>
{% include "components/post_preview.html" %} {% include "components/blog_post_preview.html" %}
<hr class="border-blue-950 my-5"> <hr class="border-blue-950 my-5">
</li> </li>
{% endfor %} {% endfor %}

BIN
static/images/uploads/deeevbreak2.jpeg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
static/images/uploads/deevbreakdoninik.jpeg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
static/images/uploads/devbreak-4-3-.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
static/images/uploads/devbreak.jpeg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
static/images/uploads/teta.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -17,7 +17,6 @@ collections:
create: true # Allow users to create new documents in this collection create: true # Allow users to create new documents in this collection
slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., YYYY-MM-DD-title.md slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., YYYY-MM-DD-title.md
fields: # The fields for each document, usually in front matter fields: # The fields for each document, usually in front matter
- { label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' }
- { label: 'Title', name: 'title', widget: 'string' } - { label: 'Title', name: 'title', widget: 'string' }
- label: 'Segments' - label: 'Segments'
name: 'segments' name: 'segments'