add template and implement rendering

This commit is contained in:
Peter Cai 2020-04-10 20:38:53 +08:00
parent b2d6678405
commit 150940cd8c
No known key found for this signature in database
GPG key ID: 71F5FB4E4F3FD54F
11 changed files with 843 additions and 2 deletions

3
.gitignore vendored
View file

@ -7,4 +7,5 @@ worker/
config.json
wrangler.toml
node_modules/
dist/
dist/
theme_config.json

333
Cargo.lock generated
View file

@ -1,23 +1,101 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "backtrace"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
dependencies = [
"backtrace-sys",
"cfg-if",
"libc",
"rustc-demangle",
]
[[package]]
name = "backtrace-sys"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "bumpalo"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "cc"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
dependencies = [
"num-integer",
"num-traits",
"time",
]
[[package]]
name = "console_error_panic_hook"
version = "0.1.6"
@ -28,18 +106,108 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array",
]
[[package]]
name = "failure"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
dependencies = [
"backtrace",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
dependencies = [
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn",
"synstructure",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "futures"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
dependencies = [
"typenum",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "handlebars"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba758d094d31274eb49d15da6f326b96bf3185239a6359bf684f3d5321148900"
dependencies = [
"log",
"pest",
"pest_derive",
"quick-error",
"serde",
"serde_json",
]
[[package]]
name = "hex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
[[package]]
name = "include_dir"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25ec8c61b6100ad0fc58ca644c59c0137d526d73cefa7497426369ea0d84d769"
dependencies = [
"glob",
"include_dir_impl",
"proc-macro-hack",
]
[[package]]
name = "include_dir_impl"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f03b4f7b64011df46794cc221854be5c3084345e260576518b91693866d0afd1"
dependencies = [
"failure",
"proc-macro-hack",
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn",
]
[[package]]
name = "itoa"
version = "0.4.5"
@ -76,6 +244,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "memchr"
version = "2.3.3"
@ -88,15 +262,60 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
[[package]]
name = "mime"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mime_guess"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
dependencies = [
"mime",
"unicase",
]
[[package]]
name = "num-integer"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
dependencies = [
"autocfg",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "paprika"
version = "0.1.0"
dependencies = [
"cfg-if",
"chrono",
"console_error_panic_hook",
"handlebars",
"hex",
"include_dir",
"js-sys",
"lazy_static",
"mime_guess",
"pulldown-cmark",
"serde",
"serde_json",
@ -107,6 +326,55 @@ dependencies = [
"wee_alloc",
]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [
"pest",
"pest_meta",
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
dependencies = [
"maplit",
"pest",
"sha-1",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
[[package]]
name = "proc-macro2"
version = "0.4.30"
@ -136,6 +404,12 @@ dependencies = [
"unicase",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "0.6.13"
@ -154,6 +428,18 @@ dependencies = [
"proc-macro2 1.0.10",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "ryu"
version = "1.0.3"
@ -197,6 +483,18 @@ dependencies = [
"serde",
]
[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer",
"digest",
"fake-simd",
"opaque-debug",
]
[[package]]
name = "syn"
version = "1.0.17"
@ -208,6 +506,41 @@ dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "synstructure"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn",
"unicode-xid 0.2.0",
]
[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
dependencies = [
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "typenum"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicase"
version = "2.6.0"

View file

@ -12,9 +12,13 @@ default = ["console_error_panic_hook", "wee_alloc"]
[dependencies]
cfg-if = "0.1.2"
chrono = "0.4"
lazy_static = "1.4"
handlebars = "3.0"
hex = "0.4"
include_dir = "0.5"
js-sys = "0.3"
mime_guess = "2.0"
pulldown-cmark = { version = "0.7", default-features = false }
serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1.0"

View file

@ -1,7 +1,13 @@
#![feature(vec_remove_item)]
#[macro_use]
extern crate handlebars;
#[macro_use]
extern crate include_dir;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate serde_json;
#[macro_use]
mod utils;
@ -9,6 +15,7 @@ mod router;
mod store;
mod blog;
mod sn;
mod render;
use cfg_if::cfg_if;
use js_sys::{Promise};
@ -42,6 +49,7 @@ fn build_routes() -> router::Router {
router.add_route("/hello", &hello_world);
router.add_route(blog::IMG_CACHE_PREFIX, &proxy_remote_image);
sn::build_routes(&mut router);
render::build_routes(&mut router);
return router;
}
@ -109,7 +117,19 @@ async fn default_route(_req: Request, url: Url) -> MyResult<Response> {
).internal_err();
}
// TODO: handle home page and pagination on home page
// Home page (this cannot be registered as a standalone route due to our Router)
if path == "/" {
return Response::new_with_opt_str_and_init(
Some(&render::render_homepage().await?),
ResponseInit::new()
.status(200)
.headers(headers!{
"Content-Type" => "text/html",
"Cache-Control" => "no-cache"
}.as_ref())
).internal_err();
}
// Now we can be sure the path ends with `/`
// (and of course it starts with `/` as per standard)
if path.len() > 1 {

117
src/render.rs Normal file
View file

@ -0,0 +1,117 @@
// Front-end page rendering
use crate::blog;
use crate::router::Router;
use crate::utils::*;
use chrono::NaiveDateTime;
use handlebars::Handlebars;
use include_dir::{include_dir, Dir};
use js_sys::{Date, Uint8Array};
use serde::Serialize;
use std::vec::Vec;
use web_sys::*;
// TODO: allow static configuration of which theme to use
const THEME_DIR: Dir = include_dir!("theme/default");
pub fn build_routes(router: &mut Router) {
router.add_route("/static/", &serve_static);
}
async fn serve_static(_req: Request, url: Url) -> MyResult<Response> {
let path = url.pathname();
if let Some(file) = THEME_DIR.get_file(&path[1..path.len()]) {
let u8arr: Uint8Array = file.contents().into();
Response::new_with_opt_buffer_source_and_init(
Some(&u8arr),
ResponseInit::new()
.status(200)
.headers(headers!{
"Content-Type" => mime_guess::from_path(path).first().unwrap().essence_str()
}.as_ref())
).internal_err()
} else {
Err(Error::NotFound("This file does not exist".into()))
}
}
// Context objects used when rendering pages
#[derive(Serialize)]
struct BlogRootContext {
theme_config: &'static serde_json::Value,
title: &'static str,
description: &'static str,
}
#[derive(Serialize)]
struct HomePagePost {
title: String,
url: String,
timestamp: u64,
summary: String
}
#[derive(Serialize)]
struct HomePageContext {
blog: &'static BlogRootContext,
posts: Vec<HomePagePost>
}
lazy_static! {
static ref THEME_CONFIG: serde_json::Value = serde_json::from_str(
include_str!("../theme_config.json")).unwrap();
static ref ROOT_CONTEXT: BlogRootContext = {
BlogRootContext {
theme_config: &THEME_CONFIG,
title: &crate::CONFIG.title,
description: &crate::CONFIG.description
}
};
}
handlebars_helper!(cur_year: |dummy: u64| Date::new_0().get_full_year());
// TODO: actually implement this helper
handlebars_helper!(format_date: |date: u64, format: str| {
NaiveDateTime::from_timestamp(date as i64, 0).format(format).to_string()
});
fn build_handlebars() -> Handlebars<'static> {
let mut hbs = Handlebars::new();
// Helpers
hbs.register_helper("cur_year", Box::new(cur_year));
hbs.register_helper("format_date", Box::new(format_date));
// Templates
for file in THEME_DIR.files() {
let path = file.path().to_str().unwrap();
if path.ends_with(".hbs") {
// Register all .hbs templates
hbs.register_template_string(
path, file.contents_utf8().unwrap()).unwrap();
}
}
return hbs;
}
pub async fn render_homepage() -> MyResult<String> {
let hbs = build_handlebars();
let mut context = HomePageContext {
blog: &ROOT_CONTEXT,
posts: vec![]
};
let posts_list = blog::PostsList::load().await;
for uuid in posts_list.0.iter() {
let post = blog::Post::find_by_uuid(uuid).await?;
let post_cache = blog::PostContentCache::find_or_render(&post).await;
context.posts.push(HomePagePost {
title: post.title,
url: post.url,
timestamp: post.timestamp,
summary: post_cache.content // TODO: make actual summaries
});
}
hbs.render("home.hbs", &context)
.map_err(|e| Error::BadRequest(format!("{:#?}", e)))
}

View file

@ -147,6 +147,10 @@ pub struct Config {
pub secret: String,
// Title of the blog
pub title: String,
// Language of blog
pub lang: String,
// Description of the blog
pub description: String,
// Plugin identifier used for Standard Notes
pub plugin_identifier: String
}

29
theme/default/home.hbs Normal file
View file

@ -0,0 +1,29 @@
<html lang="{{ blog.lang }}">
<head>
<meta charset="UTF-8">
<title>{{ blog.title }}</title>
<link rel="stylesheet" href="/static/style.css?ver=20200410"/>
</head>
<body>
<div class="page-wrapper">
{{> sidebar.hbs }}
<div class="post-list">
{{ #each posts }}
<article class="post with-divider with-divider-wide-center with-divider-thin">
<h1><a href="{{ this.url }}">{{ this.title }}</a></h1>
<span class="date">{{ format_date this.timestamp "%e %b, %Y" }}</span>
<section>
{{{ this.summary }}}
</section>
<a href="{{ this.url }}"><span class="read-more"></span></a>
</article>
{{ /each }}
<div class="pagination">
<a href="#"><span class="page-older"></span></a>
<a href="#"><span class="page-newer"></span></a>
</div>
</div>
</div>
<script src="/static/script.js?ver=20200410"></script>
</body>
</html>

20
theme/default/sidebar.hbs Normal file
View file

@ -0,0 +1,20 @@
<div class="sidebar">
<section class="avatar">
<img src="{{ blog.theme_config.avatar_url }}" />
</section>
<section class="introduction with-divider with-divider-right">
{{ blog.description }}
</section>
<section class="links with-divider with-divider-right">
<ul>
{{ #each blog.theme_config.nav_links }}
<li><a href="{{ this.url }}">{{ this.name }}</a></li>
{{ /each }}
</ul>
</section>
<section class="copyright">
Copyright © {{ cur_year 0 }} {{ blog.title }}<br />
Powered by <a href="https://github.com/PeterCxy/paprika" target="_blank">paprika</a><br />
Hosted on <a href="https://workers.cloudflare.com/" target="_blank">Cloudflare Workers</a>
</section>
</div>

View file

@ -0,0 +1,9 @@
// Avatar animation on hover
// Unfortunately for best result, this can only be done with JS
let avatar = document.querySelector(".sidebar .avatar img");
avatar.onmouseover = (ev) => {
ev.target.className = "animate";
};
avatar.onanimationend = (ev) => {
ev.target.className = "";
};

View file

@ -0,0 +1,304 @@
@import url('https://fonts.googleapis.com/css2?family=Fira+Sans:wght@300&display=swap');
/* Get rid of default padding */
html, body {
margin: 0;
padding: 0;
font-family: 'Fira Sans', sans-serif;
font-size: 18px;
text-shadow: 0 0 3px #dddddd;
color: rgb(100, 100, 100);
}
html {
background-image: url("/static/whitenoise-100x100.png");
background-repeat: repeat;
background-attachment: fixed;
}
.hidden {
display: none;
}
a, a:link, a:visited, a:hover, a:active {
text-decoration: none;
color: inherit;
outline: none;
}
body {
text-align: center;
}
.page-wrapper {
display: inline-block;
position: absolute;
left: 25vw;
padding-top: 10px;
width: 60vw;
max-width: 1000px;
min-width: 600px;
padding-bottom: 15px;
text-align: left;
}
.with-divider::after {
content: "";
display: block;
margin-top: 20px;
width: 40px;
height: 3px;
background-color: #E91E63;
}
.with-divider.with-divider-wide-center::after {
margin-left: calc(50% - 90px);
width: 180px;
}
.with-divider.with-divider-thin::after {
margin-top: 18px;
height: 2px;
}
.with-divider.with-divider-right::after {
margin-left: calc(100% - 40px);
}
/* Sidebar */
.sidebar {
float: left;
position: sticky;
top: 20px;
text-align: right;
width: 22%;
}
.sidebar section {
margin-top: 20px;
}
.sidebar .avatar {
display: inline-block;
overflow: hidden;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
background-color: #ffffff;
border-radius: 50%;
box-shadow: 0px 0px 6px 0px #cccccc;
}
.sidebar .avatar img {
display: inline-block;
margin-top: 5%;
width: 90%;
height: 90%;
border-radius: 50%;
object-fit: cover;
}
.sidebar .avatar img.animate {
animation: spin 1s ease-in-out;
}
/*
.sidebar .avatar img:hover {
animation: spin 0.5s ease-in-out;
}*/
@keyframes spin {
20% {
transform: rotate(30deg);
}
40% {
transform: rotate(-30deg);
}
60% {
transform: rotate(30deg);
}
80% {
transform: rotate(-30deg);
}
100% {
transform: rotate(0);
}
}
.sidebar .introduction {
font-style: italic;
}
.sidebar .links ul {
list-style-type: none;
padding-bottom: 10px;
}
.sidebar .links li {
padding-top: 10px;
}
.sidebar .links a {
transition: color 0.2s ease-in-out;
}
.sidebar .links a:hover {
color: #F06292;
}
.sidebar .copyright {
font-size: 0.6em;
color: rgb(200, 200, 200);
}
.copyright a,
.copyright a:link,
.copyright a:visited,
.copyright a:hover,
.copyright a:active {
text-decoration: underline;
}
/* Home page post list */
.post-list, .content {
margin-top: 15px;
margin-left: 25%;
width: 75%;
}
.post-list .post {
padding: 10px 5px 5px 5px;
margin-bottom: 12px;
}
.post-list .post h1 {
font-size: 1.2em;
margin: 0 0 0.5em 0;
padding: 0;
}
.post-list .post h1 a {
color: inherit;
transition: color 0.2s ease-in-out;
}
.post-list .post section {
margin-top: 0.5em;
}
.post-list .post h1 a:hover {
color: #E91E63;
text-decoration: none;
}
.post-list .post .read-more::after {
content: "......";
color: #F06292;
}
.post-list .pagination {
font-size: 0.8em;
}
.post-list .pagination .page-older:after {
content: "Older >";
color: #E91E63;
float: right;
}
.post-list .pagination .page-newer:after {
content: "< Newer";
color: #E91E63;
float: left;
}
.post a,
.post a:link,
.post a:visited,
.post a:hover,
.post a:active {
color: #E91E63;
}
.post a:hover {
text-decoration: underline;
}
/* Posts */
.date {
font-style: italic;
}
.post img,
.content img {
max-width: 100%;
object-fit: contain;
}
.toc-wrapper {
display: flex;
align-items: center;
float: right;
position: fixed;
right: 0;
top: 0;
width: 10%;
height: 100%;
}
.toc {
max-width: 200px;
font-size: 0.6em;
text-align: left;
background-color: #ffffff;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
padding-left: 15px;
}
.toc li {
margin-bottom: 2px;
}
.toc li::before {
content: "-";
position: absolute;
left: 5px; /* Relative to parent */
}
.toc ul {
margin-top: 5px;
margin-bottom: 5px;
padding-left: 0px;
margin-right: 10px;
margin-left: 0;
list-style-type: none;
}
.toc ul li.current {
color: #000000;
}
.toc ul li.current::before {
content: "+";
}
.toc ul ul {
margin-left: 5px;
}
.toc ul ul ul {
margin-left: 10px;
}
.toc ul ul ul ul {
margin-left: 15px;
}
.toc ul ul ul ul ul {
margin-left: 20px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB