forked from slonk/bingus-blog
implement sorting
This commit is contained in:
parent
02216efb7d
commit
00b721caab
9 changed files with 105 additions and 30 deletions
25
README.md
25
README.md
|
@ -43,11 +43,12 @@ title = "bingus-blog" # title of the blog
|
|||
description = "blazingly fast markdown blog software written in rust memory safe"
|
||||
markdown_access = true # allow users to see the raw markdown of a post
|
||||
# endpoint: /posts/<name>.md
|
||||
js_enable = true # enable javascript (required for below 2 options)
|
||||
date_format = "RFC3339" # format string used to format dates in the backend
|
||||
# it's highly recommended to leave this as default,
|
||||
# so the date can be formatted by the browser.
|
||||
# format: https://docs.rs/chrono/latest/chrono/format/strftime/index.html#specifiers
|
||||
js_enable = true # enable javascript (required for above)
|
||||
default_sort = "date" # default sorting method ("date" or "name")
|
||||
default_color = "#f5c2e7" # default embed color, optional
|
||||
|
||||
[rss]
|
||||
|
@ -144,7 +145,7 @@ created_at: 2024-04-18T04:15:26+03:00 # date of writing, this is highly
|
|||
# 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
|
||||
- lifestyle
|
||||
---
|
||||
```
|
||||
|
||||
|
@ -165,11 +166,11 @@ standard. examples of valid and invalid dates:
|
|||
|
||||
## Routes
|
||||
|
||||
- `GET /`: index page, lists posts
|
||||
- `GET /posts`: returns a list of all posts with metadata in JSON format
|
||||
- `GET /posts/<name>`: view a post
|
||||
- `GET /posts/<name>.md`: view the raw markdown of a post
|
||||
- `GET /post/*`: redirects to `/posts/*`
|
||||
- `GET /`: index page, lists posts
|
||||
- `GET /posts`: returns a list of all posts with metadata in JSON format
|
||||
- `GET /posts/<name>`: view a post
|
||||
- `GET /posts/<name>.md`: view the raw markdown of a post
|
||||
- `GET /post/*`: redirects to `/posts/*`
|
||||
|
||||
## Cache
|
||||
|
||||
|
@ -190,8 +191,8 @@ there is basically no good reason to not have compression on.
|
|||
|
||||
make sure your changes don't cause problems on at least the following browsers:
|
||||
|
||||
- links2
|
||||
- lynx
|
||||
- w3m
|
||||
- Firefox
|
||||
- Chromium
|
||||
- links2
|
||||
- lynx
|
||||
- w3m
|
||||
- Firefox
|
||||
- Chromium
|
||||
|
|
|
@ -14,7 +14,7 @@ use tower_http::services::ServeDir;
|
|||
use tower_http::trace::TraceLayer;
|
||||
use tracing::{info, info_span, Span};
|
||||
|
||||
use crate::config::{Config, DateFormat};
|
||||
use crate::config::{Config, DateFormat, Sort};
|
||||
use crate::error::{AppError, AppResult};
|
||||
use crate::filters;
|
||||
use crate::post::{MarkdownPosts, PostManager, PostMetadata, RenderStats, ReturnedPost};
|
||||
|
@ -35,6 +35,7 @@ struct IndexTemplate<'a> {
|
|||
df: &'a DateFormat,
|
||||
js: bool,
|
||||
color: Option<&'a str>,
|
||||
sort: Sort,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
|
@ -72,6 +73,7 @@ async fn index<'a>(
|
|||
df: &config.date_format,
|
||||
js: config.js_enable,
|
||||
color: config.default_color.as_deref(),
|
||||
sort: config.default_sort,
|
||||
}
|
||||
.into_response())
|
||||
}
|
||||
|
|
|
@ -67,14 +67,24 @@ pub enum DateFormat {
|
|||
Strftime(String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Copy, PartialEq, Eq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[repr(u8)]
|
||||
pub enum Sort {
|
||||
#[default]
|
||||
Date,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub markdown_access: bool,
|
||||
pub date_format: DateFormat,
|
||||
pub js_enable: bool,
|
||||
pub date_format: DateFormat,
|
||||
pub default_sort: Sort,
|
||||
pub default_color: Option<String>,
|
||||
pub rss: RssConfig,
|
||||
pub dirs: DirsConfig,
|
||||
|
@ -89,8 +99,9 @@ impl Default for Config {
|
|||
title: "bingus-blog".into(),
|
||||
description: "blazingly fast markdown blog software written in rust memory safe".into(),
|
||||
markdown_access: true,
|
||||
date_format: Default::default(),
|
||||
js_enable: true,
|
||||
date_format: Default::default(),
|
||||
default_sort: Default::default(),
|
||||
default_color: Some("#f5c2e7".into()),
|
||||
// i have a love-hate relationship with serde
|
||||
// it was engimatic at first, but then i started actually using it
|
||||
|
|
|
@ -50,3 +50,7 @@ pub fn collect_tags(posts: &Vec<PostMetadata>) -> Result<Vec<(String, u64)>, ask
|
|||
|
||||
Ok(tags)
|
||||
}
|
||||
|
||||
pub fn join_tags_for_meta(tags: &Vec<String>) -> Result<String, askama::Error> {
|
||||
Ok(tags.join(", "))
|
||||
}
|
||||
|
|
4
static/date.js
Normal file
4
static/date.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
for (let el of document.querySelectorAll(".date-rfc3339")) {
|
||||
let date = new Date(Date.parse(el.textContent));
|
||||
el.textContent = date.toLocaleString();
|
||||
}
|
|
@ -1,4 +1,40 @@
|
|||
for (let el of document.querySelectorAll(".date-rfc3339")) {
|
||||
let date = new Date(Date.parse(el.textContent));
|
||||
el.textContent = date.toLocaleString();
|
||||
let form = document.getElementById("sort");
|
||||
let posts = document.getElementById("posts");
|
||||
|
||||
let postsName = document.createElement("div");
|
||||
|
||||
function initialSort(source, target) {
|
||||
let posts = [];
|
||||
for (let post of source.children) {
|
||||
let title = post.firstElementChild.innerText;
|
||||
posts.push([title, post.cloneNode(true)]);
|
||||
}
|
||||
posts.sort(([a, _1], [b, _2]) => a.toLocaleLowerCase() > b.toLocaleLowerCase());
|
||||
for (let [_, post] of posts) {
|
||||
target.appendChild(post);
|
||||
}
|
||||
}
|
||||
|
||||
function sort(by) {
|
||||
console.log("sorting by", by);
|
||||
switch (by) {
|
||||
case "date":
|
||||
posts.style.display = "block";
|
||||
postsName.style.display = "none";
|
||||
break;
|
||||
case "name":
|
||||
postsName.style.display = "block";
|
||||
posts.style.display = "none";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSort() {
|
||||
if (!form) return;
|
||||
for (let el of form.sort) el.addEventListener("change", () => sort(form.sort.value));
|
||||
}
|
||||
|
||||
initialSort(posts, postsName);
|
||||
posts.parentNode.appendChild(postsName);
|
||||
handleSort();
|
||||
sort(form.sort.value);
|
||||
|
|
|
@ -112,6 +112,11 @@ div.post {
|
|||
grid-row: 3;
|
||||
}
|
||||
|
||||
#sort {
|
||||
display: inline-block;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* BEGIN cool effect everyone liked */
|
||||
|
||||
body {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
{% endif %}
|
||||
<!-- prettier-br -->
|
||||
{% if js %}
|
||||
<script src="/static/date.js" defer></script>
|
||||
<script src="/static/main.js" defer></script>
|
||||
{% endif %}
|
||||
</head>
|
||||
|
@ -25,20 +26,31 @@
|
|||
<h1>{{ title }}</h1>
|
||||
<p>{{ description }}</p>
|
||||
<h2>posts</h2>
|
||||
<!-- prettier-ignore -->
|
||||
<div>
|
||||
{% if posts.is_empty() %}
|
||||
there are no posts right now. check back later!
|
||||
{% if posts.is_empty() %}<!-- prettier-br -->
|
||||
there are no posts right now. check back later!<!-- prettier-br -->
|
||||
{% else %}<!-- prettier-br -->
|
||||
{% if js %}<!-- prettier-br -->
|
||||
sort by:
|
||||
<form id="sort">
|
||||
<input type="radio" name="sort" id="sort-date" value="date" {% if sort == Sort::Date %} checked {% endif %} />
|
||||
<label for="sort-date">date</label>
|
||||
<input type="radio" name="sort" id="sort-name" value="name" {% if sort == Sort::Name %} checked {% endif %} />
|
||||
<label for="sort-name">name</label>
|
||||
</form>
|
||||
{% endif %}<!-- prettier-br -->
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<a href="/posts/{{ post.name }}"><b>{{ post.title }}</b></a>
|
||||
<span class="post-author">- by {{ post.author }}</span>
|
||||
<br />
|
||||
{{ post.description }}<br />
|
||||
{% call macros::table(post) %}
|
||||
<div id="posts">
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<a href="/posts/{{ post.name }}"><b>{{ post.title }}</b></a>
|
||||
<span class="post-author">- by {{ post.author }}</span>
|
||||
<br />
|
||||
{{ post.description }}<br />
|
||||
{% call macros::table(post) %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}<!-- prettier-br -->
|
||||
</div>
|
||||
{% let tags = posts|collect_tags %}<!-- prettier-br -->
|
||||
{% if !tags.is_empty() %}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="author" content="{{ meta.author }}" />
|
||||
<meta name="keywords" content="{{ meta.tags|join(", ") }}" />
|
||||
<meta name="keywords" content="{{ meta.tags|join_tags_for_meta }}" />
|
||||
<meta name="description" content="{{ meta.title }}" />
|
||||
<!-- you know what I really love? platforms like discord
|
||||
favoring twitter embeds over the open standard. to color
|
||||
|
|
Loading…
Reference in a new issue