Switch over to WebAssembly, Rust and Yew #35
424
Cargo.lock
generated
424
Cargo.lock
generated
@ -64,6 +64,12 @@ dependencies = [
|
|||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.21.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64ct"
|
name = "base64ct"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@ -134,6 +140,22 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@ -143,6 +165,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@ -183,12 +214,33 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -461,6 +513,25 @@ dependencies = [
|
|||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@ -499,12 +570,82 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2 0.4.9",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"hyper",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "implicit-clone"
|
name = "implicit-clone"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@ -553,6 +694,12 @@ dependencies = [
|
|||||||
"hashbrown 0.14.0",
|
"hashbrown 0.14.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnet"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@ -579,6 +726,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.147"
|
||||||
@ -619,6 +772,12 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -639,6 +798,24 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@ -673,6 +850,50 @@ version = "1.18.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.29",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.91"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@ -745,6 +966,12 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
@ -852,6 +1079,43 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
|
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"hyper-tls",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"winreg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "route-recognizer"
|
name = "route-recognizer"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -889,12 +1153,44 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.171"
|
version = "1.0.171"
|
||||||
@ -980,6 +1276,7 @@ dependencies = [
|
|||||||
"gray_matter",
|
"gray_matter",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
"log",
|
"log",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
@ -1010,6 +1307,16 @@ version = "1.11.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -1042,6 +1349,19 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"redox_syscall",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -1102,6 +1422,21 @@ dependencies = [
|
|||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.32.0"
|
version = "1.32.0"
|
||||||
@ -1116,7 +1451,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2 0.5.3",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
@ -1132,6 +1467,16 @@ dependencies = [
|
|||||||
"syn 2.0.29",
|
"syn 2.0.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-stream"
|
name = "tokio-stream"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
@ -1143,6 +1488,26 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-service"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.37"
|
version = "0.1.37"
|
||||||
@ -1175,6 +1540,18 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-blocks"
|
name = "unicode-blocks"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
@ -1187,24 +1564,59 @@ version = "1.0.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8-width"
|
name = "utf8-width"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
|
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||||
|
dependencies = [
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
@ -1395,6 +1807,16 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.50.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "words-count"
|
name = "words-count"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -34,6 +34,7 @@ yew = { version = "0.20" }
|
|||||||
yew-hooks = { version = "0.2" }
|
yew-hooks = { version = "0.2" }
|
||||||
yew-router = { version = "0.17" }
|
yew-router = { version = "0.17" }
|
||||||
log = { version = "0.4" }
|
log = { version = "0.4" }
|
||||||
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = { version = "1.0" }
|
serde_json = { version = "1.0" }
|
||||||
serde_yaml = { version = "0.9" }
|
serde_yaml = { version = "0.9" }
|
||||||
|
11
src/app.rs
11
src/app.rs
@ -10,24 +10,16 @@ use yew_router::{
|
|||||||
#[cfg(not(feature = "static"))]
|
#[cfg(not(feature = "static"))]
|
||||||
use yew_router::BrowserRouter;
|
use yew_router::BrowserRouter;
|
||||||
|
|
||||||
use crate::{
|
use crate::{components::layout::Layout, pages::Route};
|
||||||
components::layout::Layout,
|
|
||||||
model::{source::ModelProvider, tags::TagsProvider},
|
|
||||||
pages::Route,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[function_component(AppContent)]
|
#[function_component(AppContent)]
|
||||||
fn app_content() -> Html {
|
fn app_content() -> Html {
|
||||||
html! {
|
html! {
|
||||||
<ModelProvider>
|
|
||||||
<TagsProvider>
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<main>
|
<main>
|
||||||
<Switch<Route> render={Route::switch} />
|
<Switch<Route> render={Route::switch} />
|
||||||
</main>
|
</main>
|
||||||
</Layout>
|
</Layout>
|
||||||
</TagsProvider>
|
|
||||||
</ModelProvider>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +35,7 @@ pub struct AppProps {
|
|||||||
pub fn app(props: &AppProps) -> Html {
|
pub fn app(props: &AppProps) -> Html {
|
||||||
#[cfg(feature = "static")]
|
#[cfg(feature = "static")]
|
||||||
{
|
{
|
||||||
|
log::info!("Application is running in static mode");
|
||||||
let history = AnyHistory::from(MemoryHistory::default());
|
let history = AnyHistory::from(MemoryHistory::default());
|
||||||
history.push(&props.url);
|
history.push(&props.url);
|
||||||
html! {
|
html! {
|
||||||
|
@ -80,7 +80,18 @@ async fn copy_resources(
|
|||||||
dist_dir: impl AsRef<Path>,
|
dist_dir: impl AsRef<Path>,
|
||||||
out_dir: impl AsRef<Path>,
|
out_dir: impl AsRef<Path>,
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
let mut resources = tokio::fs::read_dir(dist_dir).await?;
|
let mut stack: Vec<(PathBuf, PathBuf)> = vec![(
|
||||||
|
dist_dir.as_ref().to_path_buf(),
|
||||||
|
out_dir.as_ref().to_path_buf(),
|
||||||
|
)];
|
||||||
|
|
||||||
|
while let Some((dist_dir, out_dir)) = stack.pop() {
|
||||||
|
if !out_dir.exists() {
|
||||||
|
log::info!("Creaing output directory: {out_dir:?}");
|
||||||
|
tokio::fs::create_dir(&out_dir).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut resources = tokio::fs::read_dir(&dist_dir).await?;
|
||||||
while let Some(entry) = resources.next_entry().await? {
|
while let Some(entry) = resources.next_entry().await? {
|
||||||
let Ok(file_type) = entry.file_type().await else {
|
let Ok(file_type) = entry.file_type().await else {
|
||||||
log::error!("Could not get file type for: {:?}", entry.path());
|
log::error!("Could not get file type for: {:?}", entry.path());
|
||||||
@ -94,9 +105,37 @@ async fn copy_resources(
|
|||||||
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
log::info!("Copying resource: {:?}", path);
|
log::info!("Copying resource: {:?}", path);
|
||||||
tokio::fs::copy(path, out_dir.as_ref().join(entry.file_name())).await?;
|
tokio::fs::copy(path, out_dir.join(entry.file_name())).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if file_type.is_dir() {
|
||||||
|
let name = entry.file_name();
|
||||||
|
let out_dir = out_dir.join(name.clone());
|
||||||
|
let dist_dir = dist_dir.join(name.clone());
|
||||||
|
stack.push((dist_dir, out_dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write_data(out_dir: impl AsRef<Path>) -> std::io::Result<()> {
|
||||||
|
log::info!("Writing tags.json ...");
|
||||||
|
let tags = site::model::source::get_tags();
|
||||||
|
tokio::fs::write(
|
||||||
|
out_dir.as_ref().join("tags.json"),
|
||||||
|
serde_json::to_string(&tags)?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
log::info!("Writing posts.json ...");
|
||||||
|
let posts = site::model::source::get_posts();
|
||||||
|
tokio::fs::write(
|
||||||
|
out_dir.as_ref().join("posts.json"),
|
||||||
|
serde_json::to_string(&posts)?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -137,5 +176,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
tokio::fs::write(path, html).await?;
|
tokio::fs::write(path, html).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info!("Writing data");
|
||||||
|
write_data(&out_dir).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use yew_router::prelude::Link;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::layout::intersperse::Intersperse,
|
components::layout::intersperse::Intersperse,
|
||||||
model::{tags::TagsContext, PostInfo},
|
model::{source::TagsContext, PostInfo},
|
||||||
pages::Route,
|
pages::Route,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,11 +40,13 @@ fn post_card_details(info: &PostInfo, tags: &TagsContext) -> Html {
|
|||||||
let tags = Intersperse::from_iter(
|
let tags = Intersperse::from_iter(
|
||||||
html! { <Icon class="text-gray-500" icon_id={IconId::BootstrapDot} /> },
|
html! { <Icon class="text-gray-500" icon_id={IconId::BootstrapDot} /> },
|
||||||
info.tags.iter().map(|tag| {
|
info.tags.iter().map(|tag| {
|
||||||
if let Some(tag) = tags.get_tag(tag) {
|
if let Some(tag) = tags.get(tag) {
|
||||||
html! {
|
html! {
|
||||||
<Link<Route>
|
<Link<Route>
|
||||||
classes="text-sky-500 hover:text-sky-600"
|
classes="text-sky-500 hover:text-sky-600"
|
||||||
to={Route::Tag { slug: tag.slug }}>{tag.name}</Link<Route>>
|
to={Route::Tag { slug: tag.slug.clone() }}>
|
||||||
|
{tag.name.clone()}
|
||||||
|
</Link<Route>>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
use yew::{function_component, html, Html, Properties};
|
use yew::{function_component, html, use_context, Html, Properties};
|
||||||
|
|
||||||
use crate::{components::blog::post_card::PostCard, model::PostInfo};
|
use crate::{components::blog::post_card::PostCard, model::source::PostsContext};
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
|
||||||
pub struct PostCardListProps {
|
|
||||||
pub posts: Vec<PostInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component(PostCardList)]
|
#[function_component(PostCardList)]
|
||||||
pub fn post_card_list(props: &PostCardListProps) -> Html {
|
pub fn post_card_list() -> Html {
|
||||||
|
let posts = use_context::<PostsContext>().expect("PostsContext to be provided");
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="grid grid-cols-3 gap-x-10 gap-y-20 my-10">
|
<div class="grid grid-cols-3 gap-x-10 gap-y-20 my-10">
|
||||||
{for props.posts.iter().enumerate().map(|(index, post)| {
|
{for posts.iter().enumerate().map(|(index, post)| {
|
||||||
html! {
|
html! {
|
||||||
<PostCard post={post.clone()} first={index == 0} />
|
<PostCard post={post.clone()} first={index == 0} />
|
||||||
}
|
}
|
||||||
|
13
src/model.rs
13
src/model.rs
@ -1,13 +1,12 @@
|
|||||||
pub mod frontmatter;
|
pub mod frontmatter;
|
||||||
pub mod source;
|
pub mod source;
|
||||||
pub mod tags;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
use self::frontmatter::FrontMatter;
|
use self::frontmatter::FrontMatter;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct DocInfo {
|
pub struct DocInfo {
|
||||||
/// The slug used to form the URL for this document.
|
/// The slug used to form the URL for this document.
|
||||||
pub slug: String,
|
pub slug: String,
|
||||||
@ -19,7 +18,7 @@ pub struct DocInfo {
|
|||||||
pub published: Option<OffsetDateTime>,
|
pub published: Option<OffsetDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PostInfo {
|
pub struct PostInfo {
|
||||||
/// Document information.
|
/// Document information.
|
||||||
pub doc_info: DocInfo,
|
pub doc_info: DocInfo,
|
||||||
@ -31,7 +30,7 @@ pub struct PostInfo {
|
|||||||
pub cover_image: Option<String>,
|
pub cover_image: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Post {
|
pub struct Post {
|
||||||
/// Information about the post
|
/// Information about the post
|
||||||
pub info: PostInfo,
|
pub info: PostInfo,
|
||||||
@ -66,7 +65,7 @@ impl PostInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
/// The slug of the tag
|
/// The slug of the tag
|
||||||
pub slug: String,
|
pub slug: String,
|
||||||
@ -78,7 +77,7 @@ pub struct Tag {
|
|||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum TagVisibility {
|
pub enum TagVisibility {
|
||||||
#[serde(rename = "public")]
|
#[serde(rename = "public")]
|
||||||
Public,
|
Public,
|
||||||
|
@ -2,8 +2,6 @@ use gray_matter::{engine::YAML, Matter, ParsedEntity};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
use super::source::SourceError;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
pub struct FrontMatter {
|
pub struct FrontMatter {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@ -16,20 +14,21 @@ pub struct FrontMatter {
|
|||||||
pub cover: Option<String>,
|
pub cover: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_front_matter(
|
pub fn parse_front_matter(content: &[u8]) -> (Option<FrontMatter>, ParsedEntity) {
|
||||||
content: &[u8],
|
|
||||||
) -> Result<(Option<FrontMatter>, ParsedEntity), SourceError> {
|
|
||||||
let content = unsafe { std::str::from_utf8_unchecked(content) };
|
let content = unsafe { std::str::from_utf8_unchecked(content) };
|
||||||
let matter = Matter::<YAML>::new().parse(content);
|
let matter = Matter::<YAML>::new().parse(content);
|
||||||
|
|
||||||
let info: Option<FrontMatter> = if let Some(data) = &matter.data {
|
let info: Option<FrontMatter> = if let Some(data) = &matter.data {
|
||||||
Some(data.deserialize().map_err(|err| {
|
match data.deserialize() {
|
||||||
|
Ok(info) => Some(info),
|
||||||
|
Err(err) => {
|
||||||
log::error!("Failed to parse front matter: {err:?}");
|
log::error!("Failed to parse front matter: {err:?}");
|
||||||
SourceError::InvalidFrontMatter(err.to_string())
|
None
|
||||||
})?)
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((info, matter))
|
(info, matter)
|
||||||
}
|
}
|
||||||
|
@ -1,86 +1,18 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
#[cfg(feature = "hydration")]
|
||||||
|
mod hydrating;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
#[cfg(feature = "hydration")]
|
||||||
use thiserror::Error;
|
pub use hydrating::*;
|
||||||
use yew::{function_component, html, Children, ContextProvider, Html, Properties};
|
|
||||||
|
#[cfg(not(feature = "hydration"))]
|
||||||
|
mod filesystem;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "hydration"))]
|
||||||
|
pub use filesystem::*;
|
||||||
|
|
||||||
use super::{PostInfo, Tag};
|
use super::{PostInfo, Tag};
|
||||||
|
|
||||||
#[cfg(feature = "hydration")]
|
pub type TagsContext = HashMap<String, Tag>;
|
||||||
mod web;
|
pub type PostsContext = Vec<PostInfo>;
|
||||||
|
|
||||||
#[cfg(not(feature = "hydration"))]
|
|
||||||
mod fs;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Error)]
|
|
||||||
pub enum SourceError {
|
|
||||||
#[error("Invalid front matter: {0}")]
|
|
||||||
InvalidFrontMatter(String),
|
|
||||||
#[error("Invalid tags format")]
|
|
||||||
InvalidTags,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait ModelSource: Send + Sync {
|
|
||||||
async fn get_posts(&self) -> Result<Vec<PostInfo>, SourceError>;
|
|
||||||
async fn get_tags(&self) -> Result<HashMap<String, Tag>, SourceError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_source() -> Box<dyn ModelSource> {
|
|
||||||
// If we're compiled to use hydration, we want to use the web source.
|
|
||||||
#[cfg(feature = "hydration")]
|
|
||||||
return Box::new(self::web::Source::new());
|
|
||||||
|
|
||||||
// If we're NOT compiled to use hydration, we want to use the file-system source.
|
|
||||||
#[cfg(not(feature = "hydration"))]
|
|
||||||
return Box::new(fs::Source::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ModelSourceWrapper {
|
|
||||||
inner: Arc<Box<dyn ModelSource>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for ModelSourceWrapper {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Arc::clone(&self.inner),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for ModelSourceWrapper {
|
|
||||||
fn eq(&self, _: &Self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ModelSource for ModelSourceWrapper {
|
|
||||||
async fn get_posts(&self) -> Result<Vec<PostInfo>, SourceError> {
|
|
||||||
self.inner.get_posts().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_tags(&self) -> Result<HashMap<String, Tag>, SourceError> {
|
|
||||||
self.inner.get_tags().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
|
||||||
pub struct ModelProviderProps {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component(ModelProvider)]
|
|
||||||
pub fn model_provider(props: &ModelProviderProps) -> Html {
|
|
||||||
let source = get_source();
|
|
||||||
let source = ModelSourceWrapper {
|
|
||||||
inner: Arc::new(source),
|
|
||||||
};
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<ContextProvider<ModelSourceWrapper> context={source}>
|
|
||||||
{props.children.clone()}
|
|
||||||
</ContextProvider<ModelSourceWrapper>>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
87
src/model/source/filesystem.rs
Normal file
87
src/model/source/filesystem.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use include_dir::{include_dir, Dir, File};
|
||||||
|
use yew::{function_component, html, Children, ContextProvider, Html, Properties};
|
||||||
|
|
||||||
|
use crate::model::{
|
||||||
|
frontmatter::parse_front_matter,
|
||||||
|
source::{PostsContext, TagsContext},
|
||||||
|
PostInfo, Tag,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct ProvideTagsProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(ProvideTags)]
|
||||||
|
pub fn provide_tags(props: &ProvideTagsProps) -> Html {
|
||||||
|
let tags = get_tags();
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<ContextProvider<TagsContext> context={tags}>
|
||||||
|
{props.children.clone()}
|
||||||
|
</ContextProvider<TagsContext>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tags() -> TagsContext {
|
||||||
|
let file = CONTENT_DIR.get_file("tags.yaml").expect("tags.yaml");
|
||||||
|
match serde_yaml::from_slice::<Vec<Tag>>(file.contents()) {
|
||||||
|
Ok(tags) => tags
|
||||||
|
.into_iter()
|
||||||
|
.map(|tag| (tag.slug.clone(), tag))
|
||||||
|
.collect::<TagsContext>(),
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Failed to parse tags.yaml: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct ProvidePostsProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(ProvidePosts)]
|
||||||
|
pub fn provide_posts(props: &ProvidePostsProps) -> Html {
|
||||||
|
let posts = get_posts();
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<ContextProvider<PostsContext> context={posts}>
|
||||||
|
{props.children.clone()}
|
||||||
|
</ContextProvider<PostsContext>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_posts() -> PostsContext {
|
||||||
|
let files = CONTENT_DIR.get_dir("posts").expect("posts dir").files();
|
||||||
|
let mut posts = files.filter_map(load_post_info).collect::<Vec<_>>();
|
||||||
|
posts.sort_by(|a, b| b.doc_info.published.cmp(&a.doc_info.published));
|
||||||
|
posts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_post_info(file: &File) -> Option<PostInfo> {
|
||||||
|
let (Some(front_matter), matter) = parse_front_matter(file.contents()) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let slug = file
|
||||||
|
.path()
|
||||||
|
.file_stem()
|
||||||
|
.expect("filename")
|
||||||
|
.to_str()
|
||||||
|
.expect("valid file name")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let reading_time = words_count::count(&matter.content).words / 200;
|
||||||
|
|
||||||
|
Some(PostInfo::from_front_matter(
|
||||||
|
slug,
|
||||||
|
Some(reading_time),
|
||||||
|
matter.excerpt,
|
||||||
|
front_matter,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
static CONTENT_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/content");
|
@ -1,76 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use include_dir::{include_dir, Dir, File};
|
|
||||||
|
|
||||||
use crate::model::{frontmatter::parse_front_matter, PostInfo, Tag};
|
|
||||||
|
|
||||||
use super::{ModelSource, SourceError};
|
|
||||||
|
|
||||||
pub struct Source {}
|
|
||||||
|
|
||||||
impl Source {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ModelSource for Source {
|
|
||||||
async fn get_posts(&self) -> Result<Vec<PostInfo>, SourceError> {
|
|
||||||
let files = get_post_files().map(|file| -> Result<Option<PostInfo>, SourceError> {
|
|
||||||
let (Some(front_matter), matter) = parse_front_matter(file.contents())? else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let slug = file
|
|
||||||
.path()
|
|
||||||
.file_stem()
|
|
||||||
.expect("filename")
|
|
||||||
.to_str()
|
|
||||||
.expect("valid file name")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let reading_time = words_count::count(&matter.content).words / 200;
|
|
||||||
|
|
||||||
Ok(Some(PostInfo::from_front_matter(
|
|
||||||
slug,
|
|
||||||
Some(reading_time),
|
|
||||||
matter.excerpt,
|
|
||||||
front_matter,
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut posts = Vec::new();
|
|
||||||
for file in files {
|
|
||||||
let file = file?;
|
|
||||||
if let Some(file) = file {
|
|
||||||
posts.push(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
posts.sort_by(|a, b| b.doc_info.published.cmp(&a.doc_info.published));
|
|
||||||
|
|
||||||
Ok(posts)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_tags(&self) -> Result<HashMap<String, Tag>, SourceError> {
|
|
||||||
let file = CONTENT_DIR.get_file("tags.yaml").expect("tags.yaml");
|
|
||||||
match serde_yaml::from_slice::<Vec<Tag>>(file.contents()) {
|
|
||||||
Ok(tags) => Ok(tags
|
|
||||||
.into_iter()
|
|
||||||
.map(|tag| (tag.slug.clone(), tag))
|
|
||||||
.collect()),
|
|
||||||
Err(err) => {
|
|
||||||
log::error!("Failed to parse tags.yaml: {err}");
|
|
||||||
Err(SourceError::InvalidTags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_post_files<'a>() -> impl Iterator<Item = &'a File<'a>> {
|
|
||||||
CONTENT_DIR.get_dir("posts").expect("posts dir").files()
|
|
||||||
}
|
|
||||||
|
|
||||||
static CONTENT_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/content");
|
|
94
src/model/source/hydrating.rs
Normal file
94
src/model/source/hydrating.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use thiserror::Error;
|
||||||
|
use yew::{function_component, html, use_state, Children, ContextProvider, Html, Properties};
|
||||||
|
use yew_hooks::{use_async_with_options, UseAsyncOptions};
|
||||||
|
|
||||||
|
use crate::model::source::{PostsContext, TagsContext};
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Clone, PartialEq)]
|
||||||
|
pub enum ApiError {
|
||||||
|
#[error("Unable to complete request")]
|
||||||
|
RequestError,
|
||||||
|
#[error("Unable to deserialize response")]
|
||||||
|
DeserializeError,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct ProvideTagsProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(ProvideTags)]
|
||||||
|
pub fn provide_tags(props: &ProvideTagsProps) -> Html {
|
||||||
|
let tags = use_state(HashMap::new);
|
||||||
|
|
||||||
|
{
|
||||||
|
let tags = tags.clone();
|
||||||
|
use_async_with_options::<_, (), ApiError>(
|
||||||
|
async move {
|
||||||
|
let res = reqwest::get("/tags.json")
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
log::error!("Failed to get '/tags.json': {err:?}");
|
||||||
|
ApiError::RequestError
|
||||||
|
})?
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
log::error!("Failed to deserialize '/tags.json': {err:?}");
|
||||||
|
ApiError::DeserializeError
|
||||||
|
})?;
|
||||||
|
tags.set(res);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
UseAsyncOptions::enable_auto(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<ContextProvider<TagsContext> context={(*tags).clone()}>
|
||||||
|
{props.children.clone()}
|
||||||
|
</ContextProvider<TagsContext>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct ProvidePostsProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(ProvidePosts)]
|
||||||
|
pub fn provide_posts(props: &ProvidePostsProps) -> Html {
|
||||||
|
let posts = use_state(Vec::new);
|
||||||
|
|
||||||
|
{
|
||||||
|
let posts = posts.clone();
|
||||||
|
use_async_with_options::<_, (), ApiError>(
|
||||||
|
async move {
|
||||||
|
let res = reqwest::get("/posts.json")
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
log::error!("Failed to get '/posts.json': {err:?}");
|
||||||
|
ApiError::RequestError
|
||||||
|
})?
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
log::error!("Failed to deserialize '/posts.json': {err:?}");
|
||||||
|
ApiError::DeserializeError
|
||||||
|
})?;
|
||||||
|
posts.set(res);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
UseAsyncOptions::enable_auto(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<ContextProvider<PostsContext> context={(*posts).clone()}>
|
||||||
|
{props.children.clone()}
|
||||||
|
</ContextProvider<PostsContext>>
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
use crate::model::PostInfo;
|
|
||||||
|
|
||||||
use super::{ModelProvider, SourceError};
|
|
||||||
|
|
||||||
pub struct Source {}
|
|
||||||
|
|
||||||
impl Source {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ModelProvider for Source {
|
|
||||||
async fn get_posts(&self) -> Result<Vec<PostInfo>, SourceError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use yew::{
|
|
||||||
function_component, html, use_context, use_state, Children, ContextProvider, Html, Properties,
|
|
||||||
};
|
|
||||||
use yew_hooks::{use_async_with_options, UseAsyncOptions};
|
|
||||||
|
|
||||||
use crate::model::source::{ModelSource, SourceError};
|
|
||||||
|
|
||||||
use super::{source::ModelSourceWrapper, Tag};
|
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
|
||||||
pub struct TagsProviderProps {
|
|
||||||
#[prop_or_default]
|
|
||||||
pub children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default, PartialEq)]
|
|
||||||
pub struct TagsContext {
|
|
||||||
tags: HashMap<String, Tag>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TagsContext {
|
|
||||||
fn new(tags: HashMap<String, Tag>) -> Self {
|
|
||||||
Self { tags }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tag<S: AsRef<str>>(&self, slug: S) -> Option<Tag> {
|
|
||||||
self.tags.get(slug.as_ref()).cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component(TagsProvider)]
|
|
||||||
pub fn tags_provider(props: &TagsProviderProps) -> Html {
|
|
||||||
let source = use_context::<ModelSourceWrapper>().expect("ModelSource to be provided");
|
|
||||||
let tags = use_state(TagsContext::default);
|
|
||||||
|
|
||||||
{
|
|
||||||
let tags = tags.clone();
|
|
||||||
use_async_with_options::<_, (), SourceError>(
|
|
||||||
async move {
|
|
||||||
tags.set(TagsContext::new(source.get_tags().await?));
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
UseAsyncOptions::enable_auto(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<ContextProvider<TagsContext> context={(*tags).clone()}>
|
|
||||||
{props.children.clone()}
|
|
||||||
</ContextProvider<TagsContext>>
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +1,17 @@
|
|||||||
use yew::{function_component, html, use_context, use_state, Html};
|
use yew::{function_component, html, Html};
|
||||||
use yew_hooks::{use_async_with_options, UseAsyncOptions};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::blog::post_card_list::PostCardList,
|
components::blog::post_card_list::PostCardList,
|
||||||
model::source::{ModelSource, ModelSourceWrapper, SourceError},
|
model::source::{ProvidePosts, ProvideTags},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[function_component(Page)]
|
#[function_component(Page)]
|
||||||
pub fn page() -> Html {
|
pub fn page() -> Html {
|
||||||
let source = use_context::<ModelSourceWrapper>().expect("ModelSource to be provided");
|
|
||||||
let posts = use_state(Vec::new);
|
|
||||||
|
|
||||||
{
|
|
||||||
let posts = posts.clone();
|
|
||||||
use_async_with_options::<_, (), SourceError>(
|
|
||||||
async move {
|
|
||||||
posts.set(source.get_posts().await?);
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
UseAsyncOptions::enable_auto(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<ProvideTags>
|
||||||
<PostCardList posts={(*posts).clone()} />
|
<ProvidePosts>
|
||||||
</>
|
<PostCardList />
|
||||||
|
</ProvidePosts>
|
||||||
|
</ProvideTags>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,17 @@
|
|||||||
use yew::{function_component, html, use_context, use_state, Html};
|
use yew::{function_component, html, Html};
|
||||||
use yew_hooks::{use_async_with_options, UseAsyncOptions};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::blog::post_card_list::PostCardList,
|
components::blog::post_card_list::PostCardList,
|
||||||
model::source::{ModelSource, ModelSourceWrapper, SourceError},
|
model::source::{ProvidePosts, ProvideTags},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[function_component(Page)]
|
#[function_component(Page)]
|
||||||
pub fn page() -> Html {
|
pub fn page() -> Html {
|
||||||
let source = use_context::<ModelSourceWrapper>().expect("ModelSource to be provided");
|
|
||||||
let posts = use_state(Vec::new);
|
|
||||||
|
|
||||||
{
|
|
||||||
let posts = posts.clone();
|
|
||||||
use_async_with_options::<_, (), SourceError>(
|
|
||||||
async move {
|
|
||||||
posts.set(source.get_posts().await?);
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
UseAsyncOptions::enable_auto(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<ProvideTags>
|
||||||
<PostCardList posts={(*posts).clone()} />
|
<ProvidePosts>
|
||||||
</>
|
<PostCardList />
|
||||||
|
</ProvidePosts>
|
||||||
|
</ProvideTags>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user