[[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",
]
[[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",
]
[[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",
"pure-rust-locales",
"serde",
"wasm-bindgen",
- "windows-targets 0.52.6",
+ "windows-link",
]
[[package]]
[[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",
[[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",
[[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",
]
[[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"
[[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",
"httpdate",
"idna",
"mime",
- "nom",
+ "nom 8.0.0",
"percent-encoding",
"quoted_printable",
"rustls",
- "rustls-pemfile",
- "rustls-pki-types",
"socket2",
"tokio",
"tokio-rustls",
[[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"
[[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"
[[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"
[[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",
]
"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"
[[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",
]
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]]
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
- "rand_core 0.9.0",
+ "rand_core 0.9.2",
]
[[package]]
[[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]]
"itertools",
"lettre",
"rand 0.9.0",
- "rand_core 0.9.0",
+ "rand_core 0.9.2",
"rinja",
"ron",
"serde",
[[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",
]
[[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",
]
checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
dependencies = [
"memchr",
- "nom",
+ "nom 7.1.3",
"serde",
]
"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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf5845f2587e0dd28b0dc313d1bbe0b7aa70aedb8e236785f670dcd1df1f677"
dependencies = [
- "nom",
+ "nom 7.1.3",
]
[[package]]
[[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",
]
[[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",
[[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",
[[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",
]
[[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",
[[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",
[[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",
[[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"
[[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"
"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"
[[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]]
[[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",
[[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",
name = "recipes"
version = "1.0.0"
authors = ["Grégory Burri <greg.burri@gmail.com>"]
-edition = "2021"
+edition = "2024"
[dependencies]
common = { path = "../common" }
margin: 0;
&.current-month {
- background-color: blue;
+ background-color: green;
}
&.today {
+@use 'sass:color';
+
@use 'toast.scss';
@use 'modal-dialog.scss';
@use 'calendar.scss';
$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;
}
a {
- color: darken($color-3, 25%);
+ color: $link-color;
text-decoration: none;
&:hover {
- color: lighten($color-3, 20%);
+ color: $link-hover-color;
}
}
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;
}
}
- .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;
}
.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;
+ }
}
}
}
#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;
}
}
}
+ #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;
// justify-self: flex-end;
// }
// }
-
- // #sign-in {
-
- // }
}
}
\ No newline at end of file
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])
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)
} 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)
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::*;
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;
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| {
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 ///
message = tr.t(Sentence::ProfileSaved);
}
Err(_) => {
- return error_response(ProfileUpdateError::DatabaseError, &form_data, user, tr)
+ return error_response(ProfileUpdateError::DatabaseError, &form_data, user, tr);
}
}
{% 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 %}
<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>
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 %}
<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">
<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>
<input
id="input-is-published"
type="checkbox"
- {%+ if recipe.is_published %}
+ {%~ if recipe.is_published %}
checked
{% endif %}
>
{% 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>
-{% 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>
<input type="submit" value="{{ tr.t(Sentence::SignInMenu) }}">
</form>
+
<span class="user-message">{{ message }}</span>
</div>
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) }}">
--- /dev/null
+sass -w scss/style.scss static/style.css
\ No newline at end of file
name = "common"
version = "0.1.0"
authors = ["Grégory Burri <greg.burri@gmail.com>"]
-edition = "2021"
+edition = "2024"
[dependencies]
ron = "0.8"
name = "frontend"
version = "0.1.0"
authors = ["Greg Burri <greg.burri@gmail.com>"]
-edition = "2021"
+edition = "2024"
[lib]
crate-type = ["cdylib"]
--- /dev/null
+// 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),
+}
-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(
}
}
});
-
- Ok(())
}
+use chrono::Local;
use common::ron_api;
use gloo::{console::log, events::EventListener, utils::window};
use utils::by_id;
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;
.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");
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.
})
.forget();
}
-
- Ok(())
}
fn create_group_element(group: &ron_api::Group) -> Element {
-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};
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");
});
})
.forget();
-
- Ok(())
}