add template and implement rendering
This commit is contained in:
parent
b2d6678405
commit
150940cd8c
11 changed files with 843 additions and 2 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -7,4 +7,5 @@ worker/
|
|||
config.json
|
||||
wrangler.toml
|
||||
node_modules/
|
||||
dist/
|
||||
dist/
|
||||
theme_config.json
|
333
Cargo.lock
generated
333
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -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
117
src/render.rs
Normal 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)))
|
||||
}
|
|
@ -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
29
theme/default/home.hbs
Normal 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
20
theme/default/sidebar.hbs
Normal 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>
|
9
theme/default/static/script.js
Normal file
9
theme/default/static/script.js
Normal 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 = "";
|
||||
};
|
304
theme/default/static/style.css
Normal file
304
theme/default/static/style.css
Normal 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;
|
||||
}
|
BIN
theme/default/static/whitenoise-100x100.png
Normal file
BIN
theme/default/static/whitenoise-100x100.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5 KiB |
Loading…
Reference in a new issue