From f56f8c6818a7965b4421d617a31195198ce5b206 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Tue, 7 Mar 2023 15:44:30 +0100 Subject: [PATCH] feat: with biteme cli --- Cargo.lock | 498 ++++++++++++++++++++++++++++++++++++- Cargo.toml | 21 +- Makefile.toml | 8 + crates/biteme/Cargo.toml | 23 ++ crates/biteme/src/main.rs | 95 +++++++ crates/domain/src/lib.rs | 4 + crates/services/Cargo.toml | 1 + crates/services/src/lib.rs | 69 +++-- src/api/events.rs | 124 +++------ src/components/day.rs | 10 +- style/output.css | 40 +++ 11 files changed, 773 insertions(+), 120 deletions(-) create mode 100644 crates/biteme/Cargo.toml create mode 100644 crates/biteme/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 2183192..336bf43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.7.6" @@ -53,6 +68,12 @@ dependencies = [ "syn", ] +[[package]] +name = "async_once" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82" + [[package]] name = "atty" version = "0.2.14" @@ -133,6 +154,21 @@ dependencies = [ "syn", ] +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -145,6 +181,25 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +[[package]] +name = "biteme" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "color-eyre", + "domain", + "eyre", + "inquire", + "regex", + "serde", + "serde_yaml", + "tokio", + "tracing", + "tracing-subscriber", + "uuid", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -188,6 +243,44 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "cached" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5877db5d1af7fae60d06b5db9430b68056a69b3582a0be8e3691e87654aeb6" +dependencies = [ + "async-trait", + "async_once", + "cached_proc_macro", + "cached_proc_macro_types", + "futures 0.3.26", + "hashbrown 0.13.2", + "instant", + "lazy_static", + "once_cell", + "thiserror", + "tokio", +] + +[[package]] +name = "cached_proc_macro" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10ca87c81aaa3a949dbbe2b5e6c2c45dbc94ba4897e45ea31ff9ec5087be3dc" +dependencies = [ + "cached_proc_macro_types", + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" + [[package]] name = "cc" version = "1.0.79" @@ -243,6 +336,28 @@ dependencies = [ "half", ] +[[package]] +name = "clap" +version = "4.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +dependencies = [ + "bitflags", + "clap_lex", + "is-terminal", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_lex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -253,6 +368,33 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colored" version = "2.0.0" @@ -333,6 +475,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -387,6 +554,41 @@ dependencies = [ "syn", ] +[[package]] +name = "darling" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.10.6" @@ -418,6 +620,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + [[package]] name = "educe" version = "0.4.20" @@ -450,6 +658,27 @@ dependencies = [ "syn", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "eyre" version = "0.6.8" @@ -460,6 +689,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fnv" version = "1.0.7" @@ -614,6 +852,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + [[package]] name = "gloo-net" version = "0.2.6" @@ -662,6 +906,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "heck" version = "0.4.1" @@ -686,6 +936,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "html-escape" version = "0.2.13" @@ -782,6 +1038,12 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.3.0" @@ -805,7 +1067,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "inquire" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd079157ad94a32f7511b2e13037f3ae417ad80a6a9b0de29154d48b86f5d6c8" +dependencies = [ + "bitflags", + "chrono", + "crossterm", + "dyn-clone", + "lazy_static", + "newline-converter", + "tempfile", + "thiserror", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +dependencies = [ + "libc", + "windows-sys 0.45.0", ] [[package]] @@ -817,6 +1116,18 @@ dependencies = [ "libc", ] +[[package]] +name = "is-terminal" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1081,6 +1392,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -1134,6 +1451,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.6" @@ -1146,6 +1472,15 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "newline-converter" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "nom" version = "7.1.3" @@ -1156,6 +1491,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -1205,6 +1550,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -1218,9 +1572,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.12.3", ] +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "pad-adapter" version = "0.1.1" @@ -1443,6 +1815,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1458,6 +1836,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.36.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + [[package]] name = "rustversion" version = "1.0.11" @@ -1568,6 +1960,7 @@ dependencies = [ name = "services" version = "0.1.0" dependencies = [ + "cached", "chrono", "domain", "eyre", @@ -1589,6 +1982,36 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1673,6 +2096,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.109" @@ -1702,6 +2131,19 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "tempfile" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.42.0", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -1731,6 +2173,16 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.1.45" @@ -1923,6 +2375,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -2030,6 +2518,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 9e8a509..84837ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,14 @@ [workspace] -members = [".", "crates/services", "crates/domain"] +members = [".", "crates/services", "crates/domain", "crates/biteme"] +[workspace.dependencies] +domain = { path = "crates/domain" } +services = { path = "crates/services" } +biteme = { path = "crates/biteme" } + +uuid = { version = "1.3.0", features = ["v4", "serde"] } +chrono = { version = "0.4.23", features = ["serde"] } +serde = { version = "1", features = ["derive"] } [package] name = "ssr_modes_axum" @@ -20,7 +28,6 @@ leptos_meta = { version = "*", default-features = false } leptos_axum = { version = "*", default-features = false, optional = true } leptos_router = { version = "*", default-features = false } log = "0.4" -serde = { version = "1", features = ["derive"] } simple_logger = "4" thiserror = "1" axum = { version = "0.6.1", optional = true } @@ -28,11 +35,13 @@ tower = { version = "0.4.13", optional = true } tower-http = { version = "0.3.4", features = ["fs"], optional = true } tokio = { version = "1", features = ["time"], optional = true } wasm-bindgen = "0.2" -chrono = { version = "0.4.23", features = ["serde"] } -uuid = { version = "1.3.0", features = ["v4", "wasm-bindgen", "js", "serde"] } -domain = { path = "crates/domain" } -services = { path = "crates/services", optional = true } +serde = { workspace = true } +chrono = { workspace = true } +uuid = { workspace = true, features = ["v4", "wasm-bindgen", "js", "serde"] } + +domain = { workspace = true } +services = { workspace = true, optional = true } [features] hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"] diff --git a/Makefile.toml b/Makefile.toml index 6122747..5b9e15f 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -18,7 +18,15 @@ args = [ "./style/output.css", "--watch", ] +workspace = false [tasks.build_tailwind] command = "npx" args = ["tailwindcss", "-i", "./input.css", "-o", "./style/output.css"] +workspace = false + +[tasks.install_biteme] +command = "cargo" +args = ["install", "--path", "crates/biteme"] +workspace = false +install_crate = "cargo-all-features" diff --git a/crates/biteme/Cargo.toml b/crates/biteme/Cargo.toml new file mode 100644 index 0000000..2a30d46 --- /dev/null +++ b/crates/biteme/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "biteme" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +domain = { workspace = true } + +serde = { workspace = true } +uuid = { workspace = true } +chrono = { workspace = true } + +clap = "4.1.8" +color-eyre = "0.6.2" +eyre = "0.6.8" +inquire = { version = "0.6.0", features = ["editor", "chrono", "date"] } +tokio = { version = "1.26.0", features = ["full"] } +tracing = { version = "0.1.37", features = ["log"] } +serde_yaml = "0.9.19" +tracing-subscriber = "0.3.16" +regex = "1.7.1" diff --git a/crates/biteme/src/main.rs b/crates/biteme/src/main.rs new file mode 100644 index 0000000..ff6c377 --- /dev/null +++ b/crates/biteme/src/main.rs @@ -0,0 +1,95 @@ +use domain::{Event, Image}; +use inquire::validator::ValueRequiredValidator; +use regex::Regex; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + tracing_subscriber::fmt::init(); + + color_eyre::install()?; + + let cli = clap::Command::new("biteme") + .subcommand(clap::Command::new("generate").subcommand(clap::Command::new("article"))); + + let args = std::env::args(); + + let matches = cli.get_matches_from(args); + match matches.subcommand() { + Some(("generate", subm)) => match subm.subcommand() { + Some(("article", _subm)) => { + generate_article().await?; + } + _ => panic!("command not valid"), + }, + _ => panic!("command not valid"), + } + + Ok(()) +} + +async fn generate_article() -> eyre::Result<()> { + let name = inquire::Text::new("What are you going to eat?") + .with_validator(ValueRequiredValidator::default()) + .prompt()?; + let description = inquire::Editor::new("Do you want to provide a description?") + .prompt_skippable()? + .and_then(|ci| if ci == "" { None } else { Some(ci) }); + let time = inquire::DateSelect::new("When is the event?") + .with_min_date(chrono::Local::now().date_naive()) + .prompt()?; + let cover_image = inquire::Text::new("Do you have a picture for it?") + .prompt_skippable()? + .and_then(|ci| if ci == "" { None } else { Some(ci) }); + let cover_alt = if let Some(_) = cover_image { + Some( + inquire::Text::new("Do you have a description for the image?") + .with_validator(ValueRequiredValidator::default()) + .prompt()?, + ) + } else { + None + }; + + let prepared_name = name.replace(" ", "-"); + let prepared_name = prepared_name.replace("--", "-"); + let prepared_name = prepared_name.trim_matches('-'); + + let re = Regex::new(r"[a-zA-Z-_0-9]*")?; + let name_slug = re + .find_iter(&prepared_name) + .map(|n| n.as_str()) + .collect::>(); + let name_slug = name_slug.join(""); + + let slug = format!("{}-{}", time.format("%Y-%m-%d"), name_slug.to_lowercase()); + + let event = Event { + id: uuid::Uuid::new_v4(), + cover_image: cover_image.zip(cover_alt).map(|(image, alt)| Image { + id: uuid::Uuid::new_v4(), + url: image, + alt, + metadata: None, + }), + name, + description: description.clone(), + time, + recipe_id: None, + images: Vec::new(), + metadata: None, + }; + + let contents = serde_yaml::to_string(&event)?; + let contents = format!( + "--- +{}--- + +{}", + contents, + description.unwrap_or("".into()) + ); + + tokio::fs::write(format!("articles/events/{}.md", slug), contents).await?; + + Ok(()) +} diff --git a/crates/domain/src/lib.rs b/crates/domain/src/lib.rs index 3765010..f0ff1f7 100644 --- a/crates/domain/src/lib.rs +++ b/crates/domain/src/lib.rs @@ -6,12 +6,14 @@ use serde::{Deserialize, Serialize}; pub struct Metadata(HashMap); #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct Recipe { pub id: uuid::Uuid, pub metadata: Option, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct Image { pub id: uuid::Uuid, pub url: String, @@ -20,6 +22,7 @@ pub struct Image { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct Event { pub id: uuid::Uuid, pub cover_image: Option, @@ -32,6 +35,7 @@ pub struct Event { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct EventOverview { pub id: uuid::Uuid, pub cover_image: Option, diff --git a/crates/services/Cargo.toml b/crates/services/Cargo.toml index c465fae..58b5848 100644 --- a/crates/services/Cargo.toml +++ b/crates/services/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cached = "0.42.0" chrono = { version = "0.4.23", features = ["serde"] } domain = { path = "../domain" } eyre = "0.6.8" diff --git a/crates/services/src/lib.rs b/crates/services/src/lib.rs index 96040f8..3246ae2 100644 --- a/crates/services/src/lib.rs +++ b/crates/services/src/lib.rs @@ -1,10 +1,13 @@ use std::path::PathBuf; +use std::sync::Arc; +use cached::proc_macro::{cached, once}; use domain::{Event, Image, Metadata}; use serde::{Deserialize, Serialize}; pub struct EventStore { pub path: PathBuf, + events: Arc>>, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -16,6 +19,7 @@ pub struct RawImage { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RawEvent { + #[serde(alias = "coverImage")] pub cover_image: Option, pub name: String, pub description: Option, @@ -29,7 +33,7 @@ pub struct RawEvent { } mod short_time_stamp { - use chrono::{DateTime, NaiveDate, TimeZone, Utc}; + use chrono::NaiveDate; use serde::{self, Deserialize, Deserializer, Serializer}; const FORMAT: &'static str = "%Y-%m-%d"; @@ -79,42 +83,65 @@ impl From for Image { impl EventStore { pub fn new(path: PathBuf) -> Self { - Self { path } + Self { + path, + events: Default::default(), + } } pub async fn get_upcoming_events(&self) -> eyre::Result> { let mut event_path = self.path.clone(); event_path.push("events"); - let mut dir = tokio::fs::read_dir(event_path).await?; - let mut events = vec![]; + let events = fetch_events(event_path).await?; - while let Ok(Some(entry)) = dir.next_entry().await { - let metadata = entry.metadata().await?; - if metadata.is_file() { - let file = tokio::fs::read(entry.path()).await?; - let content = std::str::from_utf8(&file)?; - if content.starts_with("---\n") { - let after_marker = &content[4..]; - if let Some(marker_end) = after_marker.find("---\n") { - let raw_front_matter = &content[4..marker_end + 4]; - let mut raw_event: RawEvent = serde_yaml::from_str(raw_front_matter)?; - raw_event.content = content[marker_end + 4..].to_string(); - - events.push(raw_event.into()) - } - } - } - } + let mut e = self.events.write().await; + *e = events.clone(); Ok(events) } + + pub async fn get_event(&self, event_id: uuid::Uuid) -> eyre::Result> { + let events = self.events.read().await; + + let event = events.iter().find(|e| e.id == event_id); + + Ok(event.map(|e| e.clone())) + } +} + +#[once(time = 60, result = true, sync_writes = true)] +pub async fn fetch_events(event_path: PathBuf) -> eyre::Result> { + let mut dir = tokio::fs::read_dir(event_path).await?; + + let mut events = vec![]; + + while let Ok(Some(entry)) = dir.next_entry().await { + let metadata = entry.metadata().await?; + if metadata.is_file() { + let file = tokio::fs::read(entry.path()).await?; + let content = std::str::from_utf8(&file)?; + if content.starts_with("---\n") { + let after_marker = &content[4..]; + if let Some(marker_end) = after_marker.find("---\n") { + let raw_front_matter = &content[4..marker_end + 4]; + let mut raw_event: RawEvent = serde_yaml::from_str(raw_front_matter)?; + raw_event.content = content[marker_end + 4..].to_string(); + + events.push(raw_event.into()) + } + } + } + } + + Ok(events) } impl Default for EventStore { fn default() -> Self { Self { path: PathBuf::from("articles"), + events: Default::default(), } } } diff --git a/src/api/events.rs b/src/api/events.rs index fdf6d5f..1365458 100644 --- a/src/api/events.rs +++ b/src/api/events.rs @@ -1,66 +1,42 @@ -use lazy_static::lazy_static; +use cfg_if::cfg_if; use leptos::*; use serde::{Deserialize, Serialize}; -use domain::{Event, EventOverview, Image}; +use domain::{Event, EventOverview}; -lazy_static! { - static ref EVENTS: Vec = vec![ - Event { - cover_image: Some(Image { - id: uuid::Uuid::new_v4(), - url: "https://images.unsplash.com/photo-1513104890138-7c749659a591?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=400&q=80".into(), - alt: "some-alt".into(), - metadata: None, - }), - id: uuid::Uuid::new_v4(), - name: "Pizza".into(), - description: Some("Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.".into()), - time: chrono::Utc::now() - .checked_add_days(chrono::Days::new(1)) - .unwrap() - .date_naive(), - recipe_id: None, - images: vec![], - metadata: None, - }, - Event { - cover_image: Some(Image { - id: uuid::Uuid::new_v4(), - url: "https://images.unsplash.com/photo-1513104890138-7c749659a591?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=400&q=80".into(), - alt: "some-alt".into(), - metadata: None, - }), - id: uuid::Uuid::new_v4(), - name: "Kød boller".into(), - description: Some("Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa duis.".into()), - time: chrono::Utc::now() - .checked_add_days(chrono::Days::new(4)) - .unwrap() - .date_naive(), - recipe_id: None, - images: vec![], - metadata: None, - }, - Event { - cover_image: Some(Image { - id: uuid::Uuid::new_v4(), - url: "https://images.unsplash.com/photo-1513104890138-7c749659a591?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=400&q=80".into(), - alt: "some-alt".into(), - metadata: None, - }), - id: uuid::Uuid::new_v4(), - name: "Pizza".into(), - description: Some("description".into()), - time: chrono::Utc::now() - .checked_sub_days(chrono::Days::new(2)) - .unwrap() - .date_naive(), - recipe_id: None, - images: vec![], - metadata: None, - }, - ]; +cfg_if! { + if #[cfg(feature = "ssr")] { + use services::EventStore; + use lazy_static::lazy_static; + + lazy_static! { + static ref EVENTSTORE: EventStore = EventStore::default(); + } + async fn get_upcoming_events_fn() -> Result { + let current_time = chrono::Utc::now(); + + let mut events: Vec = EVENTSTORE + .get_upcoming_events() + .await + .map_err(|e| ServerFnError::ServerError(e.to_string()))? + .iter() + .filter(|d| d.time.gt(&chrono::Utc::now().date_naive())) + .map(|data| data.clone().into()) + .collect(); + + events.sort_by(|a, b| a.time.cmp(&b.time)); + + Ok(UpcomingEventsOverview { events }) + } + async fn get_full_event_fn(event_id: uuid::Uuid) -> Result, ServerFnError> { + let event = EVENTSTORE + .get_event(event_id) + .await + .map_err(|e| ServerFnError::ServerError(e.to_string()))?; + + Ok(event) + } + } } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -70,40 +46,10 @@ pub struct UpcomingEventsOverview { #[server(GetUpcomingEvents, "/api")] pub async fn get_upcoming_events() -> Result { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; get_upcoming_events_fn().await } -#[cfg(feature = "ssr")] -async fn get_upcoming_events_fn() -> Result { - let current_time = chrono::Utc::now(); - - let es = services::EventStore::default(); - - let events = es - .get_upcoming_events() - .await - .map_err(|e| ServerFnError::ServerError(e.to_string()))? - .iter() - .map(|data| data.clone().into()) - .collect(); - - Ok(UpcomingEventsOverview { events }) -} - #[server(GetFullEvent, "/api")] pub async fn get_full_event(event_id: uuid::Uuid) -> Result, ServerFnError> { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - get_full_event_fn(event_id).await } - -#[cfg(feature = "ssr")] -async fn get_full_event_fn(event_id: uuid::Uuid) -> Result, ServerFnError> { - let event = EVENTS - .iter() - .find(|data| data.id == event_id) - .map(|d| d.clone()); - - Ok(event) -} diff --git a/src/components/day.rs b/src/components/day.rs index 13dfd9e..a51e81e 100644 --- a/src/components/day.rs +++ b/src/components/day.rs @@ -51,6 +51,12 @@ pub fn Day( }.into_view(cx) }} + { + last.filter(|l| !l).map(|_l| view! { + cx, +
@@ -188,8 +194,8 @@ fn DayContentCollapsed( }}
diff --git a/style/output.css b/style/output.css index 0a4fc33..106ecc0 100644 --- a/style/output.css +++ b/style/output.css @@ -655,6 +655,32 @@ video { flex-grow: 1; } +@keyframes bounce { + 0%, 100% { + transform: translateY(-25%); + animation-timing-function: cubic-bezier(0.8,0,1,1); + } + + 50% { + transform: none; + animation-timing-function: cubic-bezier(0,0,0.2,1); + } +} + +.animate-bounce { + animation: bounce 1s infinite; +} + +@keyframes pulse { + 50% { + opacity: .5; + } +} + +.animate-pulse { + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + .list-decimal { list-style-type: decimal; } @@ -743,6 +769,20 @@ video { border-top-right-radius: 1rem; } +.border { + border-width: 1px; +} + +.border-gray-400 { + --tw-border-opacity: 1; + border-color: rgb(156 163 175 / var(--tw-border-opacity)); +} + +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + .bg-gray-200 { --tw-bg-opacity: 1; background-color: rgb(229 231 235 / var(--tw-bg-opacity));