Compare commits

..

8 commits

11 changed files with 87 additions and 37 deletions

View file

@ -8,7 +8,9 @@ title = "bingus-blog" # title of the blog
description = "blazingly fast markdown blog software written in rust memory safe" description = "blazingly fast markdown blog software written in rust memory safe"
markdown_access = true # allow users to see the raw markdown of a post markdown_access = true # allow users to see the raw markdown of a post
# endpoint: /posts/<name>.md # endpoint: /posts/<name>.md
js_enable = true # enable javascript (required for below 2 options) js_enable = true # enable javascript (required for sorting and dates)
[style]
date_format = "RFC3339" # format string used to format dates in the backend date_format = "RFC3339" # format string used to format dates in the backend
# it's highly recommended to leave this as default, # it's highly recommended to leave this as default,
# so the date can be formatted by the browser. # so the date can be formatted by the browser.
@ -16,6 +18,10 @@ date_format = "RFC3339" # format string used to format dates in the backend
default_sort = "date" # default sorting method ("date" or "name") default_sort = "date" # default sorting method ("date" or "name")
#default_color = "#f5c2e7" # default embed color, optional #default_color = "#f5c2e7" # default embed color, optional
[style.display_dates]
creation = true # display creation ("written") dates
modification = true # display modified ("last modified") dates
[rss] [rss]
enable = false # serve an rss field under /feed.xml enable = false # serve an rss field under /feed.xml
# this may be a bit resource intensive # this may be a bit resource intensive
@ -54,7 +60,7 @@ a default value
you don't have to copy the whole thing from here, you don't have to copy the whole thing from here,
it's generated by the program if it doesn't exist it's generated by the program if it doesn't exist
## Specifying Configuration ## Specifying the configuration file
the configuration file is loaded from `config.toml` by default, but the path the configuration file is loaded from `config.toml` by default, but the path
can be overriden by setting the environment variable `BINGUS_BLOG_CONFIG`, can be overriden by setting the environment variable `BINGUS_BLOG_CONFIG`,

View file

