Compare commits

..

No commits in common. "6f7b9b73506ae4a2e298db8d44807b9f2f0ccbd2" and "41228d55b6c5370c797fd54c829bd1ea374b4e63" have entirely different histories.

9 changed files with 35 additions and 76 deletions

View file

@ -1,7 +1,7 @@
--- ---
title: README title: "README"
description: the README.md file of this project description: "the README.md file of this project"
author: slonkazoid author: "slonkazoid"
created_at: 2024-04-18T04:15:26+03:00 created_at: 2024-04-18T04:15:26+03:00
--- ---
@ -14,8 +14,6 @@ blazingly fast markdown blog software written in rust memory safe
- [x] RSS - [x] RSS
- [x] finish writing this document - [x] finish writing this document
- [x] document config - [x] document config
- [ ] blog thumbnail and favicon
- [x] alt text for post icon
- [ ] extend syntect options - [ ] extend syntect options
- [ ] general cleanup of code - [ ] general cleanup of code
- [ ] better error reporting and error pages - [ ] better error reporting and error pages
@ -48,7 +46,6 @@ date_format = "RFC3339" # format string used to format dates in the backend
# so the date can be formatted by the browser. # so the date can be formatted by the browser.
# format: https://docs.rs/chrono/latest/chrono/format/strftime/index.html#specifiers # format: https://docs.rs/chrono/latest/chrono/format/strftime/index.html#specifiers
js_enable = true # enable javascript (required for above) js_enable = true # enable javascript (required for above)
default_color = "#f5c2e7" # default embed color, optional
[rss] [rss]
enable = false # serve an rss field under /feed.xml enable = false # serve an rss field under /feed.xml
@ -58,7 +55,6 @@ link = "https://..." # public url of the blog, required if rss is enabled
[dirs] [dirs]
posts = "posts" # where posts are stored posts = "posts" # where posts are stored
media = "media" # directory served under /media/ media = "media" # directory served under /media/
static = "static" # directory server under /static/ (css and js)
[http] [http]
host = "0.0.0.0" # ip to listen on host = "0.0.0.0" # ip to listen on
@ -129,22 +125,15 @@ every post **must** begin with a **valid** front matter. else it wont be listed
in / & /posts, and when you navigate to it, you will be met with an error page. in / & /posts, and when you navigate to it, you will be met with an error page.
the error page will tell you what the problem is. the error page will tell you what the problem is.
full example: example:
```md ```md
--- ---
title: My first post # title of the post title: "README"
description: The first post on this awesome blog! # short description of the post description: "the README.md file of this project"
author: Blubber256 # author of the post author: "slonkazoid"
icon: /media/first-post/icon.png # icon/thumbnail of post used in embeds created_at: 2024-04-18T04:15:26+03:00
icon_alt: Picture of a computer running DOOM #modified_at: ... # see above
color: "#00aacc" # color of post, also used in embeds
created_at: 2024-04-18T04:15:26+03:00 # date of writing, this is highly
# recommended if you are on a system which doesnt have btime (like musl),
# because this is fetched from file stats by default
#modified_at: ... # see above. this is also fetched from the filesystem
tags: # tags, or keywords, used in meta and also in the ui
- lifestyle
--- ---
``` ```

View file

