Form CSS style + dev panel (WIP)
This commit is contained in:
parent
9daa852add
commit
f2e0aa3b43
18 changed files with 154 additions and 34 deletions
|
|
@ -266,13 +266,54 @@ body {
|
||||||
// width: fit-content;
|
// width: fit-content;
|
||||||
// justify-self: flex-end;
|
// justify-self: flex-end;
|
||||||
// }
|
// }
|
||||||
// }
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
border: 0.1em solid consts.$color-3;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
background-color: consts.$color-1;
|
||||||
|
margin: consts.$margin;
|
||||||
|
padding: consts.$margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea,
|
||||||
|
input {
|
||||||
|
margin: consts.$margin;
|
||||||
|
padding: calc(consts.$margin / 2) calc(2 * consts.$margin);
|
||||||
|
|
||||||
|
background-color: consts.$color-1;
|
||||||
|
border: solid 1px consts.$color-3;
|
||||||
|
color: consts.$text-color;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
background-color: consts.$color-2;
|
||||||
|
box-shadow: 0 0 5px color.adjust(consts.$color-3, $lightness: -20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
margin: consts.$margin;
|
||||||
|
padding: calc(consts.$margin / 2) calc(2 * consts.$margin);
|
||||||
|
|
||||||
|
background-color: consts.$color-1;
|
||||||
|
border: solid 1px consts.$color-3;
|
||||||
|
color: consts.$text-color;
|
||||||
|
|
||||||
|
option {
|
||||||
|
color: inherit;
|
||||||
|
background-color: consts.$color-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="button"],
|
||||||
|
input[type="submit"],
|
||||||
.button {
|
.button {
|
||||||
margin: consts.$margin;
|
margin: consts.$margin;
|
||||||
padding: calc(consts.$margin / 2) calc(2 * consts.$margin);
|
padding: calc(consts.$margin / 2) calc(2 * consts.$margin);
|
||||||
|
|
||||||
border: 0.1em solid consts.$color-3;
|
border: 0.1em solid consts.$color-3;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
background-color: consts.$color-2;
|
background-color: consts.$color-2;
|
||||||
|
|
@ -281,6 +322,8 @@ body {
|
||||||
5px 5px 4px 3px color.adjust(consts.$color-2, $lightness: 4%) inset;
|
5px 5px 4px 3px color.adjust(consts.$color-2, $lightness: 4%) inset;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
color: consts.$link-color;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: consts.$link-hover-color;
|
color: consts.$link-hover-color;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,3 +56,5 @@ pub const REVERSE_PROXY_IP_HTTP_FIELD: &str = "x-real-ip";
|
||||||
|
|
||||||
// To avoid database lock.
|
// To avoid database lock.
|
||||||
pub const MAX_DB_CONNECTION: u32 = 1;
|
pub const MAX_DB_CONNECTION: u32 = 1;
|
||||||
|
|
||||||
|
pub const NOT_AUTHORIZED_MESSAGE: &str = "Action not authorized";
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,13 @@ mod filters {
|
||||||
#[template(path = "home.html")]
|
#[template(path = "home.html")]
|
||||||
pub struct HomeTemplate {
|
pub struct HomeTemplate {
|
||||||
pub context: Context,
|
pub context: Context,
|
||||||
|
pub recipes: Recipes,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "dev_panel.html")]
|
||||||
|
pub struct DevPanelTemplate {
|
||||||
|
pub context: Context,
|
||||||
pub recipes: Recipes,
|
pub recipes: Recipes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@ async fn main() {
|
||||||
|
|
||||||
let html_routes = Router::new()
|
let html_routes = Router::new()
|
||||||
.route("/", get(services::home_page))
|
.route("/", get(services::home_page))
|
||||||
|
.route("/dev_panel", get(services::dev_panel))
|
||||||
.route("/signup", get(services::user::sign_up_get))
|
.route("/signup", get(services::user::sign_up_get))
|
||||||
.route("/validation", get(services::user::sign_up_validation))
|
.route("/validation", get(services::user::sign_up_validation))
|
||||||
.route("/revalidation", get(services::user::email_revalidation))
|
.route("/revalidation", get(services::user::email_revalidation))
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Bytes,
|
body::Bytes,
|
||||||
http::{header, HeaderValue, StatusCode},
|
http::{HeaderValue, StatusCode, header},
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
};
|
};
|
||||||
use common::ron_api;
|
use common::ron_api;
|
||||||
use ron::de::from_bytes;
|
use ron::de::from_bytes;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
|
|
||||||
pub const RON_CONTENT_TYPE: HeaderValue = HeaderValue::from_static("application/ron");
|
pub const RON_CONTENT_TYPE: HeaderValue = HeaderValue::from_static("application/ron");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Context, Result, data::db, html_templates::*, ron_utils};
|
use crate::{Context, Result, consts, data::db, html_templates::*, ron_utils};
|
||||||
|
|
||||||
pub mod fragments;
|
pub mod fragments;
|
||||||
pub mod recipe;
|
pub mod recipe;
|
||||||
|
|
@ -66,15 +66,31 @@ pub async fn home_page(
|
||||||
pub async fn dev_panel(
|
pub async fn dev_panel(
|
||||||
State(connection): State<db::Connection>,
|
State(connection): State<db::Connection>,
|
||||||
Extension(context): Extension<Context>,
|
Extension(context): Extension<Context>,
|
||||||
) -> Result<impl IntoResponse> {
|
) -> Result<Response> {
|
||||||
Ok(Html(
|
if context.user.is_some() && context.user.as_ref().unwrap().is_admin {
|
||||||
HomeTemplate {
|
Ok(Html(
|
||||||
recipes: Recipes::new(connection, &context.user, context.tr.current_lang_code())
|
DevPanelTemplate {
|
||||||
.await?,
|
recipes: Recipes::new(connection, &context.user, context.tr.current_lang_code())
|
||||||
context,
|
.await?,
|
||||||
}
|
context,
|
||||||
.render()?,
|
}
|
||||||
))
|
.render()?,
|
||||||
|
)
|
||||||
|
.into_response())
|
||||||
|
} else {
|
||||||
|
Ok((
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
Html(
|
||||||
|
MessageTemplate::new_with_user(
|
||||||
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
|
context.tr,
|
||||||
|
context.user,
|
||||||
|
)
|
||||||
|
.render()?,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into_response())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///// 404 /////
|
///// 404 /////
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@ use axum::{
|
||||||
response::{ErrorResponse, IntoResponse, Response, Result},
|
response::{ErrorResponse, IntoResponse, Response, Result},
|
||||||
};
|
};
|
||||||
use axum_extra::extract::Query;
|
use axum_extra::extract::Query;
|
||||||
// use tracing::{event, Level};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Context,
|
Context, consts,
|
||||||
data::{self, db},
|
data::{self, db},
|
||||||
ron_extractor::ExtractRon,
|
ron_extractor::ExtractRon,
|
||||||
ron_utils::{ron_error, ron_response_ok},
|
ron_utils::{ron_error, ron_response_ok},
|
||||||
|
|
@ -31,7 +30,7 @@ pub async fn get_scheduled_recipes(
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@ pub mod recipe;
|
||||||
mod rights;
|
mod rights;
|
||||||
pub mod shopping_list;
|
pub mod shopping_list;
|
||||||
|
|
||||||
const NOT_AUTHORIZED_MESSAGE: &str = "Action not authorized";
|
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn set_lang(
|
pub async fn set_lang(
|
||||||
State(connection): State<db::Connection>,
|
State(connection): State<db::Connection>,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
response::{ErrorResponse, Result},
|
response::{ErrorResponse, Result},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{data::db, model, ron_utils::ron_error};
|
use crate::{consts, data::db, model, ron_utils::ron_error};
|
||||||
|
|
||||||
pub async fn check_user_rights_recipe(
|
pub async fn check_user_rights_recipe(
|
||||||
connection: &db::Connection,
|
connection: &db::Connection,
|
||||||
|
|
@ -17,7 +17,7 @@ pub async fn check_user_rights_recipe(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -36,7 +36,7 @@ pub async fn check_user_rights_recipe_group(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -55,7 +55,7 @@ pub async fn check_user_rights_recipe_groups(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -74,7 +74,7 @@ pub async fn check_user_rights_recipe_step(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -93,7 +93,7 @@ pub async fn check_user_rights_recipe_steps(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -112,7 +112,7 @@ pub async fn check_user_rights_recipe_ingredient(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -131,7 +131,7 @@ pub async fn check_user_rights_recipe_ingredients(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -150,7 +150,7 @@ pub async fn check_user_rights_shopping_list_entry(
|
||||||
{
|
{
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use axum::{
|
||||||
use common::ron_api;
|
use common::ron_api;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Context,
|
Context, consts,
|
||||||
data::db,
|
data::db,
|
||||||
model,
|
model,
|
||||||
ron_extractor::ExtractRon,
|
ron_extractor::ExtractRon,
|
||||||
|
|
@ -48,7 +48,7 @@ pub async fn get(
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorResponse::from(ron_error(
|
Err(ErrorResponse::from(ron_error(
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
super::NOT_AUTHORIZED_MESSAGE,
|
consts::NOT_AUTHORIZED_MESSAGE,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@
|
||||||
<span class="user-menu">
|
<span class="user-menu">
|
||||||
{% match context.user %}
|
{% match context.user %}
|
||||||
{% when Some with (user) %}
|
{% when Some with (user) %}
|
||||||
<a class="create-recipe button" href="/recipe/new" >{{ context.tr.t(Sentence::CreateNewRecipe) }}</a>
|
<a class="button" href="/recipe/new" >{{ context.tr.t(Sentence::CreateNewRecipe) }}</a>
|
||||||
|
{% if user.is_admin %}
|
||||||
|
<a class="button" href="/dev_panel">Dev panel</a>
|
||||||
|
{% endif %}
|
||||||
<a href="/{{ context.tr.current_lang_code() }}/user/edit">
|
<a href="/{{ context.tr.current_lang_code() }}/user/edit">
|
||||||
{% if user.name == "" %}
|
{% if user.name == "" %}
|
||||||
{{ user.email }}
|
{{ user.email }}
|
||||||
|
|
|
||||||
17
backend/templates/dev_panel.html
Normal file
17
backend/templates/dev_panel.html
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "base_with_list.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="content" id="dev_panel">
|
||||||
|
<input type="button" class="button" id="test-toast" value="Test toast">
|
||||||
|
<input type="button" class="button" id="test-modal-dialog" value="Test modal">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="hidden-templates">
|
||||||
|
|
||||||
|
<div class="modal-test-message">
|
||||||
|
This is a message.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -7,11 +7,11 @@
|
||||||
|
|
||||||
{% if let Some(user) = context.user %}
|
{% if let Some(user) = context.user %}
|
||||||
{% if crate::data::model::can_user_edit_recipe(user, recipe) %}
|
{% if crate::data::model::can_user_edit_recipe(user, recipe) %}
|
||||||
<a class="edit-recipe" href="/{{ context.tr.current_lang_code() }}/recipe/edit/{{ recipe.id }}" >Edit</a>
|
<a class="edit-recipe button" href="/{{ context.tr.current_lang_code() }}/recipe/edit/{{ recipe.id }}" >Edit</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<span class="add-to-planner">{{ context.tr.t(Sentence::CalendarAddToPlanner) }}</span>
|
<span class="add-to-planner button">{{ context.tr.t(Sentence::CalendarAddToPlanner) }}</span>
|
||||||
|
|
||||||
<div class="tags">
|
<div class="tags">
|
||||||
{% for tag in recipe.tags %}
|
{% for tag in recipe.tags %}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ pub fn main() -> Result<(), JsValue> {
|
||||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
||||||
pages::recipe_view::setup_page(id, is_user_logged)
|
pages::recipe_view::setup_page(id, is_user_logged)
|
||||||
}
|
}
|
||||||
|
["dev_panel"] => pages::dev_panel::setup_page(),
|
||||||
// Home.
|
// Home.
|
||||||
[""] => pages::home::setup_page(is_user_logged),
|
[""] => pages::home::setup_page(is_user_logged),
|
||||||
_ => log!("Path unknown: ", location),
|
_ => log!("Path unknown: ", location),
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,18 @@ use web_sys::{Element, HtmlDialogElement};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
on_click,
|
on_click,
|
||||||
utils::{by_id, selector_and_clone, SelectorExt},
|
utils::{SelectorExt, by_id, selector_and_clone},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Show a modal dialog with a copy of the given HTML element as content.
|
||||||
pub async fn show(element_selector: &str) -> bool {
|
pub async fn show(element_selector: &str) -> bool {
|
||||||
show_and_initialize(element_selector, async |_| Some(()))
|
show_and_initialize(element_selector, async |_| Some(()))
|
||||||
.await
|
.await
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show a modal dialog with a copy of the given HTML element as content and execute an initilizer
|
||||||
|
/// to modify the given content.
|
||||||
pub async fn show_and_initialize<T, U>(element_selector: &str, initializer: T) -> Option<U>
|
pub async fn show_and_initialize<T, U>(element_selector: &str, initializer: T) -> Option<U>
|
||||||
where
|
where
|
||||||
T: AsyncFn(Element) -> U,
|
T: AsyncFn(Element) -> U,
|
||||||
|
|
@ -19,6 +22,9 @@ where
|
||||||
show_and_initialize_with_ok(element_selector, initializer, |_, result| result).await
|
show_and_initialize_with_ok(element_selector, initializer, |_, result| result).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show a modal dialog with a copy of the given HTML element as content and execute an initilizer
|
||||||
|
/// to modify the given content.
|
||||||
|
/// Call the given function when OK is pressed.
|
||||||
pub async fn show_and_initialize_with_ok<T, V, W, U>(
|
pub async fn show_and_initialize_with_ok<T, V, W, U>(
|
||||||
element_selector: &str,
|
element_selector: &str,
|
||||||
initializer: T,
|
initializer: T,
|
||||||
|
|
|
||||||
26
frontend/src/pages/dev_panel.rs
Normal file
26
frontend/src/pages/dev_panel.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
use gloo::{console::log, events::EventListener};
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen_futures::spawn_local;
|
||||||
|
use web_sys::{Element, HtmlInputElement};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
calendar, modal_dialog,
|
||||||
|
recipe_scheduler::RecipeScheduler,
|
||||||
|
shopping_list::ShoppingList,
|
||||||
|
toast::{self, Level},
|
||||||
|
utils::{SelectorExt, by_id, get_current_lang, get_locale, selector},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn setup_page() {
|
||||||
|
EventListener::new(&by_id("test-toast"), "click", move |_event| {
|
||||||
|
toast::show_message(Level::Info, "This is a message");
|
||||||
|
})
|
||||||
|
.forget();
|
||||||
|
|
||||||
|
EventListener::new(&by_id("test-modal-dialog"), "click", move |_event| {
|
||||||
|
spawn_local(async move {
|
||||||
|
modal_dialog::show("#hidden-templates").await;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.forget();
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod dev_panel;
|
||||||
pub mod home;
|
pub mod home;
|
||||||
pub mod recipe_edit;
|
pub mod recipe_edit;
|
||||||
pub mod recipe_view;
|
pub mod recipe_view;
|
||||||
|
|
|
||||||
|
|
@ -446,6 +446,7 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let tag_span = document().create_element("span").unwrap();
|
let tag_span = document().create_element("span").unwrap();
|
||||||
|
tag_span.set_class_name("tag");
|
||||||
tag_span.set_inner_html(&tag);
|
tag_span.set_inner_html(&tag);
|
||||||
let delete_tag_button: HtmlInputElement = document()
|
let delete_tag_button: HtmlInputElement = document()
|
||||||
.create_element("input")
|
.create_element("input")
|
||||||
|
|
@ -453,7 +454,7 @@ where
|
||||||
.dyn_into()
|
.dyn_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
delete_tag_button.set_attribute("type", "button").unwrap();
|
delete_tag_button.set_attribute("type", "button").unwrap();
|
||||||
delete_tag_button.set_attribute("value", "X").unwrap();
|
delete_tag_button.set_attribute("value", "✖").unwrap();
|
||||||
tag_span.append_child(&delete_tag_button).unwrap();
|
tag_span.append_child(&delete_tag_button).unwrap();
|
||||||
tags_span.append_child(&tag_span).unwrap();
|
tags_span.append_child(&tag_span).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue