From 15c590a42e5d9f1af8a17a58d8d265aff8f0d2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Tue, 22 Oct 2024 15:18:20 +0200 Subject: [PATCH] Render --- .gitignore | 1 + Cargo.lock | 635 ++++++++++++++- Cargo.toml | 3 +- build.rs | 12 +- src/main.rs | 154 +++- templates/index.html | 156 +--- templates/recipes/create_form.html | 0 templates/recipes/show.html | 0 templates/recipes/update_form.html | 0 templates/styles.css | 1213 ++++++++++++++++++++++++++++ 10 files changed, 2004 insertions(+), 170 deletions(-) delete mode 100644 templates/recipes/create_form.html delete mode 100644 templates/recipes/show.html delete mode 100644 templates/recipes/update_form.html diff --git a/.gitignore b/.gitignore index ea8c4bf..7daeddd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +node_modules diff --git a/Cargo.lock b/Cargo.lock index dccb35f..127e4f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "actix" @@ -376,6 +376,70 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.90" @@ -444,6 +508,125 @@ dependencies = [ "nom", ] +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", + "tokio", +] + +[[package]] +name = "async-io" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +dependencies = [ + "async-attributes", + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -466,6 +649,12 @@ dependencies = [ "syn 2.0.82", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.83" @@ -486,6 +675,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.4.0" @@ -585,6 +780,19 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "brotli" version = "6.0.0" @@ -686,7 +894,10 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ + "android-tzdata", + "iana-time-zone", "num-traits", + "windows-targets 0.52.6", ] [[package]] @@ -699,6 +910,52 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.82", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "colored" version = "2.1.0" @@ -816,6 +1073,7 @@ dependencies = [ "actix-web", "askama", "askama_actix", + "migration", "redis", "rswind", "sea-orm", @@ -844,6 +1102,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.14" @@ -973,6 +1237,40 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.82", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.82", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -1148,6 +1446,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "5.3.1" @@ -1159,6 +1463,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.1.1" @@ -1205,6 +1519,7 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1255,6 +1570,30 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -1276,6 +1615,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1330,6 +1670,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.15" @@ -1338,8 +1684,20 @@ checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -1413,6 +1771,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1484,6 +1848,35 @@ dependencies = [ "libm", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[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.5.0" @@ -1540,6 +1933,12 @@ dependencies = [ "libc", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -1584,6 +1983,15 @@ dependencies = [ "serde", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -1715,6 +2123,18 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] [[package]] name = "matches" @@ -1738,6 +2158,16 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "migration" +version = "0.1.0" +dependencies = [ + "async-std", + "sea-orm-migration", + "tracing", + "tracing-subscriber", +] + [[package]] name = "mime" version = "0.3.17" @@ -1775,7 +2205,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "log", "wasi", @@ -2205,6 +2635,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -2217,6 +2667,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -2244,6 +2705,21 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "polyval" version = "0.6.2" @@ -2416,6 +2892,7 @@ dependencies = [ "async-trait", "bytes", "combine", + "futures", "futures-util", "itoa", "num-bigint", @@ -2427,6 +2904,7 @@ dependencies = [ "sha1_smol", "socket2 0.5.7", "tokio", + "tokio-retry2", "tokio-util", "url", "uuid", @@ -2469,8 +2947,17 @@ checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -2481,7 +2968,7 @@ checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.5", ] [[package]] @@ -2490,6 +2977,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -2882,6 +3375,23 @@ dependencies = [ "uuid", ] +[[package]] +name = "sea-orm-cli" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25" +dependencies = [ + "chrono", + "clap", + "dotenvy", + "glob", + "regex", + "sea-schema", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "sea-orm-macros" version = "1.1.0" @@ -2896,6 +3406,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sea-orm-migration" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0" +dependencies = [ + "async-trait", + "clap", + "dotenvy", + "futures", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + [[package]] name = "sea-query" version = "0.32.0" @@ -2904,6 +3431,7 @@ checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" dependencies = [ "inherent", "ordered-float", + "sea-query-derive", "uuid", ] @@ -2918,6 +3446,43 @@ dependencies = [ "uuid", ] +[[package]] +name = "sea-query-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" +dependencies = [ + "darling", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.82", + "thiserror", +] + +[[package]] +name = "sea-schema" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e" +dependencies = [ + "futures", + "sea-query", + "sea-schema-derive", +] + +[[package]] +name = "sea-schema-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "seahash" version = "4.1.0" @@ -3196,7 +3761,7 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener", + "event-listener 5.3.1", "futures-channel", "futures-core", "futures-intrusive", @@ -3410,6 +3975,12 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.26.3" @@ -3556,6 +4127,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "tokio-retry2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903934dba1c4c2f2e9cb460ef10b5695e0b0ecad3bf9ee7c8675e540c5e8b2d1" +dependencies = [ + "pin-project", + "rand", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.23.4" @@ -3665,10 +4247,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -3769,6 +4355,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.11.0" @@ -3790,6 +4382,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3858,6 +4456,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.95" @@ -3966,6 +4576,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 74df6f8..de98b1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ actix-files = { version = "0.6.6", features = ["experimental-io-uring"] } actix-web = { version = "4.9.0", features = ["compress-brotli", "cookies", "experimental-io-uring", "macros", "rustls", "secure-cookies", "unicode"], default-features = false } askama = { version = "0.12.1", features = ["with-actix-web", "serde_json", "mime_guess", "markdown", "comrak", "mime"] } askama_actix = "0.14.0" -redis = { version = "0.27.5", features = ["tokio", "json", "uuid", "tokio-comp"] } +redis = { version = "0.27.5", features = ["tokio", "json", "uuid", "tokio-comp", "connection-manager"] } sea-orm = { version = "1.1.0", default-features = false, features = ["chrono", "macros", "runtime-actix-rustls", "serde_json", "sqlx-postgres", "with-uuid"] } tracing = "0.1.40" tracing-subscriber = "0.3.18" @@ -17,6 +17,7 @@ rswind = "0.0.1-alpha.1" serde = "1.0.210" serde_json = "1.0.132" uuid = { version = "1.11.0", features = ["v4", "v8"] } +migration = { path = "./migration" } [build-dependencies] rswind = "0.0.1-alpha.1" diff --git a/build.rs b/build.rs index e0ab29d..0c9afba 100644 --- a/build.rs +++ b/build.rs @@ -2,10 +2,10 @@ use glob::GlobMatcher; use rswind::*; fn main() { - let mut p = create_app(); - p.processor.options.watch = false; - p.processor.options.parallel = true; - p.glob = GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid"); - let contents = p.generate_contents(); - std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css"); + // let mut p = create_app(); + // p.processor.options.watch = false; + // p.processor.options.parallel = true; + // p.glob = GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid"); + // let contents = p.generate_contents(); + // std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css"); } diff --git a/src/main.rs b/src/main.rs index c869150..f84592e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,32 @@ use actix_files::Files; use actix_web::{ cookie::{time::Duration, CookieBuilder}, - delete, get, patch, post, - web::{Data, Json}, - App, HttpResponse, HttpServer, + get, post, + web::{Data, Json, Path}, + App, HttpResponse, HttpServer, Responder, }; use askama::Template; -use redis::{AsyncCommands, Commands}; -use sea_orm::{prelude::*, Database, DatabaseConnection}; +use redis::AsyncCommands; +use sea_orm::{prelude::*, Database}; use std::str::FromStr; +mod entities; + +#[derive(Debug, Template)] +#[template(path = "recipe_card.html")] +struct RecipeCard { + author: Option, + image_url: String, + title: String, + time: Option, +} + +#[derive(Debug, Template)] +#[template(path = "index.html")] +struct IndexTemplate { + recipies: Vec, +} + #[derive(Debug)] pub struct Admin { pub login: String, @@ -72,25 +89,104 @@ async fn sign_in( .iter() .any(|admin| admin.login == payload.login && admin.pass == payload.password); if is_admin { + let mut con = redis + .get_multiplexed_async_connection() + .await + .expect("Failed to get redis get_multiplexed_async_connection"); + let uid = uuid::Uuid::new_v4(); - redis + + let _: () = con .set_ex(uid.to_string(), "1", 60 * 60 * 24) // session exists for 1 day .await .expect("Failed to store session"); - HttpResponse::Ok().cookie( - CookieBuilder::new("ses", uid.to_string()) - .secure(true) - .max_age(Duration::hours(24)) - .build(), - ) + HttpResponse::Ok() + .cookie( + CookieBuilder::new("ses", uid.to_string()) + .secure(true) + .max_age(Duration::hours(24)) + .finish(), + ) + .finish() } else { HttpResponse::Ok().finish() } } #[get("/")] -async fn index_html() -> HttpResponse { - HttpResponse::Ok().body(include_str!("../templates/index.html")) +async fn index_html(db: Data) -> IndexTemplate { + let recipies = entities::prelude::Recipies::find() + .all(&**db) + .await + .unwrap_or_default(); + IndexTemplate { + recipies: recipies + .into_iter() + .map(|r| RecipeCard { + author: r.author, + image_url: r.image_url.unwrap_or_default(), + title: r.title, + time: r.time, + }) + .collect(), + } +} + +#[derive(Debug, Template)] +#[template(path = "recipies/show.html", print = "all")] +struct RecipeDetailTemplate { + recipe: entities::recipies::Model, + tags: Vec, + steps: Vec, + ingeredients: Vec, +} + +#[get("/recipe/{id}")] +async fn show(id: Path, db: Data) -> impl Responder { + let id = id.into_inner(); + let db = &**db; + let Ok(Some(recipe)) = entities::prelude::Recipies::find() + .filter(entities::recipies::Column::Id.eq(id)) + .one(db) + .await + else { + return HttpResponse::SeeOther() + .append_header(("location", "/")) + .finish(); + }; + let tags = entities::prelude::RecipeTags::find() + .filter(entities::recipe_tags::Column::RecipeId.eq(id)) + .all(db) + .await + .unwrap_or_default(); + let steps = entities::prelude::RecipeSteps::find() + .filter(entities::recipe_steps::Column::RecipeId.eq(id)) + .all(db) + .await + .unwrap_or_default(); + let ingeredients = entities::prelude::RecipeIngeredients::find() + .filter(entities::recipe_ingeredients::Column::RecipeId.eq(id)) + .all(db) + .await + .unwrap_or_default(); + + HttpResponse::Ok().body( + RecipeDetailTemplate { + steps, + tags, + recipe, + ingeredients, + } + .render() + .unwrap_or_default(), + ) +} + +#[get("/styles.css")] +async fn styles_css() -> HttpResponse { + HttpResponse::Ok() + .append_header(("Content-Type", "text/css")) + .body(include_str!("../templates/styles.css")) } #[actix_web::main] @@ -100,18 +196,18 @@ async fn main() { tracing::info!("You can define admins by setting env variable ADMINS"); tracing::info!(" Example: ADMINS=login1:pass1,login2,pass2"); - { - use glob::GlobMatcher; - use rswind::*; + // { + // use glob::GlobMatcher; + // use rswind::*; - let mut p = create_app(); - p.processor.options.watch = false; - p.processor.options.parallel = true; - p.glob = - GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid"); - let contents = p.generate_contents(); - std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css"); - } + // let mut p = create_app(); + // p.processor.options.watch = false; + // p.processor.options.parallel = true; + // p.glob = + // GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid"); + // let contents = p.generate_contents(); + // std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css"); + // } std::fs::create_dir_all("./pages").ok(); std::fs::create_dir_all("./tmp").ok(); @@ -130,7 +226,11 @@ async fn main() { let db = Database::connect(&psql) .await .expect("Failed to connect to postgresql"); - // Migrator::up(&conn, None).await.unwrap(); + { + use migration::*; + + Migrator::up(&db, None).await.unwrap(); + } let redis = redis::Client::open(redis_url).expect("Failed to connect to redis"); // Transform to data @@ -147,10 +247,12 @@ async fn main() { .app_data(admins.clone()) .app_data(db.clone()) .app_data(redis.clone()) + .service(styles_css) .service(Files::new("/pages", "./pages")) .service(render_sign_in) .service(sign_in) .service(index_html) + .service(show) }) .bind(&bind) .expect("Failed to start http server") diff --git a/templates/index.html b/templates/index.html index 4fa0da3..4587946 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,131 +1,29 @@ - - - - - - - - Techie Recipes - - - -
+{% extends "base.html" %} - -
- -
- - -
-
- Login - Sign Up -
- -
-

Recipes

-

For Techies

-
- -
-

Latest Recipes

-
-
- stew -
- 5 Bean Chilli Stew - Recipe by McTechie -
-
- - - - 25 mins -
-
-
- noodles -
- Lo Mein - Recipe by McTechie -
-
- - - - 25 mins -
-
-
- curry -
- Tofu Curry - Recipe by McTechie -
-
- - - - 25 mins -
-
-
- -

Most Popular

-
- -
- -
-
Load More
-
-
-
+{% block content %} + +
+
+ Login
- - + +
+

Recipes

+

For Techies

+
+ +
+

Latest Recipes

+
+ {% for recipe in recipies %} + {{ recipe|safe }} + {% endfor %} +
+ +
+
Load More
+
+
+
+ +{% endblock %} diff --git a/templates/recipes/create_form.html b/templates/recipes/create_form.html deleted file mode 100644 index e69de29..0000000 diff --git a/templates/recipes/show.html b/templates/recipes/show.html deleted file mode 100644 index e69de29..0000000 diff --git a/templates/recipes/update_form.html b/templates/recipes/update_form.html deleted file mode 100644 index e69de29..0000000 diff --git a/templates/styles.css b/templates/styles.css index e69de29..0433949 100644 --- a/templates/styles.css +++ b/templates/styles.css @@ -0,0 +1,1213 @@ +@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200;0,300;0,400;0,600;0,700;0,800;0,900;1,200;1,300;1,400;1,600;1,700;1,800;1,900&display=swap'); + +*, ::before, ::after{ + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop{ + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +/* +! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden]:where(:not([hidden="until-found"])) { + display: none; +} + +.m-4{ + margin: 1rem; +} + +.ml-2{ + margin-left: 0.5rem; +} + +.mt-12{ + margin-top: 3rem; +} + +.mt-2{ + margin-top: 0.5rem; +} + +.mt-6{ + margin-top: 1.5rem; +} + +.mt-8{ + margin-top: 2rem; +} + +.mb-2{ + margin-bottom: 0.5rem; +} + +.mb-3{ + margin-bottom: 0.75rem; +} + +.mb-5{ + margin-bottom: 1.25rem; +} + +.mb-6{ + margin-bottom: 1.5rem; +} + +.mb-7{ + margin-bottom: 1.75rem; +} + +.mb-8{ + margin-bottom: 2rem; +} + +.ml-6{ + margin-left: 1.5rem; +} + +.ml-\[1\.7rem\]{ + margin-left: 1.7rem; +} + +.ml-auto{ + margin-left: auto; +} + +.mr-4{ + margin-right: 1rem; +} + +.mr-auto{ + margin-right: auto; +} + +.mr-2{ + margin-right: 0.5rem; +} + +.block{ + display: block; +} + +.inline-block{ + display: inline-block; +} + +.flex{ + display: flex; +} + +.table{ + display: table; +} + +.grid{ + display: grid; +} + +.hidden{ + display: none; +} + +.h-32{ + height: 8rem; +} + +.h-5{ + height: 1.25rem; +} + +.h-6{ + height: 1.5rem; +} + +.w-5{ + width: 1.25rem; +} + +.w-6{ + width: 1.5rem; +} + +.w-full{ + width: 100%; +} + +.w-\[20\.2rem\]{ + width: 20.2rem; +} + +.w-\[20rem\]{ + width: 20rem; +} + +.w-fit{ + width: -moz-fit-content; + width: fit-content; +} + +.transform{ + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.cursor-pointer{ + cursor: pointer; +} + +.list-decimal{ + list-style-type: decimal; +} + +.list-disc{ + list-style-type: disc; +} + +.items-center{ + align-items: center; +} + +.justify-end{ + justify-content: flex-end; +} + +.justify-center{ + justify-content: center; +} + +.justify-between{ + justify-content: space-between; +} + +.gap-10{ + gap: 2.5rem; +} + +.rounded-xl{ + border-radius: 0.75rem; +} + +.border-b{ + border-bottom-width: 1px; +} + +.border-r-4{ + border-right-width: 4px; +} + +.border-b-2{ + border-bottom-width: 2px; +} + +.border-b-\[2px\]{ + border-bottom-width: 2px; +} + +.border-gray-100{ + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity)); +} + +.border-gray-200{ + --tw-border-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-border-opacity)); +} + +.border-primary{ + --tw-border-opacity: 1; + border-color: rgb(255 99 99 / var(--tw-border-opacity)); +} + +.border-white{ + --tw-border-opacity: 1; + border-color: rgb(255 255 255 / var(--tw-border-opacity)); +} + +.bg-gray-100{ + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.bg-secondary-100{ + --tw-bg-opacity: 1; + background-color: rgb(226 226 213 / var(--tw-bg-opacity)); +} + +.bg-rose-50{ + --tw-bg-opacity: 1; + background-color: rgb(255 241 242 / var(--tw-bg-opacity)); +} + +.object-cover{ + -o-object-fit: cover; + object-fit: cover; +} + +.p-4{ + padding: 1rem; +} + +.px-16{ + padding-left: 4rem; + padding-right: 4rem; +} + +.px-4{ + padding-left: 1rem; + padding-right: 1rem; +} + +.py-2{ + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-6{ + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} + +.py-5{ + padding-top: 1.25rem; + padding-bottom: 1.25rem; +} + +.pb-2{ + padding-bottom: 0.5rem; +} + +.pl-1{ + padding-left: 0.25rem; +} + +.pb-4{ + padding-bottom: 1rem; +} + +.pb-6{ + padding-bottom: 1.5rem; +} + +.pl-3{ + padding-left: 0.75rem; +} + +.pl-7{ + padding-left: 1.75rem; +} + +.pl-8{ + padding-left: 2rem; +} + +.pl-\[1\.7rem\]{ + padding-left: 1.7rem; +} + +.pr-7{ + padding-right: 1.75rem; +} + +.pr-\[15px\]{ + padding-right: 15px; +} + +.text-right{ + text-align: right; +} + +.font-body{ + font-family: Nunito; +} + +.text-2xl{ + font-size: 1.5rem; + line-height: 2rem; +} + +.text-6xl{ + font-size: 3.75rem; + line-height: 1; +} + +.text-sm{ + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-\[17px\]{ + font-size: 17px; +} + +.text-\[37px\]{ + font-size: 37px; +} + +.text-base{ + font-size: 1rem; + line-height: 1.5rem; +} + +.text-lg{ + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-xl{ + font-size: 1.25rem; + line-height: 1.75rem; +} + +.font-bold{ + font-weight: 700; +} + +.font-semibold{ + font-weight: 600; +} + +.uppercase{ + text-transform: uppercase; +} + +.leading-10{ + line-height: 2.5rem; +} + +.leading-\[2\.8rem\]{ + line-height: 2.8rem; +} + +.text-gray-500{ + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-gray-600{ + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.text-gray-700{ + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} + +.text-primary{ + --tw-text-opacity: 1; + color: rgb(255 99 99 / var(--tw-text-opacity)); +} + +.text-secondary-200{ + --tw-text-opacity: 1; + color: rgb(136 136 131 / var(--tw-text-opacity)); +} + +.text-rose-900{ + --tw-text-opacity: 1; + color: rgb(136 19 55 / var(--tw-text-opacity)); +} + +.text-stone-500{ + --tw-text-opacity: 1; + color: rgb(120 113 108 / var(--tw-text-opacity)); +} + +.text-stone-600{ + --tw-text-opacity: 1; + color: rgb(87 83 78 / var(--tw-text-opacity)); +} + +.text-stone-700{ + --tw-text-opacity: 1; + color: rgb(68 64 60 / var(--tw-text-opacity)); +} + +.transition{ + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.duration-300{ + transition-duration: 300ms; +} + +.ease-linear{ + transition-timing-function: linear; +} + +.ease-out{ + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); +} + +/* overflow-hidden is to prevent overflow within the card */ + +.card{ + position: relative; + overflow: hidden; + border-radius: 0.25rem; + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +/* object-cover is to prevent distortion */ + +.badge{ + position: absolute; + top: 0px; + margin-left: 0.5rem; + margin-top: 0.5rem; + border-radius: 9999px; + --tw-bg-opacity: 1; + background-color: rgb(226 226 213 / var(--tw-bg-opacity)); + padding: 0.5rem; + font-size: 0.75rem; + line-height: 1rem; + font-weight: 700; + text-transform: uppercase; + --tw-text-opacity: 1; + color: rgb(136 136 131 / var(--tw-text-opacity)); +} + +/* tracking-wider is for space between letters */ + +.btn{ + cursor: pointer; + border-radius: 9999px; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + padding-right: 0.75rem; + font-size: 0.75rem; + line-height: 1rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.marker\:text-rose-900 *::marker{ + color: rgb(136 19 55 ); +} + +.marker\:text-rose-900::marker{ + color: rgb(136 19 55 ); +} + +.hover\:scale-105:hover{ + --tw-scale-x: 1.05; + --tw-scale-y: 1.05; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:scale-110:hover{ + --tw-scale-x: 1.1; + --tw-scale-y: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:bg-opacity-60:hover{ + --tw-bg-opacity: 0.6; +} + +.hover\:text-gray-600:hover{ + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.hover\:shadow-inner:hover{ + --tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.hover\:shadow-lg:hover{ + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.hover\:shadow-md:hover{ + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +@media (min-width: 640px){ + .sm\:ml-0{ + margin-left: 0px; + } + + .sm\:ml-auto{ + margin-left: auto; + } + + .sm\:mr-0{ + margin-right: 0px; + } + + .sm\:mr-auto{ + margin-right: auto; + } + + .sm\:mt-9{ + margin-top: 2.25rem; + } + + .sm\:mt-\[10rem\]{ + margin-top: 10rem; + } + + .sm\:w-\[50\%\]{ + width: 50%; + } + + .sm\:w-auto{ + width: auto; + } + + .sm\:w-full{ + width: 100%; + } + + .sm\:rounded-3xl{ + border-radius: 1.5rem; + } + + .sm\:rounded-xl{ + border-radius: 0.75rem; + } + + .sm\:bg-white{ + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + } + + .sm\:p-0{ + padding: 0px; + } + + .sm\:p-10{ + padding: 2.5rem; + } + + .sm\:py-6{ + padding-top: 1.5rem; + padding-bottom: 1.5rem; + } + + .sm\:pb-0{ + padding-bottom: 0px; + } + + .sm\:pl-8{ + padding-left: 2rem; + } + + .sm\:text-left{ + text-align: left; + } + + .sm\:text-\[16px\]{ + font-size: 16px; + } + + .sm\:text-base{ + font-size: 1rem; + line-height: 1.5rem; + } + + .sm\:text-stone-800{ + --tw-text-opacity: 1; + color: rgb(41 37 36 / var(--tw-text-opacity)); + } +} + +@media (min-width: 768px){ + .md\:col-span-1{ + grid-column: span 1 / span 1; + } + + .md\:col-span-3{ + grid-column: span 3 / span 3; + } + + .md\:block{ + display: block; + } + + .md\:flex{ + display: flex; + } + + .md\:hidden{ + display: none; + } + + .md\:h-48{ + height: 12rem; + } + + .md\:grid-cols-3{ + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .md\:grid-cols-4{ + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .md\:justify-end{ + justify-content: flex-end; + } + + .md\:border-2{ + border-width: 2px; + } +}