From 1d67f611fc552861ce8cb364c41da1f18d302ace Mon Sep 17 00:00:00 2001 From: Pantonshire Date: Wed, 25 May 2022 23:09:58 +0100 Subject: [PATCH] Styling for articles --- blog_server/src/codeblock.rs | 16 +++++--- blog_server/src/post.rs | 18 ++++++++- blog_server/src/service/post.rs | 21 +++++++--- static/styles/main.css | 68 ++++++++++++++++++++++++++++++--- 4 files changed, 105 insertions(+), 18 deletions(-) diff --git a/blog_server/src/codeblock.rs b/blog_server/src/codeblock.rs index 3e21c4b..2b810d3 100644 --- a/blog_server/src/codeblock.rs +++ b/blog_server/src/codeblock.rs @@ -54,12 +54,18 @@ impl CodeBlockRenderer { let html_out = html_gen.finalize(); - //TODO: show context & language - html! { - pre .codeblock { - code { - (PreEscaped(html_out)) + .codeblock { + @if context.is_some() || !lang.is_empty() { + .codeblock_banner { + span .codeblock_language { (lang) } + span .codeblock_context { (context.unwrap_or("")) } + } + } + pre .codeblock_code { + code { + (PreEscaped(html_out)) + } } } } diff --git a/blog_server/src/post.rs b/blog_server/src/post.rs index f398971..5ee3a39 100644 --- a/blog_server/src/post.rs +++ b/blog_server/src/post.rs @@ -2,7 +2,7 @@ use std::{borrow, error, fmt, ops}; use chrono::{DateTime, Utc}; use libshire::{strings::ShString22, uuid::{Uuid, UuidV5Error}}; -use maud::{Markup, PreEscaped}; +use maud::{Markup, PreEscaped, html}; use crate::codeblock::CodeBlockRenderer; @@ -76,6 +76,7 @@ pub struct Post { uuid: Uuid, id: PostId, title: String, + subtitle: Option, author: String, html: Markup, tags: Vec, @@ -96,6 +97,10 @@ impl Post { &self.title } + pub fn subtitle(&self) -> Option<&str> { + self.subtitle.as_deref() + } + pub fn author(&self) -> &str { &self.author } @@ -169,6 +174,7 @@ impl Post { uuid, id, title: mdpost.title, + subtitle: mdpost.subtitle, author: mdpost.author, html: PreEscaped(html_buf), tags: mdpost.tags, @@ -226,6 +232,12 @@ impl<'e, 'p, I> Iterator for PostMdParser<'p, I> where I: Iterator { + Event::Html(CowStr::Boxed(html! { + code .inline_code { (code) } + }.into_string().into_boxed_str())) + }, + event => { match &event { Event::Start(Tag::Link(LinkType::Inline | LinkType::Autolink, destination, _title)) => { @@ -253,6 +265,8 @@ struct HeaderNode { #[knuffel(child, unwrap(argument))] title: String, #[knuffel(child, unwrap(argument))] + subtitle: Option, + #[knuffel(child, unwrap(argument))] author: String, #[knuffel(children(name="tag"))] tags: Vec, @@ -268,6 +282,7 @@ struct TagNode { struct MdPost { markdown: String, title: String, + subtitle: Option, author: String, tags: Vec, } @@ -287,6 +302,7 @@ impl MdPost { Ok(Self { markdown: md.to_owned(), title: header.title, + subtitle: header.subtitle, author: header.author, tags: header.tags.into_iter().map(|tag| tag.tag.into()).collect(), }) diff --git a/blog_server/src/service/post.rs b/blog_server/src/service/post.rs index 0e6f488..83cff61 100644 --- a/blog_server/src/service/post.rs +++ b/blog_server/src/service/post.rs @@ -1,7 +1,10 @@ use axum::extract::{Extension, Path}; use maud::html; -use crate::posts_store::ConcurrentPostsStore; +use crate::{ + posts_store::ConcurrentPostsStore, + template, +}; use super::response::{Error, Html}; pub async fn handle( @@ -17,13 +20,19 @@ pub async fn handle( .with_crawler_permissive() .with_title_owned(post.title().to_owned()) .with_head(html! { + link href="/static/styles/main.css" rel="stylesheet"; link href="/static/styles/code.css" rel="stylesheet"; }) - .with_body(html! { - h1 { (post.title()) } - p { "by " (post.author()) } - article { + .with_body(template::main_page(html! { + section .article_header { + h1 .article_title { (post.title()) } + @if let Some(subtitle) = post.subtitle() { + p .article_subtitle { (subtitle) } + } + p .article_published_date { "Published " (post.created().format("%Y/%m/%d")) } + } + article .article_content { (post.html()) } - })) + }))) } diff --git a/static/styles/main.css b/static/styles/main.css index 8c94305..2bbedd4 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -45,7 +45,6 @@ body { grid-template-rows: auto 1fr auto; margin: 0; padding: 0; - /* font-family: Gill Sans, Gill Sans MT, Calibri, sans-serif; */ font-family: Rubik, sans-serif; font-size: 1.1rem; font-weight: 300; @@ -59,15 +58,12 @@ body { } #page_nav { - /* background-color: #F7B801; */ - /* background-color: #7678ED; */ display: flex; flex-direction: row; justify-content: space-between; padding: 1rem 1rem; margin: 0 auto; max-width: 60rem; - /* box-shadow: 0px 2px 10px #B8B8B8; */ } #page_nav #title_box { @@ -164,8 +160,6 @@ h1, h2 { } figure { - /* display: flex; - flex-direction: column; */ width: fit-content; margin: 0; } @@ -188,6 +182,68 @@ li { margin-bottom: 0.5rem; } +.article_header { + padding-bottom: 1rem; + margin-top: 0.5rem; + margin-bottom: 2rem; + border-bottom: 2px solid #94BFBE; +} + +.article_title { + font-size: 3rem; + margin-top: 0.5rem; + margin-bottom: 1rem; +} + +.article_subtitle { + font-size: 1.2rem; + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} + +.article_published_date { + color: #898989; + font-size: 1rem; + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} + +.codeblock { + background-color: #FAF9F6; + border-radius: 5px; + font-size: 1.1rem; + line-height: 1.4; +} + +.codeblock_banner { + display: flex; + justify-content: space-between; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + color: white; +} + +.codeblock_code { + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.5rem; + padding-bottom: 1rem; +} + +.inline_code { + background-color: #F0F0F0; + padding: 0.1rem 0.2rem; + border-radius: 5px; +} + +.codeblock_banner { + background-color: #94BFBE; +} + /* Palette #94BFBE