@ -27,26 +27,24 @@ pub struct AppState {
#[derive(Template)] #[derive(Template)]
#[template(path = "index.html")] #[template(path = "index.html")]
struct IndexTemplate<'a> { struct IndexTemplate {
title: &'a str, title: String,
description: &'a str, description: String,
posts: Vec<PostMetadata>, posts: Vec<PostMetadata>,
rss: bool, rss: bool,
df: &'a DateFormat, df: DateFormat,
js: bool, js: bool,
color: Option<&'a str>,
} }
#[derive(Template)] #[derive(Template)]
#[template(path = "post.html")] #[template(path = "post.html")]
struct PostTemplate<'a> { struct PostTemplate {
meta: &'a PostMetadata, meta: PostMetadata,
rendered: String, rendered: String,
rendered_in: RenderStats, rendered_in: RenderStats,
markdown_access: bool, markdown_access: bool,
df: &'a DateFormat, df: DateFormat,
js: bool, js: bool,
color: Option<&'a str>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -56,24 +54,22 @@ struct QueryParams {
num_posts: Option<usize>, num_posts: Option<usize>,
} }
async fn index<'a>( async fn index(
State(AppState { config, posts }): State<AppState>, State(AppState { config, posts }): State<AppState>,
Query(query): Query<QueryParams>, Query(query): Query<QueryParams>,
) -> AppResult<Response> { ) -> AppResult<IndexTemplate> {
let posts = posts let posts = posts
.get_max_n_post_metadata_with_optional_tag_sorted(query.num_posts, query.tag.as_ref()) .get_max_n_post_metadata_with_optional_tag_sorted(query.num_posts, query.tag.as_ref())
.await?; .await?;
Ok(IndexTemplate { Ok(IndexTemplate {
title: &config.title, title: config.title.clone(),
description: &config.description, description: config.description.clone(),
posts, posts,
rss: config.rss.enable, rss: config.rss.enable,
df: &config.date_format, df: config.date_format.clone(),
js: config.js_enable, js: config.js_enable,
color: config.default_color.as_deref(), })
}
.into_response())
} }
async fn all_posts( async fn all_posts(
@ -151,16 +147,18 @@ async fn post(
Path(name): Path<String>, Path(name): Path<String>,
) -> AppResult<Response> { ) -> AppResult<Response> {
match posts.get_post(&name).await? { match posts.get_post(&name).await? {
ReturnedPost::Rendered(ref meta, rendered, rendered_in) => Ok(PostTemplate { ReturnedPost::Rendered(meta, rendered, rendered_in) => {
let page = PostTemplate {
meta, meta,
rendered, rendered,
rendered_in, rendered_in,
markdown_access: config.markdown_access, markdown_access: config.markdown_access,
df: &config.date_format, df: config.date_format.clone(),
js: config.js_enable, js: config.js_enable,
color: meta.color.as_deref().or(config.default_color.as_deref()), };
Ok(page.into_response())
} }
.into_response()),
ReturnedPost::Raw(body, content_type) => { ReturnedPost::Raw(body, content_type) => {
Ok(([(CONTENT_TYPE, content_type)], body).into_response()) Ok(([(CONTENT_TYPE, content_type)], body).into_response())
} }

View file

@ -75,7 +75,6 @@ pub struct Config {
pub markdown_access: bool, pub markdown_access: bool,
pub date_format: DateFormat, pub date_format: DateFormat,
pub js_enable: bool, pub js_enable: bool,
pub default_color: Option<String>,
pub rss: RssConfig, pub rss: RssConfig,
pub dirs: DirsConfig, pub dirs: DirsConfig,
pub http: HttpConfig, pub http: HttpConfig,
@ -91,7 +90,6 @@ impl Default for Config {
markdown_access: true, markdown_access: true,
date_format: Default::default(), date_format: Default::default(),
js_enable: true, js_enable: true,
default_color: Some("#f5c2e7".into()),
// i have a love-hate relationship with serde // i have a love-hate relationship with serde
// it was engimatic at first, but then i started actually using it // it was engimatic at first, but then i started actually using it
// writing my own serialize and deserialize implementations.. spending // writing my own serialize and deserialize implementations.. spending

View file

@ -27,8 +27,6 @@ struct FrontMatter {
pub description: String, pub description: String,
pub author: String, pub author: String,
pub icon: Option<String>, pub icon: Option<String>,
pub icon_alt: Option<String>,
pub color: Option<String>,
pub created_at: Option<DateTime<Utc>>, pub created_at: Option<DateTime<Utc>>,
pub modified_at: Option<DateTime<Utc>>, pub modified_at: Option<DateTime<Utc>>,
#[serde(default)] #[serde(default)]
@ -48,8 +46,6 @@ impl FrontMatter {
description: self.description, description: self.description,
author: self.author, author: self.author,
icon: self.icon, icon: self.icon,
icon_alt: self.icon_alt,
color: self.color,
created_at: self.created_at.or_else(|| created.map(|t| t.into())), created_at: self.created_at.or_else(|| created.map(|t| t.into())),
modified_at: self.modified_at.or_else(|| modified.map(|t| t.into())), modified_at: self.modified_at.or_else(|| modified.map(|t| t.into())),
tags: self.tags.into_iter().collect(), tags: self.tags.into_iter().collect(),

View file

@ -17,8 +17,6 @@ pub struct PostMetadata {
pub description: String, pub description: String,
pub author: String, pub author: String,
pub icon: Option<String>, pub icon: Option<String>,
pub icon_alt: Option<String>,
pub color: Option<String>,
pub created_at: Option<DateTime<Utc>>, pub created_at: Option<DateTime<Utc>>,
pub modified_at: Option<DateTime<Utc>>, pub modified_at: Option<DateTime<Utc>>,
pub tags: Vec<String>, pub tags: Vec<String>,

View file

@ -7,16 +7,11 @@
<meta name="description" content="{{ title }}" /> <meta name="description" content="{{ title }}" />
<meta property="og:title" content="{{ title }}" /> <meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ description }}" /> <meta property="og:description" content="{{ description }}" />
{% match color %} {% when Some with (color) %}
<meta name="theme-color" content="{{ color }}" />
{% when None %} {% endmatch %}
<title>{{ title }}</title> <title>{{ title }}</title>
<link rel="stylesheet" href="/static/style.css" /> <link rel="stylesheet" href="/static/style.css" />
{% if rss %} {% if rss %}
<link rel="alternate" type="application/rss+xml" title="{{ title }}" href="/feed.xml" /> <link rel="alternate" type="application/rss+xml" title="{{ title }}" href="/feed.xml" />
{% endif %} {% endif %} {% if js %}
<!-- prettier-br -->
{% if js %}
<script src="/static/main.js" defer></script> <script src="/static/main.js" defer></script>
{% endif %} {% endif %}
</head> </head>

View file

@ -7,26 +7,11 @@
<meta name="author" content="{{ meta.author }}" /> <meta name="author" content="{{ meta.author }}" />
<meta name="keywords" content="{{ meta.tags|join(", ") }}" /> <meta name="keywords" content="{{ meta.tags|join(", ") }}" />
<meta name="description" content="{{ meta.title }}" /> <meta name="description" content="{{ meta.title }}" />
<!-- you know what I really love? platforms like discord
favoring twitter embeds over the open standard. to color
your embed or have large images, you have to do _this_. lmao -->
<meta property="og:title" content="{{ meta.title }}" /> <meta property="og:title" content="{{ meta.title }}" />
<meta property="twitter:title" content="{{ meta.title }}" />
<meta property="og:description" content="{{ meta.description }}" /> <meta property="og:description" content="{{ meta.description }}" />
<meta property="twitter:description" content="{{ meta.description }}" />
{% match meta.icon %} {% when Some with (url) %} {% match meta.icon %} {% when Some with (url) %}
<meta property="og:image" content="{{ url }}" /> <meta property="og:image" content="{{ url }}" />
<meta name="twitter:card" content="summary_large_image" /> <link rel="shortcut icon" href="{{ url }}" />
<meta property="twitter:image:src" content="{{ url }}" />
{% match meta.icon_alt %} {% when Some with (alt) %}
<meta property="og:image:alt" content="{{ alt }}" />
<meta property="twitter:image:alt" content="{{ alt }}" />
{% when None %} {% endmatch %}
<!-- prettier-br -->
{% when None %} {% endmatch %}
<!-- prettier is annoying -->
{% match color %} {% when Some with (color) %}
<meta name="theme-color" content="{{ color }}" />
{% when None %} {% endmatch %} {% when None %} {% endmatch %}
<title>{{ meta.title }}</title> <title>{{ meta.title }}</title>
<link rel="stylesheet" href="/static/style.css" /> <link rel="stylesheet" href="/static/style.css" />

0
templates/post_list.html Normal file
View file

View file