A bit of clean up
authorGreg Burri <greg.burri@gmail.com>
Sat, 1 Mar 2025 23:39:58 +0000 (00:39 +0100)
committerGreg Burri <greg.burri@gmail.com>
Sat, 1 Mar 2025 23:39:58 +0000 (00:39 +0100)
24 files changed:
Cargo.lock
backend/Cargo.toml
backend/scss/calendar.scss
backend/scss/style.scss
backend/sql/data_test.sql
backend/src/data/db/recipe.rs
backend/src/main.rs
backend/src/services/user.rs
backend/templates/ask_reset_password.html
backend/templates/base_with_header.html
backend/templates/profile.html
backend/templates/recipe_edit.html
backend/templates/recipe_view.html
backend/templates/recipes_list_fragment.html
backend/templates/sign_in_form.html
backend/templates/sign_up_form.html
backend/watch_scss.nu [new file with mode: 0644]
common/Cargo.toml
frontend/Cargo.toml
frontend/src/error.rs [new file with mode: 0644]
frontend/src/home.rs
frontend/src/lib.rs
frontend/src/recipe_edit.rs
frontend/src/recipe_view.rs

index 7096d3a..2f667da 100644 (file)
@@ -291,9 +291,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 dependencies = [
  "serde",
 ]
@@ -336,9 +336,9 @@ checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
 
 [[package]]
 name = "cc"
-version = "1.2.13"
+version = "1.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
+checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
 dependencies = [
  "shlex",
 ]
@@ -351,9 +351,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.39"
+version = "0.4.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
+checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -362,7 +362,7 @@ dependencies = [
  "pure-rust-locales",
  "serde",
  "wasm-bindgen",
- "windows-targets 0.52.6",
+ "windows-link",
 ]
 
 [[package]]
