From 0ca4161e036d2735f15aefc87def7ec8bab0902d Mon Sep 17 00:00:00 2001 From: eiiko6 Date: Fri, 13 Feb 2026 18:20:33 +0100 Subject: [PATCH] converted to wiki --- Cargo.lock | 399 +++++++++++++++++++++-------------- Cargo.toml | 6 +- example/azrak.md | 31 +++ example/azrak.toml | 11 + example/bernardo.md | 5 + example/bernardo.png | Bin 0 -> 53014 bytes example/bernardo.toml | 9 + example/coffee@1767815445.md | 14 -- example/ferris@1767468388.md | 16 -- example/lumina.md | 28 +++ example/lumina.toml | 11 + example/space@1767813388.md | 17 -- example/voidmother.md | 32 +++ example/voidmother.toml | 11 + flake.lock | 109 ---------- flake.nix | 19 +- src/main.rs | 181 +++++++++------- templates/page.html | 87 +++++--- templates/style.css | 352 ++++++++++-------------------- 19 files changed, 681 insertions(+), 657 deletions(-) create mode 100644 example/azrak.md create mode 100644 example/azrak.toml create mode 100644 example/bernardo.md create mode 100755 example/bernardo.png create mode 100644 example/bernardo.toml delete mode 100644 example/coffee@1767815445.md delete mode 100644 example/ferris@1767468388.md create mode 100644 example/lumina.md create mode 100644 example/lumina.toml delete mode 100644 example/space@1767813388.md create mode 100644 example/voidmother.md create mode 100644 example/voidmother.toml delete mode 100644 flake.lock diff --git a/Cargo.lock b/Cargo.lock index 259c166..63835d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,9 +78,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "atomic-waker" @@ -96,9 +96,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.15.2" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" dependencies = [ "aws-lc-sys", "zeroize", @@ -106,9 +106,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.35.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" dependencies = [ "cc", "cmake", @@ -198,27 +198,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blog" -version = "0.1.0" -dependencies = [ - "anyhow", - "axum", - "chrono", - "clap", - "lazy_static", - "pulldown-cmark", - "pulldown-cmark-escape", - "reqwest", - "serde", - "syntect", - "tera", - "tokio", - "tower-http", - "tracing", - "tracing-subscriber", -] - [[package]] name = "bstr" version = "1.12.1" @@ -237,15 +216,15 @@ checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.51" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "jobserver", @@ -273,9 +252,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", "js-sys", @@ -308,9 +287,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" dependencies = [ "clap_builder", "clap_derive", @@ -318,9 +297,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" dependencies = [ "anstream", "anstyle", @@ -330,9 +309,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", @@ -342,9 +321,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cmake" @@ -452,9 +431,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" dependencies = [ "powerfmt", ] @@ -519,15 +498,15 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -625,9 +604,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -738,6 +717,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + [[package]] name = "httparse" version = "1.10.1" @@ -800,14 +785,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -826,9 +810,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -968,12 +952,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown", + "serde", + "serde_core", ] [[package]] @@ -1038,9 +1024,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -1054,15 +1040,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.179" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "linked-hash-map" @@ -1105,9 +1091,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mime" @@ -1115,6 +1101,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "miniz_oxide" version = "0.8.9" @@ -1147,9 +1143,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-traits" @@ -1196,9 +1192,9 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "parking_lot" @@ -1240,9 +1236,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.5" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" dependencies = [ "memchr", "ucd-trie", @@ -1250,9 +1246,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.5" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed" +checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" dependencies = [ "pest", "pest_generator", @@ -1260,9 +1256,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.5" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5" +checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" dependencies = [ "pest", "pest_meta", @@ -1273,9 +1269,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.5" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365" +checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" dependencies = [ "pest", "sha2", @@ -1376,9 +1372,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1425,7 +1421,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -1447,7 +1443,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -1469,9 +1465,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1500,7 +1496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -1520,7 +1516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -1529,14 +1525,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -1552,9 +1548,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1564,9 +1560,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1575,15 +1571,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "reqwest" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64", "bytes", @@ -1627,7 +1623,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -1667,9 +1663,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -1704,9 +1700,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "aws-lc-rs", "ring", @@ -1722,9 +1718,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -1827,6 +1823,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1883,15 +1888,15 @@ checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slug" @@ -1911,9 +1916,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -1939,9 +1944,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" dependencies = [ "proc-macro2", "quote", @@ -1984,16 +1989,16 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "walkdir", "yaml-rust", ] [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", "core-foundation 0.9.4", @@ -2043,11 +2048,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -2063,9 +2068,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -2083,30 +2088,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -2189,10 +2194,51 @@ dependencies = [ ] [[package]] -name = "tower" -version = "0.5.2" +name = "toml" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -2212,14 +2258,24 @@ checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", + "futures-core", "futures-util", "http", "http-body", + "http-body-util", + "http-range-header", + "httpdate", "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -2318,9 +2374,9 @@ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-segmentation" @@ -2403,18 +2459,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -2425,11 +2481,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -2438,9 +2495,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2448,9 +2505,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ "bumpalo", "proc-macro2", @@ -2461,18 +2518,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -2490,13 +2547,36 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] +[[package]] +name = "wiki-maker" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "chrono", + "clap", + "indexmap", + "lazy_static", + "pulldown-cmark", + "pulldown-cmark-escape", + "reqwest", + "serde", + "syntect", + "tera", + "tokio", + "toml", + "tower-http", + "tracing", + "tracing-subscriber", +] + [[package]] name = "winapi-util" version = "0.1.11" @@ -2799,10 +2879,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "wit-bindgen" -version = "0.46.0" +name = "winnow" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "writeable" @@ -2844,18 +2933,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.32" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.32" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", @@ -2924,6 +3013,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.12" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index cad5f3e..b7f052a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "blog" +name = "wiki-maker" version = "0.1.0" edition = "2024" @@ -15,9 +15,11 @@ serde = { version = "1.0.228", features = ["derive"] } syntect = "5.3.0" tera = "1.20.1" tokio = { version = "1.49.0", features = ["full"] } -tower-http = { version = "0.6.8", features = ["cors"] } +tower-http = { version = "0.6.8", features = ["cors", "fs"] } tracing = "0.1.44" tracing-subscriber = "0.3.22" +toml = "0.8.19" +indexmap = { version = "2.7.1", features = ["serde"] } [build-dependencies] reqwest = { version = "0.13.1", features = ["blocking"] } diff --git a/example/azrak.md b/example/azrak.md new file mode 100644 index 0000000..672bb8b --- /dev/null +++ b/example/azrak.md @@ -0,0 +1,31 @@ +# Azrak the Wall-Eater + +Azrak does not eat food. + +Azrak eats **structures**. + +Concrete. +Drywall. +The concept of shelter. + +--- + +## Lore + +When humans invented houses, Azrak woke up. + +Every abandoned building is believed to be a corpse. + +--- + +## Family + +- Mother: [Voidmother](voidmother) +- Sister: [Lumina](lumina) + +--- + +## Fun Fact + +Azrak once ate half a shopping mall because a light flickered funny. + diff --git a/example/azrak.toml b/example/azrak.toml new file mode 100644 index 0000000..2c2b9e0 --- /dev/null +++ b/example/azrak.toml @@ -0,0 +1,11 @@ +title = "Azrak the Wall-Eater" +image = "azrak.png" +content_file = "azrak.md" + +[infobox] +"Espèce" = "Devourer Papoute" +"Genre" = "M" +"Domain" = "Hunger & Destruction" +"Enemy of" = "Entire buildings" +"Mother" = "Voidmother" + diff --git a/example/bernardo.md b/example/bernardo.md new file mode 100644 index 0000000..482b37c --- /dev/null +++ b/example/bernardo.md @@ -0,0 +1,5 @@ +## Biographie +Bernardo est un Papoute commun. Il est souvent considéré en tant qu'example de l'espèce, de par sa simplicité faciale et le parfait alignement de ses pates. + +## Répliques +> ... diff --git a/example/bernardo.png b/example/bernardo.png new file mode 100755 index 0000000000000000000000000000000000000000..1df10b6426f2e0888c5f5fcc1585e7cc2187a192 GIT binary patch literal 53014 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 literal 0 HcmV?d00001 diff --git a/example/bernardo.toml b/example/bernardo.toml new file mode 100644 index 0000000..4c158a2 --- /dev/null +++ b/example/bernardo.toml @@ -0,0 +1,9 @@ +title = "Bernardo" +image = "bernardo.png" +content_file = "bernardo.md" + +[infobox] +"Espèce" = "Papoute Commun" +Genre = "H" +"Lieu d'habitation" = "Inside your walls" +"Créateur" = "Papoute god?" diff --git a/example/coffee@1767815445.md b/example/coffee@1767815445.md deleted file mode 100644 index 30bacbc..0000000 --- a/example/coffee@1767815445.md +++ /dev/null @@ -1,14 +0,0 @@ -# The Dark Elixir: A History of Coffee - -Coffee is more than just a drink; it's a global phenomenon. Legend has it that a goat herder named Kaldi discovered coffee in Ethiopia after noticing his goats became very energetic after eating berries from a certain tree. - -### Common Coffee Roasts - -| Roast | Color | Oil on Surface | Flavor Profile | -| :--- | :--- | :--- | :--- | -| **Light** | Light Brown | None | Toasted grain, high acidity | -| **Medium** | Medium Brown | Rare | Balanced flavor, aroma | -| **Dark** | Shiny Black | Heavy | Bitter, smoky, or burnt | - ---- -**Fun Fact:** Coffee is actually a fruit! The "beans" are the pits of a cherry-like berry. diff --git a/example/ferris@1767468388.md b/example/ferris@1767468388.md deleted file mode 100644 index 225f25f..0000000 --- a/example/ferris@1767468388.md +++ /dev/null @@ -1,16 +0,0 @@ -# The Mascot: Ferris - -**Ferris** is the unofficial mascot of the Rust community. He is a crab because Rust programmers often call themselves "Rustaceans" (a play on the word crustacean). - -### Why a crab? -- Rustaceans are known for being friendly and helpful. -- Crabs have hard shells (like Rust's safety guarantees). -- They have powerful claws (like Rust's powerful type system). - -```rust -fn main() { - println!("Hello from Ferris!"); -} -``` - -> "The Rust community is one of the most welcoming in the tech world." diff --git a/example/lumina.md b/example/lumina.md new file mode 100644 index 0000000..229ae6e --- /dev/null +++ b/example/lumina.md @@ -0,0 +1,28 @@ +# Lumina the Warm One + +Lumina is the reason blankets feel safe. + +She lives inside warm air vents, sunsets, and the feeling of soup. + +--- + +## Personality + +- Gentle +- Massive cosmic being +- Will still destroy stars if annoyed + +--- + +## Child + +Her smallest creation: + +- [Bernardo](bernardo) + +--- + +## Enemy + +- [Azrak](azrak) (he keeps eating her favorite houses) + diff --git a/example/lumina.toml b/example/lumina.toml new file mode 100644 index 0000000..b566fe7 --- /dev/null +++ b/example/lumina.toml @@ -0,0 +1,11 @@ +title = "Lumina the Warm One" +image = "lumina.png" +content_file = "lumina.md" + +[infobox] +"Espèce" = "Radiant Papoute" +"Genre" = "F" +"Domain" = "Comfort & heat" +"Children" = "Bernardo" +"Mother" = "Voidmother" + diff --git a/example/space@1767813388.md b/example/space@1767813388.md deleted file mode 100644 index 7b7ad9f..0000000 --- a/example/space@1767813388.md +++ /dev/null @@ -1,17 +0,0 @@ -# To the Stars: Voyager 1 - -Voyager 1 is a space probe launched by NASA on September 5, 1977. As of today, it is the most distant human-made object from Earth. - -### Voyager 1 Mission Checklist -- [x] Flyby of Jupiter (1979) -- [x] Flyby of Saturn (1980) -- [x] Enter Interstellar Space (2012) -- [ ] Reach the next star (Estimated in 40,000 years) - -### The Golden Record -The probe carries a gold-plated audio-visual disc in case it is ever found by intelligent life. It contains: -- Greetings in 55 languages. -- Sounds of whales, a baby crying, and waves breaking. -- Music by Bach, Mozart, and Chuck Berry. - -> "The Voyager mission is a testament to human curiosity and our desire to touch the stars." diff --git a/example/voidmother.md b/example/voidmother.md new file mode 100644 index 0000000..c826ed6 --- /dev/null +++ b/example/voidmother.md @@ -0,0 +1,32 @@ +# Voidmother + +Voidmother is not born. + +Voidmother **happened**. + +Before walls existed. +Before warmth existed. +Before Papoutes learned how to hide inside radiators. + +She tore reality like wet paper and leaked children into existence. + +--- + +## Offspring + +- [Azrak the Wall-Eater](azrak) +- [Lumina the Warm One](lumina) +- [Grubble](grubble) + +--- + +## Known Abilities + +- Creates Papoutes by accident +- Consumes timelines when annoyed +- Whispers inside electrical outlets + +> Some say Bernardo can hear her when the house is quiet. + +And she hears him too. + diff --git a/example/voidmother.toml b/example/voidmother.toml new file mode 100644 index 0000000..4570db9 --- /dev/null +++ b/example/voidmother.toml @@ -0,0 +1,11 @@ +title = "Voidmother" +image = "voidmother.png" +content_file = "voidmother.md" + +[infobox] +"Espèce" = "Primordial Papoute" +"Genre" = "Beyond gender" +"Rôle cosmique" = "Origin of all papoutes" +"Tempérament" = "Indescribable horror" +"Présence" = "Between dimensions" + diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 39feaa9..0000000 --- a/flake.lock +++ /dev/null @@ -1,109 +0,0 @@ -{ - "nodes": { - "code-theme": { - "flake": false, - "locked": { - "narHash": "sha256-28LGXKITHbrmt6qrcG/W+qTlaWthre7x7izp/TPjQgA=", - "type": "file", - "url": "https://raw.githubusercontent.com/catppuccin/bat/refs/heads/main/themes/Catppuccin%20Macchiato.tmTheme" - }, - "original": { - "type": "file", - "url": "https://raw.githubusercontent.com/catppuccin/bat/refs/heads/main/themes/Catppuccin%20Macchiato.tmTheme" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1767767207, - "narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5912c1772a44e31bf1c63c0390b90501e5026886", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1744536153, - "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "code-theme": "code-theme", - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" - } - }, - "rust-overlay": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1767754000, - "narHash": "sha256-znoNJs2QZFl+wCFLd6FbUJ00c74kvzOjyQYXc45uFvo=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "0b3a5ad260479f2c9bdadf3ba5b2a4be359cfcdd", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix index 228d350..f9e8b4d 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Blog website"; + description = "Wiki maker"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; @@ -12,8 +12,16 @@ }; }; - outputs = { nixpkgs, flake-utils, rust-overlay, code-theme, ... }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + nixpkgs, + flake-utils, + rust-overlay, + code-theme, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: let overlays = [ rust-overlay.overlays.default ]; pkgs = import nixpkgs { @@ -24,7 +32,7 @@ in { packages.default = pkgs.rustPlatform.buildRustPackage { - pname = "blog"; + pname = "wiki-maker"; version = "0.1.0"; src = ./.; @@ -60,5 +68,6 @@ OPENSSL_DIR = openssl.dev; PKG_CONFIG_PATH = "${openssl.dev}/lib/pkgconfig"; }; - }); + } + ); } diff --git a/src/main.rs b/src/main.rs index 8432836..b2940d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use ax_models::Page; +use ax_models::{Page, WikiConfig}; use axum::{ Router, extract::{Path, State}, @@ -13,7 +13,6 @@ use std::sync::Arc; use std::{io::Cursor, path::PathBuf}; use syntect::{highlighting::ThemeSet, parsing::SyntaxSet}; use tera::{Context, Tera}; -use tokio::io::{AsyncBufReadExt, BufReader}; mod codeblocks; use codeblocks::*; @@ -48,7 +47,7 @@ lazy_static! { } #[derive(Parser)] -#[command(author, version, about = "A simple markdown book server/builder")] +#[command(author, version, about = "A simple wiki server/builder")] struct Cli { #[command(subcommand)] command: Commands, @@ -56,33 +55,21 @@ struct Cli { #[derive(Subcommand)] enum Commands { - /// Serve the markdown files dynamically Serve { - /// Path to the directory containing markdown files + #[arg(short, long)] path: PathBuf, - - /// Whether the home page and navbar should be removed #[arg(short, long)] no_navigation: bool, - - /// Port to listen on - #[arg(short, long, default_value = "3456")] + #[arg(short = 'P', long, default_value = "8090")] port: u16, - - /// Whether to serve on 0.0.0.0 (local network) #[arg(short = 'H', long)] host: bool, }, - /// Build static HTML files from the markdown directory Build { - /// Path to the directory containing markdown files + #[arg(short, long)] path: PathBuf, - - /// Whether the home page and navbar should be removed #[arg(short, long)] no_navigation: bool, - - /// Output directory (defaults to the input directory) #[arg(short, long)] out_dir: Option, }, @@ -118,6 +105,11 @@ async fn main() -> anyhow::Result<()> { .route("/", get(render_summary_handler)) .route("/{page}", get(render_page_handler)) .route("/style.css", get(serve_css)) + // Serve images relative to the docs directory + .nest_service( + "/assets", + tower_http::services::ServeDir::new(&shared_state.docs_dir), + ) .with_state(shared_state); let addr = if host { @@ -137,7 +129,6 @@ async fn main() -> anyhow::Result<()> { let abs_path = std::fs::canonicalize(&path)?; let output_path = out_dir.unwrap_or_else(|| abs_path.clone()); tokio::fs::create_dir_all(&output_path).await?; - run_build(abs_path, output_path, no_navigation).await?; } } @@ -149,48 +140,65 @@ async fn get_summary_data(docs_dir: &PathBuf) -> Vec { if let Ok(mut entries) = tokio::fs::read_dir(docs_dir).await { while let Ok(Some(entry)) = entries.next_entry().await { let path = entry.path(); - if path.extension().and_then(|s| s.to_str()) != Some("md") { + // We now look for TOML files as the entry points + if path.extension().and_then(|s| s.to_str()) != Some("toml") { continue; } let filename = entry.file_name(); let filename_str = filename.to_str().unwrap_or(""); - let title = if let Ok(file) = tokio::fs::File::open(&path).await { - let mut reader = BufReader::new(file); - let mut line = String::new(); - match reader.read_line(&mut line).await { - Ok(_) => line.trim_start_matches('#').trim().to_string(), - Err(_) => filename_str.to_string(), + // Read TOML to get the title + let title = if let Ok(content) = tokio::fs::read_to_string(&path).await { + if let Ok(config) = toml::from_str::(&content) { + config.title + } else { + filename_str.to_string() } } else { filename_str.to_string() }; - let datetime = filename_str - .split_once('@') - .and_then(|(_, ts_with_ext)| ts_with_ext.split('.').next()) - .map(|dt| dt.to_string()) - .unwrap_or_else(|| "Invalid Date".to_string()); + // TODO: + let datetime = "".to_string(); pages.push(Page { - filename: filename_str.to_string(), + filename: filename_str.to_string(), // Keep .toml extension here for now title, datetime, }); } } - pages.sort_by(|a, b| b.datetime.cmp(&a.datetime)); + pages.sort_by(|a, b| a.title.cmp(&b.title)); pages } -async fn render_markdown_to_html( - content: &str, +async fn render_wiki_page( filename: &str, docs_dir: &PathBuf, no_navigation: bool, is_static: bool, -) -> String { +) -> Result { + let toml_path = docs_dir.join(filename); + let toml_content = tokio::fs::read_to_string(&toml_path) + .await + .map_err(|_| "Page configuration not found".to_string())?; + + let config: WikiConfig = + toml::from_str(&toml_content).map_err(|e| format!("Invalid TOML configuration: {}", e))?; + + let markdown_content = if let Some(md_file) = &config.content_file { + let md_path = docs_dir.join(md_file); + tokio::fs::read_to_string(&md_path) + .await + .unwrap_or_else(|_| { + "# Content missing\nThe linked markdown file could not be found.".to_string() + }) + } else { + String::new() + }; + + // Render Markdown let mut options = Options::empty(); options.insert( Options::ENABLE_TABLES @@ -199,7 +207,7 @@ async fn render_markdown_to_html( | Options::ENABLE_TASKLISTS, ); - let parser = MarkdownParser::new_ext(content, options); + let parser = MarkdownParser::new_ext(&markdown_content, options); let renderer = CodeblockRenderer::new(parser); let mut html_output = String::new(); html::push_html(&mut html_output, renderer); @@ -210,21 +218,30 @@ async fn render_markdown_to_html( get_nav_links(docs_dir, filename) }; - // If building statically, rewrite .md links to .html if is_static { prev = prev.map(|s| { if s == "." { "index.html".to_string() } else { - s.replace(".md", ".html") + s.replace(".toml", ".html") } }); - next = next.map(|s| s.replace(".md", ".html")); + next = next.map(|s| s.replace(".toml", ".html")); } + let infobox_list: Vec = match config.infobox { + Some(map) => map + .into_iter() + .map(|(k, v)| InfoboxItem { key: k, value: v }) + .collect(), + None => Vec::new(), + }; + let mut context = Context::new(); - context.insert("title", filename); + context.insert("title", &config.title); context.insert("content", &html_output); + context.insert("infobox", &infobox_list); // Pass the ordered list, not the map + context.insert("main_image", &config.image); context.insert("prev_page", &prev); context.insert("next_page", &next); context.insert("no_navigation", &no_navigation); @@ -232,7 +249,7 @@ async fn render_markdown_to_html( TEMPLATES .render("page.html", &context) - .unwrap_or_else(|e| format!("Error: {}", e)) + .map_err(|e| format!("Template Error: {}", e)) } async fn run_build(docs_dir: PathBuf, out_dir: PathBuf, no_navigation: bool) -> anyhow::Result<()> { @@ -241,17 +258,16 @@ async fn run_build(docs_dir: PathBuf, out_dir: PathBuf, no_navigation: bool) -> // Build summary if !no_navigation { let pages = get_summary_data(&docs_dir).await; - // Rewrite filenames for static links in home page let static_pages: Vec = pages .into_iter() .map(|mut p| { - p.filename = p.filename.replace(".md", ".html"); + p.filename = p.filename.replace(".toml", ".html"); p }) .collect(); let mut context = Context::new(); - context.insert("title", "Pages"); + context.insert("title", "Wiki Index"); context.insert("files", &static_pages); context.insert("is_static", &true); @@ -263,19 +279,35 @@ async fn run_build(docs_dir: PathBuf, out_dir: PathBuf, no_navigation: bool) -> let css = TEMPLATES.render("style.css", &Context::new())?; tokio::fs::write(out_dir.join("style.css"), css).await?; + // Copy assets (images, etc) + // NOTE: In a real app you'd recursively copy everything not .md/.toml + // For now we just copy files that look like images if they are in root + let mut entries = tokio::fs::read_dir(&docs_dir).await?; + while let Some(entry) = entries.next_entry().await? { + let path = entry.path(); + if let Some(ext) = path.extension().and_then(|s| s.to_str()) { + if ["png", "jpg", "jpeg", "gif", "webp"].contains(&ext) { + let dest = out_dir.join(path.file_name().unwrap()); + tokio::fs::copy(path, dest).await?; + } + } + } + // Build pages let mut entries = tokio::fs::read_dir(&docs_dir).await?; while let Some(entry) = entries.next_entry().await? { let path = entry.path(); - if path.extension().and_then(|s| s.to_str()) == Some("md") { + if path.extension().and_then(|s| s.to_str()) == Some("toml") { let filename = entry.file_name().to_str().unwrap().to_string(); - let content = tokio::fs::read_to_string(&path).await?; - let rendered = - render_markdown_to_html(&content, &filename, &docs_dir, no_navigation, true).await; - let out_file = out_dir.join(filename.replace(".md", ".html")); - tokio::fs::write(out_file, rendered).await?; - tracing::info!("Generated {}", filename); + match render_wiki_page(&filename, &docs_dir, no_navigation, true).await { + Ok(rendered) => { + let out_file = out_dir.join(filename.replace(".toml", ".html")); + tokio::fs::write(out_file, rendered).await?; + tracing::info!("Generated {}", filename); + } + Err(e) => tracing::error!("Failed to generate {}: {}", filename, e), + } } } @@ -289,7 +321,7 @@ async fn render_summary_handler(State(state): State>) -> impl Into } let pages = get_summary_data(&state.docs_dir).await; let mut context = Context::new(); - context.insert("title", "Pages"); + context.insert("title", "Wiki Index"); context.insert("files", &pages); context.insert("is_static", &false); @@ -303,25 +335,15 @@ async fn render_page_handler( State(state): State>, Path(page): Path, ) -> impl IntoResponse { - let filename = if page.ends_with(".md") { + let filename = if page.ends_with(".toml") { page } else { - format!("{}.md", page) + format!("{}.toml", page) }; - let file_path = state.docs_dir.join(&filename); - match tokio::fs::read_to_string(&file_path).await { - Ok(content) => Html( - render_markdown_to_html( - &content, - &filename, - &state.docs_dir, - state.no_navigation, - false, - ) - .await, - ), - Err(_) => Html("

404

Page not found

".to_string()), + match render_wiki_page(&filename, &state.docs_dir, state.no_navigation, false).await { + Ok(html) => Html(html).into_response(), + Err(e) => (StatusCode::NOT_FOUND, format!("

404

{}

", e)).into_response(), } } @@ -335,15 +357,32 @@ async fn serve_css() -> impl IntoResponse { } } -// Helper model for Tera mod ax_models { - use serde::{Deserialize, Serialize}; + use indexmap::IndexMap; + use serde::{Deserialize, Serialize}; // Use IndexMap instead of BTreeMap + #[derive(Deserialize, Serialize, Clone)] pub struct Page { pub filename: String, pub title: String, pub datetime: String, } + + #[derive(Deserialize, Serialize, Clone)] + pub struct WikiConfig { + pub title: String, + pub image: Option, + // IndexMap preserves the order from the file + pub infobox: Option>, + pub content_file: Option, + } +} + +// Helper struct for the template +#[derive(serde::Serialize)] +struct InfoboxItem { + key: String, + value: String, } fn get_nav_links(dir: &PathBuf, current_file: &str) -> (Option, Option) { @@ -351,7 +390,7 @@ fn get_nav_links(dir: &PathBuf, current_file: &str) -> (Option, Option - {{ content | safe }} - +
+

{{ title }}

+
- +}); + {% endblock content %} diff --git a/templates/style.css b/templates/style.css index 3c936ac..6939a3f 100644 --- a/templates/style.css +++ b/templates/style.css @@ -9,285 +9,165 @@ --accent: #8aadf4; --accent-glow: #c6a0f6; - + --code-bg: var(--container-bg); --border-color: #494d64; --selection-bg: rgba(91, 96, 120, 0.4); --radius-sm: 6px; --radius-md: 12px; - --radius-lg: 20px; - --blur-amount: 12px; - --container-width: 850px; + --container-width: 1000px; /* Wider for wiki layout */ } -* { - box-sizing: border-box; -} +* { box-sizing: border-box; } body { background-color: var(--bg-color); color: var(--text-main); - font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - line-height: 1.7; + font-family: 'Inter', system-ui, sans-serif; + line-height: 1.6; margin: 0; - padding: 40px 20px; + padding-top: 80px; display: flex; justify-content: center; min-height: 100vh; - font-size: 14px; } #content { width: 100%; max-width: var(--container-width); - min-width: 0; + padding: 0 20px; } -::selection { - background: var(--selection-bg); - color: #fff; +/* --- Wiki Layout --- */ + +.wiki-header { + border-bottom: 2px solid; + border-image-source: linear-gradient(to right, var(--accent), transparent); + border-image-slice: 1; + margin-bottom: 2rem; } -h1, h2, h3, h4, h5, h6 { - color: #fff; - margin-top: 2rem; - margin-bottom: 1rem; - font-weight: 700; - line-height: 1.25; +.wiki-header h1 { + margin: 0; + padding-bottom: 0.5rem; + font-size: 2.5rem; + color: #fff; } -h1 { - font-size: 2.5rem; - padding-bottom: 0.8rem; - margin-bottom: 2.5rem; - border-bottom: 2px solid; - border-image-source: linear-gradient(to right, var(--accent), transparent); - border-image-slice: 1; -} -h2 { - font-size: 1.8rem; - color: var(--accent); -} -h3 { - font-size: 1.5rem; +.wiki-container { + display: flex; + gap: 40px; + align-items: flex-start; } -a { - color: var(--accent); - text-decoration: none; - transition: color 0.2s ease, text-shadow 0.2s ease; +.wiki-body { + flex: 1; + min-width: 0; /* Prevents overflow in flex items */ } -a:hover { - color: var(--accent-glow); - text-shadow: 0 0 8px var(--accent-glow); +.wiki-sidebar { + width: 300px; + background: var(--container-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + padding: 15px; + flex-shrink: 0; + position: sticky; + top: 90px; } -p { margin-bottom: 1.2rem; } - -ul, ol { - padding-left: 1.5rem; - margin-bottom: 1.2rem; +@media (max-width: 800px) { + .wiki-container { + flex-direction: column-reverse; + } + .wiki-sidebar { + width: 100%; + position: static; + } } -li { margin-bottom: 0.5rem; } +/* --- Sidebar Components --- */ +.sidebar-image img { + width: 100%; + border-radius: var(--radius-sm); + border: 2px solid var(--border-color); + margin-bottom: 15px; +} + +.infobox-data h3 { + margin-top: 0; + background: var(--lighter-bg); + padding: 8px; + text-align: center; + border-radius: var(--radius-sm); + font-size: 1.1rem; + color: var(--accent); +} + +.infobox-data table { + width: 100%; + margin: 0; + border-collapse: collapse; + font-size: 0.9rem; +} + +.infobox-data td { + padding: 8px; + border-bottom: 1px solid var(--border-color); +} + +.infobox-data tr:last-child td { + border-bottom: none; +} + +.info-label { + font-weight: bold; + color: var(--text-muted); +} + +.info-value { + text-align: right; +} + +/* --- Standard Markdown Elements --- */ +h2 { font-size: 1.8rem; color: var(--accent); margin-top: 2rem; } +h3 { font-size: 1.5rem; color: #fff; } +p { margin-bottom: 1rem; } +a { color: var(--accent); text-decoration: none; } +a:hover { color: var(--accent-glow); text-decoration: underline; } blockquote { - margin: 2rem 0; - padding: 0.1rem 1.5rem; - border-left: 4px solid var(--accent); - background: var(--container-bg); - border-radius: var(--radius-sm); - color: var(--text-muted); - font-style: italic; + border-left: 4px solid var(--accent); + padding-left: 1rem; + margin: 1.5rem 0; + font-style: italic; + color: var(--text-muted); } +/* Code blocks */ pre { - position: relative; - background: var(--code-bg); - background-color: var(--code-bg) !important; - padding: 1.2rem; - border-radius: var(--radius-md); - overflow-x: auto; - border: 2px solid var(--border-color); - /* margin: 1.5rem 0; */ + background: var(--container-bg); + padding: 1rem; + border-radius: var(--radius-md); + overflow-x: auto; + border: 1px solid var(--border-color); } - code { - font-size: 0.9em; - background: rgba(255, 255, 255, 0.1); - padding: 0.2rem 0.4rem; - border-radius: var(--radius-sm); - font-style: normal !important; -} - -pre code { - display: block; - background: none !important; - padding: 0; - padding-right: 40px; -} - -pre, -code, -pre span, -code span, -pre [style], -code [style] { - font-family: 'JetBrains Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace !important; - font-style: normal !important; - font-variant-ligatures: contextual; -} - -table { - width: 100%; - border-collapse: collapse; - margin: 2rem 0; -} - -th { - background: var(--lighter-bg); - color: var(--accent); - text-align: left; -} - -th, td { - padding: 12px; - border: 2px solid var(--border-color); -} - -tr:nth-child(even) { - background: rgba(255, 255, 255, 0.025); -} - -hr { - border: none; - height: 2px; - background: linear-gradient(to right, transparent, var(--border-color), transparent); - margin: 3rem 0; -} - -img { - max-width: 100%; - border-radius: var(--radius-md); - margin: 1.5rem 0; - border: 2px solid var(--border-color); -} - -input[type="checkbox"] { - appearance: none; - -webkit-appearance: none; - background-color: transparent; - margin: 0; - margin-right: 0.5rem; - - font: inherit; - color: var(--accent); - width: 1.25em; - height: 1.25em; - border: 2px solid var(--text-muted); - border-radius: var(--radius-sm); - transform: translateY(-0.075em); - - display: inline-grid; - place-content: center; - transition: border-color 0.2s ease, background-color 0.2s ease; -} - -input[type="checkbox"]::before { - content: ""; - width: 0.65em; - height: 0.65em; - transform: scale(0); - transition: 120ms transform ease-in-out; - box-shadow: inset 1em 1em var(--accent); - - clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); -} - -input[type="checkbox"]:checked { - border-color: var(--accent); -} - -input[type="checkbox"]:checked::before { - transform: scale(1); -} - -body { - padding-top: 75px; + font-family: 'JetBrains Mono', monospace; + font-size: 0.9em; } +/* Navigation Bar */ nav { - position: fixed; - top: 0; - left: 0; - width: 100%; - z-index: 1000; - background: var(--container-bg); - /* backdrop-filter: blur(var(--blur-amount)); */ - /* -webkit-backdrop-filter: blur(var(--blur-amount)); */ - border-bottom: 2px solid var(--border-color); - padding: 1rem 2rem; - display: flex; - justify-content: space-between; - align-items: center; -} - -nav a { - color: var(--text-main); - text-decoration: none; - font-size: 1.2rem; - font-weight: 600; - margin-left: 20px; - transition: color 0.2s ease; -} - -.btn { - display: inline-block; - color: #fff; - padding: 0.6rem 1.2rem; - border: solid 1px var(--accent); - border-radius: var(--radius-md); - font-weight: 600; - cursor: pointer; - text-decoration: none; - transition: background 0.2s ease; -} - -.btn.disabled { - color: var(--text-muted); - cursor: not-allowed; - border-color: var(--text-muted); -} - -.code-wrapper { - position: relative; - margin: 1.5rem 0; -} - -.copy-button { - position: absolute; - top: 10px; - right: 10px; - padding: 10px 10px; - background: var(--container-bg); - border: 1px solid var(--border-color); - border-radius: var(--radius-sm); - color: var(--text-muted); - cursor: pointer; - font-size: 0.9rem; - transition: all 0.2s ease; - display: flex; - align-items: center; - justify-content: center; - z-index: 10; -} - -.copy-button:hover { - color: var(--accent); -} - -.copy-button:active { - transform: translateY(2px); + position: fixed; + top: 0; left: 0; right: 0; + height: 60px; + background: var(--container-bg); + border-bottom: 1px solid var(--border-color); + display: flex; + align-items: center; + padding: 0 2rem; + z-index: 100; } +nav a { font-weight: bold; font-size: 1.2rem; color: var(--text-main); }