Create form

This commit is contained in:
Adrian Woźniak 2024-10-30 16:59:15 +01:00
parent d8830fbbc0
commit afc77b5c3d
5 changed files with 1869 additions and 19 deletions

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@ use serde::Deserialize;
struct RecipeCard(entities::recipies::Model); struct RecipeCard(entities::recipies::Model);
#[derive(Debug, Template)] #[derive(Debug, Template)]
#[template(path = "index.jinja")] #[template(path = "index.jinja", ext = "html")]
struct IndexTemplate { struct IndexTemplate {
recipies: Vec<RecipeCard>, recipies: Vec<RecipeCard>,
count: u64, count: u64,
@ -24,7 +24,7 @@ struct IndexTemplate {
} }
#[derive(Debug, Template)] #[derive(Debug, Template)]
#[template(path = "search.jinja")] #[template(path = "search.jinja", ext = "html")]
struct SearchTemplate { struct SearchTemplate {
recipies: Vec<RecipeCard>, recipies: Vec<RecipeCard>,
count: u64, count: u64,
@ -34,7 +34,7 @@ struct SearchTemplate {
} }
#[derive(Debug, Template)] #[derive(Debug, Template)]
#[template(path = "top_bar.jinja")] #[template(path = "top_bar.jinja", ext = "html")]
struct TopBar<'s> { struct TopBar<'s> {
session: &'s Option<User>, session: &'s Option<User>,
} }
@ -46,7 +46,7 @@ impl<'s> TopBar<'s> {
} }
#[derive(Debug, Template)] #[derive(Debug, Template)]
#[template(path = "sign_in/form.jinja")] #[template(path = "sign_in/form.jinja", ext = "html")]
struct SignInForm { struct SignInForm {
not_found: bool, not_found: bool,
email: String, email: String,
@ -54,6 +54,19 @@ struct SignInForm {
page: Page, page: Page,
} }
#[derive(Debug, Template)]
#[template(path = "recipies/create_form.jinja", ext = "html")]
struct RecipeForm {
title: String,
summary: String,
ingeredients: String,
steps: String,
tags: String,
error: Option<String>,
session: Option<User>,
page: Page,
}
#[get("/sign-in")] #[get("/sign-in")]
async fn render_sign_in() -> SignInForm { async fn render_sign_in() -> SignInForm {
SignInForm { SignInForm {
@ -209,7 +222,7 @@ async fn index_html(
} }
#[derive(Debug, Template)] #[derive(Debug, Template)]
#[template(path = "recipies/show.jinja")] #[template(path = "recipies/show.jinja", ext = "html")]
struct RecipeDetailTemplate { struct RecipeDetailTemplate {
recipe: entities::recipies::Model, recipe: entities::recipies::Model,
tags: Vec<entities::recipe_tags::Model>, tags: Vec<entities::recipe_tags::Model>,
@ -266,6 +279,20 @@ async fn show(
) )
} }
#[get("/create")]
async fn recipe_form(admin: Identity) -> RecipeForm {
RecipeForm {
title: "".into(),
summary: "".into(),
ingeredients: "".into(),
steps: "".into(),
tags: "".into(),
error: None,
session: admin.id().ok(),
page: Page::Index,
}
}
#[get("/styles.css")] #[get("/styles.css")]
async fn styles_css() -> HttpResponse { async fn styles_css() -> HttpResponse {
HttpResponse::Ok() HttpResponse::Ok()
@ -281,5 +308,6 @@ pub fn configure(config: &mut actix_web::web::ServiceConfig) {
.service(index_html) .service(index_html)
.service(show) .service(show)
.service(search_page) .service(search_page)
.service(search_results); .service(search_results)
.service(recipe_form);
} }

View File

@ -1,6 +1,9 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
content: ["./templates/**/*.html"], content: [
"./templates/**/*.html",
"./templates/**/*.jinja",
],
theme: { theme: {
extend: { extend: {
colors: { colors: {

View File

@ -1,5 +1,9 @@
{% extends "base.jinja" %} {% extends "base.jinja" %}
{% block head %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.3/marked.min.js" integrity="sha512-kZ9BCD8vqCw2vJ1XG3EVZN5M5aRNxxMK3+uYuZPWc+TtW2Z1zSgmFlTIVHYHaWH0bH2lp2dUlB/1+M1h+lvfeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{% endblock %}
{% block content %} {% block content %}
<main class="md:col-span-3 flex flex-col gap-4 m-4 w-full"> <main class="md:col-span-3 flex flex-col gap-4 m-4 w-full">
{{ TopBar::new(session)|safe }} {{ TopBar::new(session)|safe }}
@ -9,29 +13,77 @@
</header> </header>
<div class="flex flex-col gap-8"> <div class="flex flex-col gap-8">
<div class="flex flex-wrap gap-8 justify-center"> <div class="flex flex-wrap gap-8 justify-center">
<form action="/search" method="post" class="flex flex-col gap-4"> <form action="/create" method="post" class="flex flex-col gap-4 md:w-1/2 md:mb-10">
<label for="title" class="flex gap-4"> <label for="title" class="flex gap-4">
<span>Title:</span> <span class="w-24 shrink-0">Title:</span>
<input id="title" name="title" class="input border border-solid border-gray-200 rounded-lg" type="search" value="{{title}}" /> <input id="title" name="title" class="input border border-solid border-gray-200 rounded-lg" type="text" value="{{title}}" />
</label> </label>
<label for="summary" class="flex gap-4"> <label for="summary" class="flex gap-4">
<span>Summary:</span> <span class="w-24 shrink-0">Summary:</span>
<textarea id="summary" name="summary" class="input border border-solid border-gray-200 rounded-lg" type="search" value="{{summary}}" /> <div class="flex gap-2 w-full">
<textarea id="summary" name="summary" class="textarea-with-view">{{summary}}</textarea>
<div class="content w-1/2"></div>
</div>
</label> </label>
<blockquote class="w-full">
<p class="text-base font-semibold">Summary supports Markdown</p>
</blockquote>
<label for="ingeredients" class="flex gap-4"> <label for="ingeredients" class="flex gap-4">
<span>Ingeredients:</span> <span class="w-24 shrink-0">Ingeredients:</span>
<textarea id="ingeredients" name="ingeredients" class="input border border-solid border-gray-200 rounded-lg" type="search" value="{{summary}}" /> <div class="flex gap-2 w-full">
<textarea id="ingeredients" name="ingeredients" class="textarea-without-view">{{ingeredients}}</textarea>
</div>
</label> </label>
<details class="w-full collapse collapse-arrow">
<summary class="text-base font-semibold collapse-title">Ingeredients should be listed as list of AMOUNT UNIT INGEREDIENT. Example:</summary>
<div class="flex flex-col gap-1 font-normal collapse-content">
<div>1 KG Potato</div>
<div>200 G Sugar</div>
<div>3 Bananas</div>
</div>
</details>
<label for="steps" class="flex gap-4"> <label for="steps" class="flex gap-4">
<span>Steps:</span> <span class="w-24 shrink-0">Steps:</span>
<textarea id="steps" name="steps" class="input border border-solid border-gray-200 rounded-lg" type="search" value="{{summary}}" /> <div class="flex gap-2 w-full">
<textarea id="steps" name="steps" class="textarea-with-view">{{steps}}</textarea>
<div class="content w-1/2"></div>
</div>
</label> </label>
<div></div>
<details class="w-full">
<summary class="text-base font-semibold">Syntax for steps:</summary>
<div>
<p class="text-base"><code>*</code> is step</p>
<p class="text-base"><code>&gt;</code> is hint for step</p>
</div>
</details>
<label for="tags" class="flex gap-4"> <label for="tags" class="flex gap-4">
<span>Tags:</span> <span class="w-24 shrink-0">Tags:</span>
<textarea id="tags" name="tags" class="input border border-solid border-gray-200 rounded-lg" type="search" value="{{summary}}" /> <div class="flex gap-2 w-full">
<textarea id="tags" name="tags" class="textarea-with-view">{{tags}}</textarea>
<div class="content w-1/2">&nbsp;</div>
</div>
</label> </label>
<div>
<input type="submit" class="btn w-full" value="Save" />
</div>
</form> </form>
<script type="module">
Array.from(document.body.querySelectorAll('textarea')).forEach(el => {
if (!el.parentElement.querySelector('.content')) return;
el.parentElement.querySelector('div').innerHTML = marked.parse(el.value);
el.addEventListener('keyup', () => {
el.parentElement.querySelector('div').innerHTML = marked.parse(el.value);
});
});
</script>
</div> </div>
</div> </div>
</main> </main>

View File

@ -39,3 +39,22 @@
.text-mobile-heading-xxl { .text-mobile-heading-xxl {
@apply text-5xl not-italic font-medium; @apply text-5xl not-italic font-medium;
} }
blockquote {
@apply p-4 my-4 border-s-4 border-gray-300 bg-gray-200 text-xl italic font-medium leading-relaxed text-gray-900 border-0 rounded-lg flex flex-col gap-4;
}
code {
@apply bg-gray-400 text-white py-1 px-2 border-0 rounded-full;
}
.content ul {
@apply list-inside list-decimal;
}
.textarea-with-view {
@apply min-h-40 input border border-solid border-gray-200 rounded-lg w-1/2;
}
.textarea-without-view {
@apply min-h-40 input border border-solid border-gray-200 rounded-lg w-full;
}