A bit of clean up

This commit is contained in:
Greg Burri 2025-03-02 00:39:58 +01:00
parent cb2483eab1
commit a590d7e1e9
24 changed files with 259 additions and 237 deletions

View 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" }

View file

@ -43,7 +43,7 @@
margin: 0;
&.current-month {
background-color: blue;
background-color: green;
}
&.today {

View 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 {
// }
}
}

View 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])

View 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)

View 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| {

View 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);
}
}

View 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 %}

View 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>

View file

@ -18,13 +18,13 @@
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
@ -33,18 +33,20 @@
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 %}

View file

@ -42,10 +42,10 @@
<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 %}
>

View file

@ -33,7 +33,7 @@
{% match recipe.estimated_time %}
{% when Some(time) %}
{{ time +}} {{+ tr.t(Sentence::RecipeEstimatedTimeMinAbbreviation) }}
{{ time ~}} {{~ tr.t(Sentence::RecipeEstimatedTimeMinAbbreviation) }}
{% else %}
{% endmatch %}
@ -65,10 +65,10 @@
{% 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>

View 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>

View file

@ -16,6 +16,7 @@
<input type="submit" value="{{ tr.t(Sentence::SignInMenu) }}">
</form>
<span class="user-message">{{ message }}</span>
</div>

View file

@ -12,17 +12,16 @@
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) }}">

1
backend/watch_scss.nu Normal file
View file

@ -0,0 +1 @@
sass -w scss/style.scss static/style.css