feat: add block layout for home page with CSS
This commit is contained in:
parent
282b719e61
commit
c2a2721ec6
13 changed files with 842 additions and 351 deletions
421
Cargo.lock
generated
421
Cargo.lock
generated
|
@ -146,18 +146,19 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
|
"axum-template",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"fully_pub",
|
"fully_pub",
|
||||||
"log",
|
"log",
|
||||||
"minijinja",
|
"minijinja 1.0.20",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tera",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tower-http",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -216,6 +217,18 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-template"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7013f6403ac283c62d843b344d27742a3ffb48f57a2263522b7c978cec40cc1"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"minijinja 2.0.3",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.71"
|
version = "0.3.71"
|
||||||
|
@ -267,16 +280,6 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bstr"
|
|
||||||
version = "1.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.15.4"
|
version = "3.15.4"
|
||||||
|
@ -322,28 +325,6 @@ dependencies = [
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono-tz"
|
|
||||||
version = "0.8.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"chrono-tz-build",
|
|
||||||
"phf",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono-tz-build"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f"
|
|
||||||
dependencies = [
|
|
||||||
"parse-zoneinfo",
|
|
||||||
"phf",
|
|
||||||
"phf_codegen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.4"
|
version = "4.5.4"
|
||||||
|
@ -413,25 +394,6 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -468,12 +430,6 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "deunicode"
|
|
||||||
version = "1.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
@ -704,30 +660,6 @@ version = "0.28.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "globset"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"bstr",
|
|
||||||
"log",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "globwalk"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"ignore",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
|
@ -829,6 +761,12 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-range-header"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -841,15 +779,6 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humansize"
|
|
||||||
version = "2.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
|
|
||||||
dependencies = [
|
|
||||||
"libm",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -924,22 +853,6 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ignore"
|
|
||||||
version = "0.4.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque",
|
|
||||||
"globset",
|
|
||||||
"log",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"same-file",
|
|
||||||
"walkdir",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.2.6"
|
||||||
|
@ -1056,6 +969,16 @@ version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime_guess"
|
||||||
|
version = "2.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||||
|
dependencies = [
|
||||||
|
"mime",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minijinja"
|
name = "minijinja"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
|
@ -1065,6 +988,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minijinja"
|
||||||
|
version = "2.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "933ee10775d58fca8238a84fe165dfe4bde8b07d7574f24d76ffea91170f3ac6"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minimal-lexical"
|
name = "minimal-lexical"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1196,15 +1128,6 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parse-zoneinfo"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
|
|
||||||
dependencies = [
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
@ -1226,89 +1149,6 @@ version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest"
|
|
||||||
version = "2.7.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"thiserror",
|
|
||||||
"ucd-trie",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest_derive"
|
|
||||||
version = "2.7.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c"
|
|
||||||
dependencies = [
|
|
||||||
"pest",
|
|
||||||
"pest_generator",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest_generator"
|
|
||||||
version = "2.7.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd"
|
|
||||||
dependencies = [
|
|
||||||
"pest",
|
|
||||||
"pest_meta",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.58",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest_meta"
|
|
||||||
version = "2.7.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"pest",
|
|
||||||
"sha2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_codegen"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
|
|
||||||
dependencies = [
|
|
||||||
"phf_generator",
|
|
||||||
"phf_shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_generator"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared",
|
|
||||||
"rand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_shared"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
|
||||||
dependencies = [
|
|
||||||
"siphasher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.5"
|
version = "1.1.5"
|
||||||
|
@ -1511,15 +1351,6 @@ version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "same-file"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -1633,12 +1464,6 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "siphasher"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -1648,16 +1473,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "slug"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4"
|
|
||||||
dependencies = [
|
|
||||||
"deunicode",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
|
@ -1977,28 +1792,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tera"
|
|
||||||
version = "1.19.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"chrono-tz",
|
|
||||||
"globwalk",
|
|
||||||
"humansize",
|
|
||||||
"lazy_static",
|
|
||||||
"percent-encoding",
|
|
||||||
"pest",
|
|
||||||
"pest_derive",
|
|
||||||
"rand",
|
|
||||||
"regex",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"slug",
|
|
||||||
"unic-segment",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.58"
|
version = "1.0.58"
|
||||||
|
@ -2075,6 +1868,19 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
@ -2091,6 +1897,31 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-http"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"http-range-header",
|
||||||
|
"httpdate",
|
||||||
|
"mime",
|
||||||
|
"mime_guess",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-layer"
|
name = "tower-layer"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2142,59 +1973,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ucd-trie"
|
name = "unicase"
|
||||||
version = "0.1.6"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-char-property"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unic-char-range",
|
"version_check",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-char-range"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-common"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-segment"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23"
|
|
||||||
dependencies = [
|
|
||||||
"unic-ucd-segment",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-ucd-segment"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700"
|
|
||||||
dependencies = [
|
|
||||||
"unic-char-property",
|
|
||||||
"unic-char-range",
|
|
||||||
"unic-ucd-version",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-ucd-version"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
|
|
||||||
dependencies = [
|
|
||||||
"unic-common",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2281,16 +2065,6 @@ 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 = "walkdir"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
|
||||||
dependencies = [
|
|
||||||
"same-file",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -2367,37 +2141,6 @@ dependencies = [
|
||||||
"wasite",
|
"wasite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
|
@ -11,7 +11,6 @@ chrono = { version = "0.4.26", features = ["serde"] }
|
||||||
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio", "chrono"] }
|
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio", "chrono"] }
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
clap = "4.5.4"
|
clap = "4.5.4"
|
||||||
tera = "1.19.1"
|
|
||||||
tokio = { version = "1.37.0", features = ["full"] }
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
axum = { version = "0.7.5", features = ["json"] }
|
axum = { version = "0.7.5", features = ["json"] }
|
||||||
minijinja = { version = "1.0.20", features = ["builtins"] }
|
minijinja = { version = "1.0.20", features = ["builtins"] }
|
||||||
|
@ -19,4 +18,6 @@ uuid = { version = "1.8.0", features = ["serde", "v4"] }
|
||||||
fully_pub = "0.1.4"
|
fully_pub = "0.1.4"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
|
tower-http = { version = "0.5.2", features = ["fs"] }
|
||||||
|
axum-template = { version = "2.3.0", features = ["minijinja"] }
|
||||||
|
|
||||||
|
|
0
assets/styles/app.css
Normal file
0
assets/styles/app.css
Normal file
712
assets/styles/simple.css
Normal file
712
assets/styles/simple.css
Normal file
|
@ -0,0 +1,712 @@
|
||||||
|
/* Global variables. */
|
||||||
|
:root,
|
||||||
|
::backdrop {
|
||||||
|
/* Set sans-serif & mono fonts */
|
||||||
|
--sans-font: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir,
|
||||||
|
"Nimbus Sans L", Roboto, "Noto Sans", "Segoe UI", Arial, Helvetica,
|
||||||
|
"Helvetica Neue", sans-serif;
|
||||||
|
--mono-font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||||
|
--standard-border-radius: 5px;
|
||||||
|
|
||||||
|
/* Default (light) theme */
|
||||||
|
--bg: #fff;
|
||||||
|
--accent-bg: #f5f7ff;
|
||||||
|
--text: #212121;
|
||||||
|
--text-light: #585858;
|
||||||
|
--border: #898EA4;
|
||||||
|
--accent: #0d47a1;
|
||||||
|
--accent-hover: #1266e2;
|
||||||
|
--accent-text: var(--bg);
|
||||||
|
--code: #d81b60;
|
||||||
|
--preformatted: #444;
|
||||||
|
--marked: #ffdd33;
|
||||||
|
--disabled: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark theme */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root,
|
||||||
|
::backdrop {
|
||||||
|
color-scheme: dark;
|
||||||
|
--bg: #212121;
|
||||||
|
--accent-bg: #2b2b2b;
|
||||||
|
--text: #dcdcdc;
|
||||||
|
--text-light: #ababab;
|
||||||
|
--accent: #ffb300;
|
||||||
|
--accent-hover: #ffe099;
|
||||||
|
--accent-text: var(--bg);
|
||||||
|
--code: #f06292;
|
||||||
|
--preformatted: #ccc;
|
||||||
|
--disabled: #111;
|
||||||
|
}
|
||||||
|
/* Add a bit of transparency so light media isn't so glaring in dark mode */
|
||||||
|
img,
|
||||||
|
video {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset box-sizing */
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset default appearance */
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
input,
|
||||||
|
progress {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
/* Set the font globally */
|
||||||
|
font-family: var(--sans-font);
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the body a nice central block */
|
||||||
|
body {
|
||||||
|
color: var(--text);
|
||||||
|
background-color: var(--bg);
|
||||||
|
font-size: 1.15rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr min(45rem, 90%) 1fr;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
body > * {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the header bg full width, but the content inline with body */
|
||||||
|
body > header {
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 0.5rem 2rem 0.5rem;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > header > *:only-child {
|
||||||
|
margin-block-start: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > header h1 {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 1rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > header p {
|
||||||
|
max-width: 40rem;
|
||||||
|
margin: 1rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a little padding to ensure spacing is correct between content and header > nav */
|
||||||
|
main {
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > footer {
|
||||||
|
margin-top: 4rem;
|
||||||
|
padding: 2rem 1rem 1.5rem 1rem;
|
||||||
|
color: var(--text-light);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format headers */
|
||||||
|
h1 {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.6rem;
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.44rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 0.96rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent long strings from overflowing container */
|
||||||
|
p, h1, h2, h3, h4, h5, h6 {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix line height when title wraps */
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reduce header size on mobile */
|
||||||
|
@media only screen and (max-width: 720px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format links & buttons */
|
||||||
|
a,
|
||||||
|
a:visited {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
.button,
|
||||||
|
a.button, /* extra specificity to override a */
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="button"],
|
||||||
|
label[type="button"] {
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
background-color: var(--accent);
|
||||||
|
color: var(--accent-text);
|
||||||
|
padding: 0.5rem 0.9rem;
|
||||||
|
text-decoration: none;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button[aria-disabled="true"],
|
||||||
|
input:disabled,
|
||||||
|
textarea:disabled,
|
||||||
|
select:disabled,
|
||||||
|
button[disabled] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: var(--disabled);
|
||||||
|
border-color: var(--disabled);
|
||||||
|
color: var(--text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"] {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the cursor to '?' on an abbreviation and style the abbreviation to show that there is more information underneath */
|
||||||
|
abbr[title] {
|
||||||
|
cursor: help;
|
||||||
|
text-decoration-line: underline;
|
||||||
|
text-decoration-style: dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:enabled:hover,
|
||||||
|
.button:not([aria-disabled="true"]):hover,
|
||||||
|
input[type="submit"]:enabled:hover,
|
||||||
|
input[type="reset"]:enabled:hover,
|
||||||
|
input[type="button"]:enabled:hover,
|
||||||
|
label[type="button"]:hover {
|
||||||
|
background-color: var(--accent-hover);
|
||||||
|
border-color: var(--accent-hover);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:focus-visible,
|
||||||
|
button:focus-visible:where(:enabled),
|
||||||
|
input:enabled:focus-visible:where(
|
||||||
|
[type="submit"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="button"]
|
||||||
|
) {
|
||||||
|
outline: 2px solid var(--accent);
|
||||||
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format navigation */
|
||||||
|
header > nav {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 2;
|
||||||
|
padding: 1rem 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use flexbox to allow items to wrap, as needed */
|
||||||
|
header > nav ul,
|
||||||
|
header > nav ol {
|
||||||
|
align-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List items are inline elements, make them behave more like blocks */
|
||||||
|
header > nav ul li,
|
||||||
|
header > nav ol li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
header > nav a,
|
||||||
|
header > nav a:visited {
|
||||||
|
margin: 0 0.5rem 1rem 0.5rem;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
color: var(--text);
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.1rem 1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
header > nav a:hover,
|
||||||
|
header > nav a.current,
|
||||||
|
header > nav a[aria-current="page"] {
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reduce nav side on mobile */
|
||||||
|
@media only screen and (max-width: 720px) {
|
||||||
|
header > nav a {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: underline;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consolidate box styling */
|
||||||
|
aside, details, pre, progress {
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 30%;
|
||||||
|
padding: 0 15px;
|
||||||
|
margin-inline-start: 15px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
*[dir="rtl"] aside {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make aside full-width on mobile */
|
||||||
|
@media only screen and (max-width: 720px) {
|
||||||
|
aside {
|
||||||
|
width: 100%;
|
||||||
|
float: none;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
article, fieldset, dialog {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article h2:first-child,
|
||||||
|
section h2:first-child,
|
||||||
|
article h3:first-child,
|
||||||
|
section h3:first-child {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
margin: 3rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't double separators when chaining sections */
|
||||||
|
section + section,
|
||||||
|
section:first-child {
|
||||||
|
border-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section + section {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
details {
|
||||||
|
padding: 0.7rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0.7rem 1rem;
|
||||||
|
margin: -0.7rem -1rem;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
details[open] > summary + * {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
details[open] > summary {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
details[open] > :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format tables */
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure > table {
|
||||||
|
width: max-content;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
text-align: start;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
/* Set every other cell slightly darker. Improves readability. */
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
table caption {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format forms */
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
.button {
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
box-shadow: none;
|
||||||
|
max-width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
input {
|
||||||
|
color: var(--text);
|
||||||
|
background-color: var(--bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
textarea:not([cols]) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add arrow to drop-down */
|
||||||
|
select:not([multiple]) {
|
||||||
|
background-image: linear-gradient(45deg, transparent 49%, var(--text) 51%),
|
||||||
|
linear-gradient(135deg, var(--text) 51%, transparent 49%);
|
||||||
|
background-position: calc(100% - 15px), calc(100% - 10px);
|
||||||
|
background-size: 5px 5px, 5px 5px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding-inline-end: 25px;
|
||||||
|
}
|
||||||
|
*[dir="rtl"] select:not([multiple]) {
|
||||||
|
background-position: 10px, 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checkbox and radio button style */
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
vertical-align: middle;
|
||||||
|
position: relative;
|
||||||
|
width: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] + label,
|
||||||
|
input[type="radio"] + label {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked,
|
||||||
|
input[type="radio"]:checked {
|
||||||
|
background-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked::after {
|
||||||
|
/* Creates a rectangle with colored right and bottom borders which is rotated to look like a check mark */
|
||||||
|
content: " ";
|
||||||
|
width: 0.18em;
|
||||||
|
height: 0.32em;
|
||||||
|
border-radius: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.05em;
|
||||||
|
left: 0.17em;
|
||||||
|
background-color: transparent;
|
||||||
|
border-right: solid var(--bg) 0.08em;
|
||||||
|
border-bottom: solid var(--bg) 0.08em;
|
||||||
|
font-size: 1.8em;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
input[type="radio"]:checked::after {
|
||||||
|
/* creates a colored circle for the checked radio button */
|
||||||
|
content: " ";
|
||||||
|
width: 0.25em;
|
||||||
|
height: 0.25em;
|
||||||
|
border-radius: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.125em;
|
||||||
|
background-color: var(--bg);
|
||||||
|
left: 0.125em;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Makes input fields wider on smaller screens */
|
||||||
|
@media only screen and (max-width: 720px) {
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a height for color input */
|
||||||
|
input[type="color"] {
|
||||||
|
height: 2.5rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do not show border around file selector button */
|
||||||
|
input[type="file"] {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc body elements */
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border);
|
||||||
|
margin: 1rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
background-color: var(--marked);
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark a {
|
||||||
|
color: #0d47a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0;
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure > img,
|
||||||
|
figure > picture > img {
|
||||||
|
display: block;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-light);
|
||||||
|
margin-block: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin-inline-start: 2rem;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-block: 2rem;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border-inline-start: 0.35rem solid var(--accent);
|
||||||
|
color: var(--text-light);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
cite {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-light);
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
color: var(--text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use mono font for code elements */
|
||||||
|
code,
|
||||||
|
pre,
|
||||||
|
pre span,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: var(--mono-font);
|
||||||
|
color: var(--code);
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
color: var(--preformatted);
|
||||||
|
border: 1px solid var(--preformatted);
|
||||||
|
border-bottom: 3px solid var(--preformatted);
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
padding: 0.1rem 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 1rem 1.4rem;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
color: var(--preformatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix embedded code within pre */
|
||||||
|
pre code {
|
||||||
|
color: var(--preformatted);
|
||||||
|
background: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress bars */
|
||||||
|
/* Declarations are repeated because you */
|
||||||
|
/* cannot combine vendor-specific selectors */
|
||||||
|
progress {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress:indeterminate {
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-bar {
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-value {
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
background-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-moz-progress-bar {
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
background-color: var(--accent);
|
||||||
|
transition-property: width;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress:indeterminate::-moz-progress-bar {
|
||||||
|
background-color: var(--accent-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
max-width: 40rem;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog::backdrop {
|
||||||
|
background-color: var(--bg);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 720px) {
|
||||||
|
dialog {
|
||||||
|
max-width: 100%;
|
||||||
|
margin: auto 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Superscript & Subscript */
|
||||||
|
/* Prevent scripts from affecting line-height. */
|
||||||
|
sup, sub {
|
||||||
|
vertical-align: baseline;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
top: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Classes for notices */
|
||||||
|
.notice {
|
||||||
|
background: var(--accent-bg);
|
||||||
|
border: 2px solid var(--border);
|
||||||
|
border-radius: var(--standard-border-radius);
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
|
|
|
@ -2,23 +2,28 @@ use crate::models::{Task, TaskRun, TaskRunSummary};
|
||||||
use axum::extract::{Path as ExtractPath, State};
|
use axum::extract::{Path as ExtractPath, State};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::Json;
|
use axum::Json;
|
||||||
use axum::response::Html;
|
use axum::response::{Html, IntoResponse, Response};
|
||||||
use minijinja::render;
|
use axum_template::RenderHtml;
|
||||||
|
use minijinja::{context, render};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::models::ExecutorOrder;
|
use crate::models::ExecutorOrder;
|
||||||
use crate::AppState;
|
use crate::{AppState};
|
||||||
|
|
||||||
pub async fn home() -> Html<String> {
|
pub async fn home(
|
||||||
Html(render!(
|
State(app_state): State<AppState>
|
||||||
include_str!("./templates/home.html"),
|
) -> impl IntoResponse {
|
||||||
))
|
Html(
|
||||||
|
app_state.template_engine.get_template("pages/home.html").unwrap()
|
||||||
|
.render(context!())
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_tasks(State(app_state): State<AppState>) -> Html<String> {
|
pub async fn list_tasks(State(app_state): State<AppState>) -> Html<String> {
|
||||||
let tasks: Vec<Task> = app_state.config.tasks;
|
let tasks: Vec<Task> = app_state.config.tasks;
|
||||||
Html(render!(
|
Html(render!(
|
||||||
include_str!("./templates/list_tasks.html"),
|
include_str!("./templates/pages/list_tasks.html"),
|
||||||
tasks => tasks
|
tasks => tasks
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -49,7 +54,7 @@ pub async fn trigger_task(
|
||||||
(
|
(
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Html(render!(
|
Html(render!(
|
||||||
include_str!("./templates/run_task.html"),
|
include_str!("./templates/pages/run_task.html"),
|
||||||
tasks => tasks
|
tasks => tasks
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
|
@ -80,7 +85,7 @@ pub async fn list_task_runs(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Html(render!(
|
Html(render!(
|
||||||
include_str!("./templates/list_task_runs.html"),
|
include_str!("./templates/pages/list_task_runs.html"),
|
||||||
task => task,
|
task => task,
|
||||||
runs => runs,
|
runs => runs,
|
||||||
))
|
))
|
||||||
|
@ -102,7 +107,7 @@ pub async fn get_task_run(
|
||||||
};
|
};
|
||||||
|
|
||||||
Html(render!(
|
Html(render!(
|
||||||
include_str!("./templates/task_run_details.html"),
|
include_str!("./templates/pages/task_run_details.html"),
|
||||||
run => run_details
|
run => run_details
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -2,12 +2,15 @@ mod controllers;
|
||||||
mod models;
|
mod models;
|
||||||
mod executor;
|
mod executor;
|
||||||
|
|
||||||
|
use axum_template::engine::Engine;
|
||||||
use log::info;
|
use log::info;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
use minijinja::Environment;
|
||||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||||
use sqlx::{ConnectOptions, Pool, Sqlite};
|
use sqlx::{ConnectOptions, Pool, Sqlite};
|
||||||
|
use tower_http::services::ServeDir;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -20,6 +23,7 @@ pub struct AppState {
|
||||||
config: Config,
|
config: Config,
|
||||||
db: Pool<Sqlite>,
|
db: Pool<Sqlite>,
|
||||||
executor_tx: Arc<Sender<ExecutorOrder>>,
|
executor_tx: Arc<Sender<ExecutorOrder>>,
|
||||||
|
template_engine: Environment<'static>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config() -> Result<Config> {
|
fn get_config() -> Result<Config> {
|
||||||
|
@ -42,10 +46,17 @@ async fn main() -> Result<()> {
|
||||||
let (tx, rx) = mpsc::channel::<ExecutorOrder>(32);
|
let (tx, rx) = mpsc::channel::<ExecutorOrder>(32);
|
||||||
|
|
||||||
let config: Config = get_config().expect("Cannot get config");
|
let config: Config = get_config().expect("Cannot get config");
|
||||||
|
let mut jinja = Environment::new();
|
||||||
|
jinja
|
||||||
|
.add_template("layouts/base.html", include_str!("./templates/layouts/base.html"))
|
||||||
|
.unwrap();
|
||||||
|
jinja.add_template("pages/home.html", include_str!("./templates/pages/home.html")).unwrap();
|
||||||
|
|
||||||
let state = AppState {
|
let state = AppState {
|
||||||
config,
|
config,
|
||||||
db: pool,
|
db: pool,
|
||||||
executor_tx: Arc::new(tx),
|
executor_tx: Arc::new(tx),
|
||||||
|
template_engine: jinja
|
||||||
};
|
};
|
||||||
|
|
||||||
// start executor daemon
|
// start executor daemon
|
||||||
|
@ -65,6 +76,7 @@ async fn main() -> Result<()> {
|
||||||
get(controllers::get_task_run),
|
get(controllers::get_task_run),
|
||||||
)
|
)
|
||||||
.route("/webhooks/:token", get(controllers::handle_webhook))
|
.route("/webhooks/:token", get(controllers::handle_webhook))
|
||||||
|
.nest_service("/assets", ServeDir::new("./assets"))
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
let listen_addr = "0.0.0.0:8085";
|
let listen_addr = "0.0.0.0:8085";
|
||||||
|
|
15
src/templates/layouts/base.html
Normal file
15
src/templates/layouts/base.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Autotasker</title>
|
||||||
|
<link href="/assets/styles/simple.css" rel="stylesheet">
|
||||||
|
<link href="/assets/styles/app.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,3 +1,5 @@
|
||||||
|
{% extends "layouts/base.html" %}
|
||||||
|
{% block body %}
|
||||||
<h1>Hello welcome on autotasker</h1>
|
<h1>Hello welcome on autotasker</h1>
|
||||||
|
|
||||||
You main want to start in here.
|
You main want to start in here.
|
||||||
|
@ -10,3 +12,4 @@ Autotasker is free software under <a href="https://www.gnu.org/licenses/gpl-3.0.
|
||||||
|
|
||||||
You can find source code on a <a href="https://forge.lefuturiste.fr/mbess/autotasker">self-hosted forge repository</a>.
|
You can find source code on a <a href="https://forge.lefuturiste.fr/mbess/autotasker">self-hosted forge repository</a>.
|
||||||
</p>
|
</p>
|
||||||
|
{% endblock %}
|
BIN
tmp/dbs/current.db
Normal file
BIN
tmp/dbs/current.db
Normal file
Binary file not shown.
Loading…
Reference in a new issue