A bit of clean up
This commit is contained in:
parent
cb2483eab1
commit
a590d7e1e9
24 changed files with 259 additions and 237 deletions
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
margin: 0;
|
||||
|
||||
&.current-month {
|
||||
background-color: blue;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
&.today {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
<input type="submit" value="{{ tr.t(Sentence::SignInMenu) }}">
|
||||
</form>
|
||||
|
||||
<span class="user-message">{{ message }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
1
backend/watch_scss.nu
Normal file
|
|
@ -0,0 +1 @@
|
|||
sass -w scss/style.scss static/style.css
|
||||
Loading…
Add table
Add a link
Reference in a new issue