@@ -377,9 +377,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.29"
+version = "4.5.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
+checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -387,9 +387,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.29"
+version = "4.5.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
+checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
 dependencies = [
  "anstream",
  "anstyle",
@@ -603,9 +603,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
 
 [[package]]
 name = "either"
-version = "1.13.0"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d"
 dependencies = [
  "serde",
 ]
@@ -628,9 +628,9 @@ checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
 
 [[package]]
 name = "equivalent"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
@@ -1444,9 +1444,9 @@ dependencies = [
 
 [[package]]
 name = "lettre"
-version = "0.11.12"
+version = "0.11.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e882e1489810a45919477602194312b1a7df0e5acc30a6188be7b520268f63f8"
+checksum = "5d476fe7a4a798f392ce34947aa7d53d981127e37523c5251da3c927f7fa901f"
 dependencies = [
  "async-trait",
  "base64 0.22.1",
@@ -1460,12 +1460,10 @@ dependencies = [
  "httpdate",
  "idna",
  "mime",
- "nom",
+ "nom 8.0.0",
  "percent-encoding",
  "quoted_printable",
  "rustls",
- "rustls-pemfile",
- "rustls-pki-types",
  "socket2",
  "tokio",
  "tokio-rustls",
@@ -1475,9 +1473,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.169"
+version = "0.2.170"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
 
 [[package]]
 name = "libm"
@@ -1504,9 +1502,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
 
 [[package]]
 name = "litemap"
-version = "0.7.4"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
+checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
 
 [[package]]
 name = "lock_api"
@@ -1520,9 +1518,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.25"
+version = "0.4.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
+checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
 
 [[package]]
 name = "matchers"
@@ -1579,9 +1577,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
+checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
 dependencies = [
  "adler2",
 ]
@@ -1607,6 +1605,15 @@ dependencies = [
  "minimal-lexical",
 ]
 
+[[package]]
+name = "nom"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "nu-ansi-term"
 version = "0.46.0"
@@ -1852,9 +1859,9 @@ dependencies = [
 
 [[package]]
 name = "psm"
-version = "0.1.24"
+version = "0.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
+checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88"
 dependencies = [
  "cc",
 ]
@@ -1898,8 +1905,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
 dependencies = [
  "rand_chacha 0.9.0",
- "rand_core 0.9.0",
- "zerocopy 0.8.17",
+ "rand_core 0.9.2",
+ "zerocopy 0.8.21",
 ]
 
 [[package]]
@@ -1919,7 +1926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.9.0",
+ "rand_core 0.9.2",
 ]
 
 [[package]]
@@ -1933,12 +1940,12 @@ dependencies = [
 
 [[package]]
 name = "rand_core"
-version = "0.9.0"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
+checksum = "7a509b1a2ffbe92afab0e55c8fd99dea1c280e8171bd2d88682bb20bc41cbc2c"
 dependencies = [
  "getrandom 0.3.1",
- "zerocopy 0.8.17",
+ "zerocopy 0.8.21",
 ]
 
 [[package]]
@@ -1955,7 +1962,7 @@ dependencies = [
  "itertools",
  "lettre",
  "rand 0.9.0",
- "rand_core 0.9.0",
+ "rand_core 0.9.2",
  "rinja",
  "ron",
  "serde",
@@ -1972,9 +1979,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
+checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f"
 dependencies = [
  "bitflags",
 ]
@@ -2025,15 +2032,14 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "ring"
-version = "0.17.8"
+version = "0.17.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73"
 dependencies = [
  "cc",
  "cfg-if",
  "getrandom 0.2.15",
  "libc",
- "spin",
  "untrusted",
  "windows-sys 0.52.0",
 ]
@@ -2075,7 +2081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
 dependencies = [
  "memchr",
- "nom",
+ "nom 7.1.3",
  "serde",
 ]
 
@@ -2151,15 +2157,6 @@ dependencies = [
  "zeroize",
 ]
 
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
-]
-
 [[package]]
 name = "rustls-pki-types"
 version = "1.11.0"
@@ -2195,7 +2192,7 @@ version = "1.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cbf5845f2587e0dd28b0dc313d1bbe0b7aa70aedb8e236785f670dcd1df1f677"
 dependencies = [
- "nom",
+ "nom 7.1.3",
 ]
 
 [[package]]
@@ -2206,9 +2203,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.217"
+version = "1.0.218"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
+checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
 dependencies = [
  "serde_derive",
 ]
@@ -2226,9 +2223,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.217"
+version = "1.0.218"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
+checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2250,9 +2247,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.138"
+version = "1.0.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
+checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
 dependencies = [
  "itoa",
  "memchr",
@@ -2349,9 +2346,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.13.2"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
 dependencies = [
  "serde",
 ]
@@ -2584,9 +2581,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "stacker"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d08feb8f695b465baed819b03c128dc23f57a694510ab1f06c77f763975685e"
+checksum = "d9156ebd5870ef293bfb43f91c7a74528d363ec0d424afe24160ed5a4343d08a"
 dependencies = [
  "cc",
  "cfg-if",
@@ -2614,15 +2611,15 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "strum"
-version = "0.27.0"
+version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce1475c515a4f03a8a7129bb5228b81a781a86cb0b3fbbc19e1c556d491a401f"
+checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
 
 [[package]]
 name = "strum_macros"
-version = "0.27.0"
+version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9688894b43459159c82bfa5a5fa0435c19cbe3c9b427fa1dd7b1ce0c279b18a7"
+checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -2667,9 +2664,9 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.16.0"
+version = "3.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
+checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -2982,9 +2979,9 @@ dependencies = [
 
 [[package]]
 name = "typenum"
-version = "1.17.0"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
 
 [[package]]
 name = "unicase"
@@ -3000,9 +2997,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
+checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
 
 [[package]]
 name = "unicode-normalization"
@@ -3246,6 +3243,12 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "windows-link"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -3460,11 +3463,11 @@ dependencies = [
 
 [[package]]
 name = "zerocopy"
-version = "0.8.17"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713"
+checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478"
 dependencies = [
- "zerocopy-derive 0.8.17",
+ "zerocopy-derive 0.8.21",
 ]
 
 [[package]]
@@ -3480,9 +3483,9 @@ dependencies = [
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.8.17"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626"
+checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3491,18 +3494,18 @@ dependencies = [
 
 [[package]]
 name = "zerofrom"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
 dependencies = [
  "zerofrom-derive",
 ]
 
 [[package]]
 name = "zerofrom-derive"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
 dependencies = [
  "proc-macro2",
  "quote",
index 0e40b12..7c9fda6 100644 (file)
@@ -2,7 +2,7 @@
 name = "recipes"
 version = "1.0.0"
 authors = ["GrĂ©gory Burri <greg.burri@gmail.com>"]
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 common = { path = "../common" }
index 601893a..d3f36de 100644 (file)
@@ -43,7 +43,7 @@
             margin: 0;
 
             &.current-month {
-                background-color: blue;
+                background-color: green;
             }
 
             &.today {
index ab748cd..4855638 100644 (file)
@@ -1,3 +1,5 @@
+@use 'sass:color';
+
 @use 'toast.scss';
 @use 'modal-dialog.scss';
 @use 'calendar.scss';
@@ -6,7 +8,10 @@ $color-1: #B29B89;
 $color-2: #89B29B;
 $color-3: #9B89B2;
 
-$text-color: darken($color-1, 30%);
+$text-color: color.adjust($color-1, $lightness: -30%);
+$text-highlight: color.adjust($color-1, $lightness: +30%);
+$link-color: color.adjust($color-3, $lightness: -25%);
+$link-hover-color: color.adjust($color-3, $lightness: +20%);
 
 * {
     margin: 5px;
@@ -14,11 +19,11 @@ $text-color: darken($color-1, 30%);
 }
 
 a {
-    color: darken($color-3, 25%);
+    color: $link-color;
     text-decoration: none;
 
     &:hover {
-        color: lighten($color-3, 20%);
+        color: $link-hover-color;
     }
 }
 
@@ -31,6 +36,27 @@ body {
     background-color: $color-1;
     margin: 0px;
 
+    .user-message {
+        font-weight: bold;
+    }
+
+    .footer-container {
+        align-self: center;
+        font-size: 0.7em;
+    }
+
+    .drag-handle {
+        width: 20px;
+        height: 20px;
+        display: inline-block;
+        vertical-align: bottom;
+        background-color: blue;
+    }
+
+    img {
+        border: 0px;
+    }
+
     .header-container {
         display: flex;
         flex-direction: row;
@@ -63,23 +89,6 @@ body {
         }
     }
 
-    .footer-container {
-        align-self: center;
-        font-size: 0.7em;
-    }
-
-    .drag-handle {
-        width: 20px;
-        height: 20px;
-        display: inline-block;
-        vertical-align: bottom;
-        background-color: blue;
-    }
-
-    img {
-        border: 0px;
-    }
-
     .main-container {
         display: flex;
         flex-direction: row;
@@ -96,18 +105,20 @@ body {
             }
 
             .recipe-item {
+                white-space: preserve nowrap;
                 padding: 4px;
                 // Transparent border: to keep same size than '.recipe-item-current'.
                 border: 0.1em solid rgba(0, 0, 0, 0);
-            }
 
-            .recipe-item-current {
-                color: lighten($color-3, 30%);
-                padding: 4px;
-                background-color: $color-2;
+                &.current {
+                    white-space: preserve nowrap;
+                    padding: 4px;
+                    border: 0.1em solid $color-3;
 
-                border: 0.1em solid $color-3;
-                border-radius: 0.5em;
+                    border-radius: 0.5em;
+                    color: $text-highlight;
+                    background-color: $color-2;
+                }
             }
         }
 
@@ -131,24 +142,26 @@ body {
         }
 
         #recipe-edit {
+            display: grid;
+
             .drag-handle {
                 cursor: move;
             }
 
             .group {
-                border: 0.1em solid lighten($color-3, 30%);
+                border: 0.1em solid color.adjust($color-3, $lightness: +30%);
                 margin-top: 0px;
                 margin-bottom: 0px;
             }
 
             .step {
-                border: 0.1em solid lighten($color-3, 30%);
+                border: 0.1em solid color.adjust($color-3, $lightness: +30%);
                 margin-top: 0px;
                 margin-bottom: 0px;
             }
 
             .ingredient {
-                border: 0.1em solid lighten($color-3, 30%);
+                border: 0.1em solid color.adjust($color-3, $lightness: +30%);
                 margin-top: 0px;
                 margin-bottom: 0px;
             }
@@ -184,6 +197,41 @@ body {
             }
         }
 
+        #sign-up form {
+            display: grid;
+            grid-template-columns: auto 1fr auto;
+
+            input[type="submit"] {
+                grid-column: 2
+            }
+        }
+
+        #sign-in form {
+            input[type="submit"] {
+                grid-column: 2
+            }
+        }
+
+        #ask-reset-password form {
+            grid-template-columns: auto 1fr auto;
+
+            input[type="submit"] {
+                grid-column: 2
+            }
+        }
+
+        #user-edit form {
+            grid-template-columns: auto 1fr auto;
+
+            input[type="submit"] {
+                grid-column: 2
+            }
+        }
+
+        // #sign-in {
+
+        // }
+
         // #user-edit {
         //     .label-name {
         //         grid-column: 1;
@@ -222,9 +270,5 @@ body {
         //         justify-self: flex-end;
         //     }
         // }
-
-        // #sign-in {
-
-        // }
     }
 }
\ No newline at end of file
index c2ec78c..9ca6c2b 100644 (file)
@@ -72,7 +72,7 @@ INSERT INTO [Ingredient] ([id], [order], [step_id], [name], [comment], [quantity
 VALUES (6, 3, 3, "Crème Ă  cafĂ© ou demi-crème", "", 2, "dl");
 
 INSERT INTO [Ingredient] ([id], [order], [step_id], [name], [comment], [quantity_value], [quantity_unit])
-VALUES (7, 4, 3, "Olives farcies coupĂ©es en deuxs", "", 50, "g");
+VALUES (7, 4, 3, "Olives farcies coupĂ©es en deux", "", 50, "g");
 
 
 INSERT INTO [Group] ([id], [order], [recipe_id], [name], [comment])
index 00b5cec..a6954fe 100644 (file)
@@ -22,10 +22,10 @@ impl Connection {
         if let Some(user_id) = user_id {
             sqlx::query_as(
                 r#"
-    SELECT [id], [title]
-    FROM [Recipe]
-    WHERE [is_published] = true AND ([lang] = $1 OR [user_id] = $2)
-    ORDER BY [title] COLLATE NOCASE
+SELECT [id], [title]
+FROM [Recipe]
+WHERE [is_published] = true AND ([lang] = $1 OR [user_id] = $2)
+ORDER BY [title] COLLATE NOCASE
                 "#,
             )
             .bind(lang)
@@ -33,10 +33,10 @@ impl Connection {
         } else {
             sqlx::query_as(
                 r#"
-    SELECT [id], [title]
-    FROM [Recipe]
-    WHERE [is_published] = true AND [lang] = $1
-    ORDER BY [title] COLLATE NOCASE
+SELECT [id], [title]
+FROM [Recipe]
+WHERE [is_published] = true AND [lang] = $1
+ORDER BY [title] COLLATE NOCASE
                 "#,
             )
             .bind(lang)
index 9e1b915..a9ef75a 100644 (file)
@@ -1,12 +1,12 @@
 use std::{net::SocketAddr, path::Path};
 
 use axum::{
+    Router,
     extract::{ConnectInfo, Extension, FromRef, Request, State},
     http::StatusCode,
     middleware::{self, Next},
     response::Response,
     routing::{delete, get, post, put},
-    Router,
 };
 use axum_extra::extract::cookie::CookieJar;
 use chrono::prelude::*;
@@ -14,7 +14,7 @@ use clap::Parser;
 use config::Config;
 use itertools::Itertools;
 use tower_http::{services::ServeDir, trace::TraceLayer};
-use tracing::{event, Level};
+use tracing::{Level, event};
 
 use data::{db, model};
 use translation::Tr;
@@ -380,11 +380,7 @@ async fn process_args() -> bool {
             let db_path_bckup = (1..)
                 .find_map(|n| {
                     let p = db_path.with_extension(format!("sqlite.bckup{:03}", n));
-                    if p.exists() {
-                        None
-                    } else {
-                        Some(p)
-                    }
+                    if p.exists() { None } else { Some(p) }
                 })
                 .unwrap();
             std::fs::copy(&db_path, &db_path_bckup).unwrap_or_else(|error| {
index 55da879..2e82969 100644 (file)
@@ -1,31 +1,32 @@
 use std::{collections::HashMap, net::SocketAddr};
 
 use axum::{
+    Form,
     body::Body,
     debug_handler,
     extract::{ConnectInfo, Extension, Request, State},
     http::HeaderMap,
     response::{Html, IntoResponse, Redirect, Response},
-    Form,
 };
 use axum_extra::extract::{
-    cookie::{Cookie, CookieJar},
     Host, Query,
+    cookie::{Cookie, CookieJar},
 };
 use chrono::Duration;
 use lettre::Address;
 use rinja::Template;
 use serde::Deserialize;
-use tracing::{event, Level};
+use tracing::{Level, event};
 
 use crate::{
+    AppState, Result,
     config::Config,
     consts,
     data::{db, model},
     email,
     html_templates::*,
     translation::{self, Sentence},
-    utils, AppState, Result,
+    utils,
 };
 
 /// SIGN UP ///
@@ -807,7 +808,7 @@ pub async fn edit_user_post(
                 message = tr.t(Sentence::ProfileSaved);
             }
             Err(_) => {
-                return error_response(ProfileUpdateError::DatabaseError, &form_data, user, tr)
+                return error_response(ProfileUpdateError::DatabaseError, &form_data, user, tr);
             }
         }
 
index 66db225..679ef97 100644 (file)
@@ -1,17 +1,18 @@
 {% extends "base_with_header.html" %}
 
 {% block main_container %}
-    <div class="content">
+    <div class="content"  id="ask-reset-password">
         <h1>{{ tr.t(Sentence::LostPassword) }}</h1>
         <form action="/ask_reset_password" method="post">
             <label for="email_field">{{ tr.t(Sentence::EmailAddress) }}</label>
             <input id="email_field" type="email"
                 name="email" value="{{ email }}"
                 autocapitalize="none" autocomplete="email" autofocus="autofocus">
-            {{ message_email }}
+                <span class="user-message">{{ message_email }}</span>
 
             <input type="submit" name="commit" value="{{ tr.t(Sentence::AskResetButton) }}">
         </form>
-        {{ message }}
+
+        <span class="user-message">{{ message }}</span>
     </div>
 {% endblock %}
index d0d843d..3e4433c 100644 (file)
@@ -22,7 +22,7 @@
             <select id="select-website-language">
             {% for lang in translation::available_languages() %}
                 <option value="{{ lang.0 }}"
-                {%+ if tr.current_lang_code() == lang.0 %}
+                {%~ if tr.current_lang_code() == lang.0 %}
                     selected
                 {% endif %}
                 >{{ lang.1 }}</option>
index 766553f..a140640 100644 (file)
             autocapitalize="none"
             autocomplete="title"
             autofocus="autofocus">
+        <span></span>
 
         <label for="input-email">{{ tr.t(Sentence::ProfileEmail) }}</label>
         <input id="input-email" type="email"
             name="email" value="{{ email }}"
             autocapitalize="none" autocomplete="email" autofocus="autofocus">
-
-        {{ message_email }}
+        <span class="user-message">{{ message_email }}</span>
 
         <label for="input-servings">{{ tr.t(Sentence::ProfileDefaultServings) }}</label>
         <input
             step="1" min="1" max="100"
             name="default_servings"
             value="{{ default_servings }}">
+        <span></span>
 
         <label for="input-password-1">{{ tr.tp(Sentence::ProfileNewPassword, [Box::new(common::consts::MIN_PASSWORD_SIZE)]) }}</label>
         <input id="input-password-1" type="password" name="password_1" autocomplete="new-password">
+        <span></span>
 
         <label for="input-password-2">{{ tr.t(Sentence::ReEnterPassword) }}</label>
         <input id="input-password-2" type="password" name="password_2" autocomplete="new-password">
-
-        {{ message_password }}
+        <span class="user-message">{{ message_password }}</span>
 
         <input type="submit" name="commit" value="{{ tr.t(Sentence::Save) }}">
     </form>
-    {{ message }}
+
+    <span class="user-message">{{ message }}</span>
 </div>
 
 {% endif %}
index 21f609b..22dea8c 100644 (file)
 
     <label for="select-difficulty">{{ tr.t(Sentence::RecipeDifficulty) }}</label>
     <select id="select-difficulty">
-        <option value="0" {%+ call is_difficulty(common::ron_api::Difficulty::Unknown) %}> - </option>
-        <option value="1" {%+ call is_difficulty(common::ron_api::Difficulty::Easy) %}>{{ tr.t(Sentence::RecipeDifficultyEasy) }}</option>
-        <option value="2" {%+ call is_difficulty(common::ron_api::Difficulty::Medium) %}>{{ tr.t(Sentence::RecipeDifficultyMedium) }}</option>
-        <option value="3" {%+ call is_difficulty(common::ron_api::Difficulty::Hard) %}>{{ tr.t(Sentence::RecipeDifficultyHard) }}</option>
+        <option value="0" {%~ call is_difficulty(common::ron_api::Difficulty::Unknown) %}> - </option>
+        <option value="1" {%~ call is_difficulty(common::ron_api::Difficulty::Easy) %}>{{ tr.t(Sentence::RecipeDifficultyEasy) }}</option>
+        <option value="2" {%~ call is_difficulty(common::ron_api::Difficulty::Medium) %}>{{ tr.t(Sentence::RecipeDifficultyMedium) }}</option>
+        <option value="3" {%~ call is_difficulty(common::ron_api::Difficulty::Hard) %}>{{ tr.t(Sentence::RecipeDifficultyHard) }}</option>
     </select>
 
     <div id="container-tags">
@@ -61,7 +61,7 @@
     <select id="select-language">
     {% for lang in translation::available_languages() %}
         <option value="{{ lang.0 }}"
-        {%+ if recipe.lang == lang.0 %}
+        {%~ if recipe.lang == lang.0 %}
             selected
         {% endif %}
         >{{ lang.1 }}</option>
@@ -71,7 +71,7 @@
     <input
         id="input-is-published"
         type="checkbox"
-        {%+ if recipe.is_published %}
+        {%~ if recipe.is_published %}
             checked
         {% endif %}
     >
index 8b06a2f..4a0956d 100644 (file)
@@ -33,7 +33,7 @@
 
     {% match recipe.estimated_time %}
     {% when Some(time) %}
-        {{ time +}} {{+ tr.t(Sentence::RecipeEstimatedTimeMinAbbreviation) }}
+        {{ time ~}} {{~ tr.t(Sentence::RecipeEstimatedTimeMinAbbreviation) }}
     {% else %}
     {% endmatch %}
 
             {% for ingredient in step.ingredients %}
                 <div class="ingredient">
                     {% if let Some(quantity) = ingredient.quantity_value %}
-                        {{ quantity +}}
-                        {{+ ingredient.quantity_unit }}
-                    {% endif +%}
-                    {{+ ingredient.name }}
+                        {{ quantity ~}}
+                        {{~ ingredient.quantity_unit }}
+                    {% endif ~%}
+                    {{~ ingredient.name }}
                 </div>
             {% endfor %}
             </div>
index 92d0544..ca89a18 100644 (file)
@@ -1,48 +1,40 @@
-{% macro recipe_item(id, title, class) %}
-<a href="/recipe/view/{{ id }}" class="{{ class }}" id="recipe-{{ id }}">
-    {% if title == "" %}
-        {{ tr.t(Sentence::UntitledRecipe) }}
-    {% else %}
-        {{ title }}
-    {% endif %}
-</a>
+{% macro recipe_item(id, title, is_current) %}
+    <li>
+        <a href="/recipe/view/{{ id }}" class="recipe-item
+            {%~ if is_current %}
+                current
+            {% endif %}" id="recipe-{{ id }}"
+        >
+            {% if title == "" %}
+                {{ tr.t(Sentence::UntitledRecipe) }}
+            {% else %}
+                {{ title }}
+            {% endif %}
+        </a>
+    </li>
 {% endmacro %}
 
-
 <div id="recipes-list">
-
     {% if !recipes.unpublished.is_empty() %}
-    {{ tr.t(Sentence::UnpublishedRecipes) }}
+        {{ tr.t(Sentence::UnpublishedRecipes) }}
     {% endif %}
 
     <nav class="recipes-list-unpublished">
         <ul>
             {% for (id, title) in recipes.unpublished %}
-                <li>
-                    {% if recipes.is_current(id) %}
-                        {% call recipe_item(id, title, "recipe-item-current") %}
-                    {% else %}
-                        {% call recipe_item(id, title, "recipe-item") %}
-                    {% endif %}
-                </li>
+                {% call recipe_item(id, title, recipes.is_current(id)) %}
             {% endfor %}
         </ul>
     </nav>
 
     {% if !recipes.unpublished.is_empty() %}
-    <hr>
+        <hr>
     {% endif %}
 
     <nav class="recipes-list-published">
         <ul>
             {% for (id, title) in recipes.published %}
-                <li>
-                    {% if recipes.is_current(id) %}
-                        {% call recipe_item(id, title, "recipe-item-current") %}
-                    {% else %}
-                        {% call recipe_item(id, title, "recipe-item") %}
-                    {% endif %}
-                </li>
+                {% call recipe_item(id, title, recipes.is_current(id)) %}
             {% endfor %}
         </ul>
     </nav>
index 379c9aa..88c4536 100644 (file)
@@ -16,6 +16,7 @@
 
         <input type="submit" value="{{ tr.t(Sentence::SignInMenu) }}">
     </form>
+
     <span class="user-message">{{ message }}</span>
 </div>
 
index a59774b..86dae07 100644 (file)
             name="email" value="{{ email }}"
             autocapitalize="none" autocomplete="email" autofocus="autofocus"
         >
-
         <span class="user-message">{{ message_email }}</span>
 
         <label for="input-password-1">
             {{ tr.tp(Sentence::ChooseAPassword, [Box::new(common::consts::MIN_PASSWORD_SIZE)]) }}
         </label>
         <input id="input-password-1" type="password" name="password_1" autocomplete="new-password">
+        <span></span>
 
         <label for="input-password-2">{{ tr.t(Sentence::ReEnterPassword) }}</label>
         <input id="input-password-2" type="password" name="password_2" autocomplete="new-password">
-
         <span class="user-message">{{ message_password }}</span>
 
         <input type="submit" name="commit" value="{{ tr.t(Sentence::SignUpButton) }}">
diff --git a/backend/watch_scss.nu b/backend/watch_scss.nu
new file mode 100644 (file)
index 0000000..6219d89
--- /dev/null
@@ -0,0 +1 @@
+sass -w scss/style.scss static/style.css
\ No newline at end of file
index ea07afa..2eb81f8 100644 (file)
@@ -2,7 +2,7 @@
 name = "common"
 version = "0.1.0"
 authors = ["GrĂ©gory Burri <greg.burri@gmail.com>"]
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 ron = "0.8"
index f2f9612..00bb315 100644 (file)
@@ -2,7 +2,7 @@
 name = "frontend"
 version = "0.1.0"
 authors = ["Greg Burri <greg.burri@gmail.com>"]
-edition = "2021"
+edition = "2024"
 
 [lib]
 crate-type = ["cdylib"]
diff --git a/frontend/src/error.rs b/frontend/src/error.rs
new file mode 100644 (file)
index 0000000..2c454f0
--- /dev/null
@@ -0,0 +1,13 @@
+// TODO: Not used at the moment. Remove?
+
+use gloo::utils::errors::JsError;
+// use wasm_bindgen::JsValue;
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    #[error("Javascript error: {0}")]
+    JsError(#[from] JsError),
+
+    #[error("Path unknown: {0}")]
+    UnknownPath(String),
+}
index 2d0737e..7e1b9b3 100644 (file)
@@ -1,23 +1,16 @@
-use std::str::FromStr;
-
-use chrono::Locale;
-use common::{ron_api, utils::substitute_with_names};
-use futures::TryFutureExt;
 use gloo::events::EventListener;
 use wasm_bindgen::prelude::*;
 use wasm_bindgen_futures::spawn_local;
-use web_sys::{Element, HtmlElement, HtmlInputElement};
+use web_sys::{Element, HtmlInputElement};
 
 use crate::{
-    calendar, modal_dialog,
+    calendar,
     recipe_scheduler::RecipeScheduler,
-    request,
     shopping_list::ShoppingList,
-    toast::{self, Level},
-    utils::{by_id, get_locale, selector, SelectorExt},
+    utils::{SelectorExt, by_id, get_locale, selector},
 };
 
-pub fn setup_page(is_user_logged: bool) -> Result<(), JsValue> {
+pub fn setup_page(is_user_logged: bool) {
     let recipe_scheduler = RecipeScheduler::new(!is_user_logged);
 
     calendar::setup(
@@ -111,6 +104,4 @@ pub fn setup_page(is_user_logged: bool) -> Result<(), JsValue> {
             }
         }
     });
-
-    Ok(())
 }
index 949eb30..3320e08 100644 (file)
@@ -1,3 +1,4 @@
+use chrono::Local;
 use common::ron_api;
 use gloo::{console::log, events::EventListener, utils::window};
 use utils::by_id;
@@ -5,9 +6,10 @@ use wasm_bindgen::prelude::*;
 use wasm_bindgen_futures::spawn_local;
 use web_sys::{HtmlElement, HtmlSelectElement};
 
-use crate::utils::selector;
+use crate::{error::Error, utils::selector};
 
 mod calendar;
+mod error;
 mod home;
 mod modal_dialog;
 mod on_click;
@@ -32,30 +34,18 @@ pub fn main() -> Result<(), JsValue> {
         .map(|v| v == "true")
         .unwrap_or_default();
 
-    // if let ["recipe", "edit", id] = path[..] {
     match path[..] {
         ["recipe", "edit", id] => {
             let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
-            if let Err(error) = recipe_edit::setup_page(id) {
-                log!(error);
-            }
+            recipe_edit::setup_page(id)
         }
         ["recipe", "view", id] => {
             let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
-            if let Err(error) = recipe_view::setup_page(id, is_user_logged) {
-                log!(error);
-            }
+            recipe_view::setup_page(id, is_user_logged)
         }
         // Home.
-        [""] => {
-            if let Err(error) = home::setup_page(is_user_logged) {
-                log!(error);
-            }
-        }
-        _ => (), // Disable: user editing data are now submitted as classic form data.
-                 // ["user", "edit"] => {
-                 //     handles::user_edit(document)?;
-                 // }
+        [""] => home::setup_page(is_user_logged),
+        _ => log!("Path unknown: ", location),
     }
 
     let select_language: HtmlSelectElement = by_id("select-website-language");
index eb282f3..575a73a 100644 (file)
@@ -16,17 +16,13 @@ use web_sys::{
 use crate::{
     modal_dialog, request,
     toast::{self, Level},
-    utils::{by_id, selector, selector_and_clone, SelectorExt},
+    utils::{SelectorExt, by_id, selector, selector_and_clone},
 };
 
-pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
+pub fn setup_page(recipe_id: i64) {
     // Title.
     {
-        let Some(title) = document().get_element_by_id("input-title") else {
-            return Err(JsValue::from_str("Unable to find 'input-title' element"));
-        };
-
-        let title: HtmlInputElement = title.dyn_into().unwrap();
+        let title: HtmlInputElement = by_id("input-title");
 
         // Check if the recipe has been loaded.
 
@@ -315,8 +311,6 @@ pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
         })
         .forget();
     }
-
-    Ok(())
 }
 
 fn create_group_element(group: &ron_api::Group) -> Element {
index a66104f..899f924 100644 (file)
@@ -1,9 +1,5 @@
-use std::str::FromStr;
-
-use chrono::Locale;
-use common::{ron_api, utils::substitute_with_names};
+use common::utils::substitute_with_names;
 use gloo::events::EventListener;
-use wasm_bindgen::prelude::*;
 use wasm_bindgen_futures::spawn_local;
 use web_sys::{Element, HtmlInputElement};
 
@@ -11,10 +7,10 @@ use crate::{
     calendar, modal_dialog,
     recipe_scheduler::{RecipeScheduler, ScheduleRecipeResult},
     toast::{self, Level},
-    utils::{get_locale, selector, SelectorExt},
+    utils::{SelectorExt, get_locale, selector},
 };
 
-pub fn setup_page(recipe_id: i64, is_user_logged: bool) -> Result<(), JsValue> {
+pub fn setup_page(recipe_id: i64, is_user_logged: bool) {
     let recipe_scheduler = RecipeScheduler::new(!is_user_logged);
 
     let add_to_planner: Element = selector("#recipe-view .add-to-planner");
@@ -93,6 +89,4 @@ pub fn setup_page(recipe_id: i64, is_user_logged: bool) -> Result<(), JsValue> {
         });
     })
     .forget();
-
-    Ok(())
 }