@ -17,7 +17,7 @@ for bingus-blog viewers: [see original document](https://git.slonk.ing/slonk/bin
can write posts from anywhere and sync it with the server without headache can write posts from anywhere and sync it with the server without headache
- RSS is supported - RSS is supported
- the look of the blog is extremely customizable, with support for - the look of the blog is extremely customizable, with support for
[custom drop-ins](/CUSTOM.md) for both templates and static content [custom drop-ins](CUSTOM.md) for both templates and static content
- really easy to deploy (the server is one executable file) - really easy to deploy (the server is one executable file)
- blazingly fast - blazingly fast
@ -26,18 +26,20 @@ for bingus-blog viewers: [see original document](https://git.slonk.ing/slonk/bin
- [ ] blog thumbnail and favicon - [ ] blog thumbnail and favicon
- [ ] sort asc/desc - [ ] sort asc/desc
- [ ] extend syntect options - [ ] extend syntect options
- [ ] ^ fix syntect mutex poisoning
- [ ] better error reporting and error pages - [ ] better error reporting and error pages
- [ ] better tracing - [ ] better tracing
- [ ] replace HashMap with HashCache once i implement [this](https://github.com/wvwwvwwv/scalable-concurrent-containers/issues/139) - [ ] replace HashMap with HashCache once i implement [this](https://github.com/wvwwvwwv/scalable-concurrent-containers/issues/139)
- [ ] make date parsing less strict - [ ] make date parsing less strict
- [ ] improve home page - [ ] improve home page
- [ ] multi-language support - [ ] multi-language support
- [ ] add credits
- [x] be blazingly fast - [x] be blazingly fast
- [x] 100+ MiB binary size - [x] 100+ MiB binary size
## Configuration ## Configuration
see [CONFIG.md](/CONFIG.md) see [CONFIG.md](CONFIG.md)
## Building ## Building
@ -52,7 +54,7 @@ cargo +nightly build --release
the executable will be located at `target/release/bingus-blog`. the executable will be located at `target/release/bingus-blog`.
see [BUILDING.md](/BUILDING.md) for more information and detailed instructions. see [BUILDING.md](BUILDING.md) for more information and detailed instructions.
## Writing Posts ## Writing Posts

View file

@ -1,11 +1,11 @@
<div class="table"> <div class="table">
{{#if (ne this.created_at null)}} {{#if (and (ne this.created_at null) style.display_dates.creation)}}
<div class="created">written</div> <div class="created">written</div>
<div class="created value">{{>span_date date_time=this.created_at}}</div> <div class="created value">{{>span_date dt=this.created_at df=style.date_format}}</div>
{{/if}} {{/if}}
{{#if (ne this.modified_at null)}} {{#if (and (ne this.modified_at null) style.display_dates.modification)}}
<div class="modified">last modified</div> <div class="modified">last modified</div>
<div class="modified value">{{>span_date date_time=this.modified_at}}</div> <div class="modified value">{{>span_date dt=this.modified_at df=style.date_format}}</div>
{{/if}} {{/if}}
{{#if (gt (len this.tags) 0)}} {{#if (gt (len this.tags) 0)}}
<div class="tags">tags</div> <div class="tags">tags</div>

View file

@ -1 +1 @@
<span class="date {{#if (eq df "RFC3339")}}date-rfc3339{{/if}}">{{date date_time df}}</span> <span class="date {{#if (eq df "RFC3339")}}date-rfc3339{{/if}}">{{date dt df}}</span>

View file

@ -19,7 +19,7 @@ use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use tracing::{info, info_span, Span}; use tracing::{info, info_span, Span};
use crate::config::{Config, DateFormat, Sort}; use crate::config::{Config, StyleConfig};
use crate::error::{AppError, AppResult}; use crate::error::{AppError, AppResult};
use crate::post::{MarkdownPosts, PostManager, PostMetadata, RenderStats, ReturnedPost}; use crate::post::{MarkdownPosts, PostManager, PostMetadata, RenderStats, ReturnedPost};
use crate::serve_dir_included::handle; use crate::serve_dir_included::handle;
@ -40,12 +40,10 @@ struct IndexTemplate<'a> {
description: &'a str, description: &'a str,
posts: Vec<PostMetadata>, posts: Vec<PostMetadata>,
rss: bool, rss: bool,
df: &'a DateFormat,
js: bool, js: bool,
color: Option<&'a str>,
sort: Sort,
tags: Map<String, serde_json::Value>, tags: Map<String, serde_json::Value>,
joined_tags: String, joined_tags: String,
style: &'a StyleConfig,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -54,10 +52,10 @@ struct PostTemplate<'a> {
rendered: String, rendered: String,
rendered_in: RenderStats, rendered_in: RenderStats,
markdown_access: bool, markdown_access: bool,
df: &'a DateFormat,
js: bool, js: bool,
color: Option<&'a str>, color: Option<&'a str>,
joined_tags: String, joined_tags: String,
style: &'a StyleConfig,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -128,12 +126,10 @@ async fn index<'a>(
description: &config.description, description: &config.description,
posts, posts,
rss: config.rss.enable, rss: config.rss.enable,
df: &config.date_format,
js: config.js_enable, js: config.js_enable,
color: config.default_color.as_deref(),
sort: config.default_sort,
tags, tags,
joined_tags, joined_tags,
style: &config.style,
}, },
); );
drop(reg); drop(reg);
@ -228,10 +224,13 @@ async fn post(
rendered, rendered,
rendered_in, rendered_in,
markdown_access: config.markdown_access, markdown_access: config.markdown_access,
df: &config.date_format,
js: config.js_enable, js: config.js_enable,
color: meta.color.as_deref().or(config.default_color.as_deref()), color: meta
.color
.as_deref()
.or(config.style.default_color.as_deref()),
joined_tags, joined_tags,
style: &config.style,
}, },
); );
drop(reg); drop(reg);

View file

@ -76,6 +76,23 @@ pub enum Sort {
Name, Name,
} }
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
#[derive(Default)]
pub struct StyleConfig {
pub display_dates: DisplayDates,
pub date_format: DateFormat,
pub default_sort: Sort,
pub default_color: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
pub struct DisplayDates {
pub creation: bool,
pub modification: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)] #[serde(default)]
pub struct Config { pub struct Config {
@ -83,9 +100,7 @@ pub struct Config {
pub description: String, pub description: String,
pub markdown_access: bool, pub markdown_access: bool,
pub js_enable: bool, pub js_enable: bool,
pub date_format: DateFormat, pub style: StyleConfig,
pub default_sort: Sort,
pub default_color: Option<String>,
pub rss: RssConfig, pub rss: RssConfig,
pub dirs: DirsConfig, pub dirs: DirsConfig,
pub http: HttpConfig, pub http: HttpConfig,
@ -100,9 +115,7 @@ impl Default for Config {
description: "blazingly fast markdown blog software written in rust memory safe".into(), description: "blazingly fast markdown blog software written in rust memory safe".into(),
markdown_access: true, markdown_access: true,
js_enable: true, js_enable: true,
date_format: Default::default(), style: Default::default(),
default_sort: Default::default(),
default_color: None,
// 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
@ -121,6 +134,16 @@ impl Default for Config {
} }
} }
impl Default for DisplayDates {
fn default() -> Self {
Self {
creation: true,
modification: true,
}
}
}
impl Default for DirsConfig { impl Default for DirsConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {

View file

@ -29,7 +29,7 @@ fn is_ext(path: impl AsRef<Path>, ext: &str) -> bool {
} }
} }
pub(self) fn get_template_name<'a>(path: &'a Path) -> Option<&'a str> { fn get_template_name(path: &Path) -> Option<&str> {
if !is_ext(path, "hbs") { if !is_ext(path, "hbs") {
return None; return None;
} }
@ -47,10 +47,10 @@ fn register_included_file(
Ok(()) Ok(())
} }
fn register_path<'a>( fn register_path(
path: impl AsRef<std::path::Path>, path: impl AsRef<std::path::Path>,
name: &str, name: &str,
registry: &mut Handlebars<'a>, registry: &mut Handlebars<'_>,
) -> Result<(), TemplateError> { ) -> Result<(), TemplateError> {
let template = compile_path(path)?; let template = compile_path(path)?;
registry.register_template(name, template); registry.register_template(name, template);
@ -85,7 +85,7 @@ fn compile_path(path: impl AsRef<std::path::Path>) -> Result<Template, TemplateE
Ok(template) Ok(template)
} }
pub(self) async fn compile_path_async_io( async fn compile_path_async_io(
path: impl AsRef<std::path::Path>, path: impl AsRef<std::path::Path>,
) -> Result<Template, TemplateError> { ) -> Result<Template, TemplateError> {
use tokio::fs::OpenOptions; use tokio::fs::OpenOptions;

View file

@ -54,3 +54,22 @@ th,
td:nth-child(1) { td:nth-child(1) {
word-break: keep-all; word-break: keep-all;
} }
blockquote {
margin-left: 1em;
padding-left: 1.5em;
border-left: 0.5em solid;
border-color: var(--blue);
& > blockquote {
border-color: var(--mauve);
& > blockquote {
border-color: var(--pink);
& > blockquote {
border-color: var(--rosewater);
& > blockquote {
border-color: var(--text);
}
}
}
}
}

View file

@ -1,4 +1,5 @@
/* colors */ /* colors from catppuccin https://github.com/catppuccin/catppuccin
licensed under the MIT license, available in the source tree */
:root { :root {
--base: #1e1e2e; --base: #1e1e2e;
--text: #cdd6f4; --text: #cdd6f4;

View file

@ -7,7 +7,7 @@
<meta property="og:description" content="{{description}}" /> <meta property="og:description" content="{{description}}" />
<meta name="keywords" content="{{joined_tags}}" /> <meta name="keywords" content="{{joined_tags}}" />
{{#if (ne color null)}} {{#if (ne color null)}}
<meta name="theme-color" content="{{color}}" /> <meta name="theme-color" content="{{style.color}}" />
{{/if}} {{/if}}
<title>{{title}}</title> <title>{{title}}</title>
<link rel="stylesheet" href="/static/style.css" /> <link rel="stylesheet" href="/static/style.css" />
@ -30,9 +30,9 @@
<form id="sort" style="display: none"> <form id="sort" style="display: none">
sort by: {{sort}} sort by: {{sort}}
<br /> <br />
<input type="radio" name="sort" id="sort-date" value="date" {{#if (eq sort "date")}}checked{{/if}} /> <input type="radio" name="sort" id="sort-date" value="date" {{#if (eq style.default_sort "date")}}checked{{/if}} />
<label for="sort-date">date</label> <label for="sort-date">date</label>
<input type="radio" name="sort" id="sort-name" value="name" {{#if (eq sort "name")}}checked{{/if}} /> <input type="radio" name="sort" id="sort-name" value="name" {{#if (eq style.default_sort "name")}}checked{{/if}} />
<label for="sort-name">name</label> <label for="sort-name">name</label>
</form> </form>
{{/if}} {{/if}}
@ -43,7 +43,7 @@
<span class="post-author">- by {{author}}</span> <span class="post-author">- by {{author}}</span>
<br /> <br />
{{description}}<br /> {{description}}<br />
{{>post_table post df=@root.df}} {{>post_table post style=@root.style}}
</div> </div>
</div> </div>
{{else}} there are no posts right now. check back later! {{/each}} {{else}} there are no posts right now. check back later! {{/each}}

View file

@ -21,7 +21,7 @@
<meta property="twitter:image:alt" content="{{meta.icon_alt}}" /> <meta property="twitter:image:alt" content="{{meta.icon_alt}}" />
{{/if}}{{/if}} {{/if}}{{/if}}
{{#if (ne color null)}} {{#if (ne color null)}}
<meta name="theme-color" content="{{meta.color}}" /> <meta name="theme-color" content="{{color}}" />
{{/if}} {{/if}}
<title>{{meta.title}}</title> <title>{{meta.title}}</title>
<link rel="stylesheet" href="/static/style.css" /> <link rel="stylesheet" href="/static/style.css" />
@ -41,7 +41,7 @@
</h1> </h1>
<p class="post-desc">{{meta.description}}</p> <p class="post-desc">{{meta.description}}</p>
<div class="post"> <div class="post">
{{>post_table meta df=@root.df}} {{>post_table meta style=@root.style}}
<a href="/posts/{{meta.name}}">link</a><br /> <a href="/posts/{{meta.name}}">link</a><br />
<a href="/">back to home</a> <a href="/">back to home</a>
</div> </div>