Add tmpl.js
This commit is contained in:
parent
99fc54eea9
commit
747db9602d
@ -1349,6 +1349,13 @@ pub async fn health() -> HttpResponse {
|
|||||||
HttpResponse::Ok().finish()
|
HttpResponse::Ok().finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/tmpl.js")]
|
||||||
|
async fn tmpl() -> HttpResponse {
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.append_header(("Content-Type", "application/javascript"))
|
||||||
|
.body(include_str!("../templates/tmpl.js").to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn configure(config: &mut actix_web::web::ServiceConfig) {
|
pub fn configure(config: &mut actix_web::web::ServiceConfig) {
|
||||||
tmp_cleanup();
|
tmp_cleanup();
|
||||||
|
|
||||||
@ -1374,5 +1381,6 @@ pub fn configure(config: &mut actix_web::web::ServiceConfig) {
|
|||||||
.service(no_ads)
|
.service(no_ads)
|
||||||
.service(no_sellers)
|
.service(no_sellers)
|
||||||
.service(health)
|
.service(health)
|
||||||
|
.service(tmpl)
|
||||||
.service(Files::new("/assets", "./assets"));
|
.service(Files::new("/assets", "./assets"));
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/styles.css">
|
<link rel="stylesheet" href="/styles.css">
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
||||||
|
<script type="module" src="/tmpl.js"></script>
|
||||||
<title>Cooked</title>
|
<title>Cooked</title>
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
@ -42,6 +42,10 @@
|
|||||||
<textarea id="ingredients" name="ingredients" class="textarea-without-view" required>{{ingredients}}</textarea>
|
<textarea id="ingredients" name="ingredients" class="textarea-without-view" required>{{ingredients}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
{% include "recipies/ingredients-list.jinja" %}
|
||||||
|
|
||||||
|
|
||||||
<div class="w-full flex gap-4 flex-wrap">
|
<div class="w-full flex gap-4 flex-wrap">
|
||||||
{% for ingredient in known_ingredients %}
|
{% for ingredient in known_ingredients %}
|
||||||
<label class="border rounded-lg p-2 styled-checkbox cursor-pointer">
|
<label class="border rounded-lg p-2 styled-checkbox cursor-pointer">
|
||||||
@ -49,6 +53,9 @@
|
|||||||
</label>
|
</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
{% include "recipies/ingredients-list.jinja" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<details class="w-full collapse collapse-arrow">
|
<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>
|
<summary class="text-base font-semibold collapse-title">Ingeredients should be listed as list of AMOUNT UNIT INGEREDIENT. Example:</summary>
|
||||||
|
35
cooked/templates/recipies/ingredients-list.jinja
Normal file
35
cooked/templates/recipies/ingredients-list.jinja
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<div id="ingredients-list" class="tmpl-wrapper flex flex-col gap-4">
|
||||||
|
<label for="ingredient" class="flex gap-4">
|
||||||
|
<div class="flex gap-2 w-full">
|
||||||
|
<input name="ingredient[][qty]" placeholder="Quantity" type="number" class="input border border-solid border-gray-200 rounded-lg" required/>
|
||||||
|
<input name="ingredient[][unit]" placeholder="Unit" class="input border border-solid border-gray-200 rounded-lg"/>
|
||||||
|
<input name="ingredient[][name]" placeholder="Name" class="input border border-solid border-gray-200 rounded-lg" required/>
|
||||||
|
<input name="ingredient[][sidenote]" placeholder="Sidenote" class="input border border-solid border-gray-200 rounded-lg"/>
|
||||||
|
|
||||||
|
<button class="input border border-solid border-gray-200 rounded-lg tmpl-adder tmpl-swap-before" data-tmpl-swap="#remove">
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<template class="tmpl-row">
|
||||||
|
<label for="ingredient" class="flex gap-4 tmpl-row">
|
||||||
|
<div class="flex gap-2 w-full">
|
||||||
|
<input name="ingredient[][qty]" placeholder="Quantity" type="number" class="input border border-solid border-gray-200 rounded-lg" required/>
|
||||||
|
<input name="ingredient[][unit]" placeholder="Unit" class="input border border-solid border-gray-200 rounded-lg"/>
|
||||||
|
<input name="ingredient[][name]" placeholder="Name" class="input border border-solid border-gray-200 rounded-lg" required/>
|
||||||
|
<input name="ingredient[][sidenote]" placeholder="Sidenote" class="input border border-solid border-gray-200 rounded-lg"/>
|
||||||
|
|
||||||
|
<button class="input border border-solid border-gray-200 rounded-lg tmpl-adder tmpl-swap-before" data-tmpl-swap="#remove">
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template class="tmpl-swap" id="remove">
|
||||||
|
<button class="input border border-solid border-gray-200 rounded-lg tmpl-wrapper-rm" data-tmpl-wrapper-rm="label:has(div > button.tmpl-wrapper-rm)">
|
||||||
|
-
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
75
cooked/templates/tmpl.js
Normal file
75
cooked/templates/tmpl.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* <template> framework
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```html
|
||||||
|
* <div class="tmpl-wrapper">
|
||||||
|
* <input class="tmpl-adder" />
|
||||||
|
* <template>
|
||||||
|
* <div>Some content to add</div>
|
||||||
|
* </template>
|
||||||
|
* </div>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
const setup_wrapper = (wrapper) => {
|
||||||
|
const template = wrapper.querySelector("template.tmpl-row");
|
||||||
|
const adder = wrapper.querySelector(".tmpl-adder");
|
||||||
|
const receiver = wrapper.querySelector(".tmpl-receiver") || wrapper;
|
||||||
|
|
||||||
|
wrapper.addEventListener("click", (ev) => {
|
||||||
|
if (!ev.target.classList.contains('tmpl-adder')) return;
|
||||||
|
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
const content = template.content.cloneNode(true);
|
||||||
|
template.dispatchEvent(new CustomEvent('tmpl:cloned', { detail: { content } }));
|
||||||
|
template.dispatchEvent(new CustomEvent('tmpl:before-append', { detail: { content, receiver } }));
|
||||||
|
|
||||||
|
Array.from(wrapper.querySelectorAll('.tmpl-rm-before')).forEach(el => el.remove());
|
||||||
|
|
||||||
|
receiver.appendChild(content);
|
||||||
|
template.dispatchEvent(new CustomEvent('tmpl:after-append', { detail: { content, receiver } }));
|
||||||
|
|
||||||
|
Array.from(wrapper.querySelectorAll('.tmpl-rm-after')).forEach(el => el.remove());
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.addEventListener('click', ev => {
|
||||||
|
if (!ev.target.classList.contains('tmpl-wrapper-rm')) return;
|
||||||
|
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
const selector = ev.target.dataset.tmplWrapperRm;
|
||||||
|
if (!selector) return;
|
||||||
|
|
||||||
|
const child = wrapper.querySelector(selector);
|
||||||
|
if (!child) return;
|
||||||
|
child.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.addEventListener('click', ev => {
|
||||||
|
if (!ev.target.classList.contains('tmpl-swap-before')) return;
|
||||||
|
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
const current = ev.target;
|
||||||
|
const parent = current.parentElement;
|
||||||
|
if (!parent) return;
|
||||||
|
const selector = ev.target.dataset.tmplSwap;
|
||||||
|
if (!selector) return;
|
||||||
|
const swapTemplate = wrapper.querySelector(`template${selector}`);
|
||||||
|
if (!swapTemplate) return;
|
||||||
|
const newNode = swapTemplate.content.cloneNode(true);
|
||||||
|
parent.replaceChild(newNode, current);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const mount = () => {
|
||||||
|
Array.from(document.body.querySelectorAll('.tmpl-wrapper') || []).forEach(wrapper => {
|
||||||
|
setup_wrapper(wrapper);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
document.addEventListener("DOMContentLoaded", mount);
|
Loading…
Reference in New Issue
Block a user