Fix translations

This commit is contained in:
Adrian Woźniak 2023-10-11 13:48:38 +02:00
parent d4135d425f
commit 9329c57970
12 changed files with 117 additions and 130 deletions

View File

@ -1203,11 +1203,6 @@ select {
line-height: 1; line-height: 1;
} }
.text-blue-400 {
--tw-text-opacity: 1;
color: rgb(96 165 250 / var(--tw-text-opacity));
}
.text-emerald-500 { .text-emerald-500 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(16 185 129 / var(--tw-text-opacity)); color: rgb(16 185 129 / var(--tw-text-opacity));
@ -1305,11 +1300,6 @@ select {
transition-timing-function: linear; transition-timing-function: linear;
} }
.hover\:bg-blue-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(191 219 254 / var(--tw-bg-opacity));
}
.hover\:bg-gray-100:hover { .hover\:bg-gray-100:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity)); background-color: rgb(243 244 246 / var(--tw-bg-opacity));
@ -1325,11 +1315,6 @@ select {
background-color: rgb(254 240 138 / var(--tw-bg-opacity)); background-color: rgb(254 240 138 / var(--tw-bg-opacity));
} }
.hover\:text-blue-900:hover {
--tw-text-opacity: 1;
color: rgb(30 58 138 / var(--tw-text-opacity));
}
.hover\:text-neutral-700:hover { .hover\:text-neutral-700:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(64 64 64 / var(--tw-text-opacity)); color: rgb(64 64 64 / var(--tw-text-opacity));
@ -1466,11 +1451,6 @@ select {
color: rgb(156 163 175 / var(--tw-placeholder-opacity)); color: rgb(156 163 175 / var(--tw-placeholder-opacity));
} }
.dark\:hover\:bg-blue-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
}
.dark\:hover\:bg-gray-600:hover { .dark\:hover\:bg-gray-600:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity)); background-color: rgb(75 85 99 / var(--tw-bg-opacity));
@ -1491,11 +1471,6 @@ select {
background-color: rgb(133 77 14 / var(--tw-bg-opacity)); background-color: rgb(133 77 14 / var(--tw-bg-opacity));
} }
.dark\:hover\:text-blue-300:hover {
--tw-text-opacity: 1;
color: rgb(147 197 253 / var(--tw-text-opacity));
}
.dark\:hover\:text-neutral-400:hover { .dark\:hover\:text-neutral-400:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity)); color: rgb(163 163 163 / var(--tw-text-opacity));

View File

@ -3,14 +3,17 @@ use actix_web::web::{scope, Data, Form, Path, ServiceConfig};
use actix_web::{get, post, put, HttpRequest, HttpResponse}; use actix_web::{get, post, put, HttpRequest, HttpResponse};
use askama_actix::Template; use askama_actix::Template;
use autometrics::autometrics; use autometrics::autometrics;
use oswilno_contract::parking_space_locations::Model as ParkingSpaceLocation;
use oswilno_contract::parking_space_rents; use oswilno_contract::parking_space_rents;
use oswilno_contract::parking_space_rents::Model as ParkingSpaceRent;
use oswilno_contract::parking_spaces; use oswilno_contract::parking_spaces;
use oswilno_contract::parking_spaces::Model as ParkingSpace;
use oswilno_contract::sea_orm_active_enums::ParkingSpaceState; use oswilno_contract::sea_orm_active_enums::ParkingSpaceState;
use oswilno_contract::{accounts, parking_space_locations}; use oswilno_contract::{accounts, parking_space_locations};
use oswilno_session::{Authenticated, MaybeAuthenticated}; use oswilno_session::{Authenticated, MaybeAuthenticated};
use oswilno_view::{ use oswilno_view::{
filters, is_partial, Blank, Errors, HelperContext, Lang, Layout, Main, MainOpts, SearchOpts, filters, is_partial, Blank, Errors, HelperContext, Layout, Main, MainOpts, SearchOpts,
SessionOpts, TranslationStorage, SessionOpts,
}; };
use sea_orm::prelude::*; use sea_orm::prelude::*;
use sea_orm::ActiveValue::{NotSet, Set}; use sea_orm::ActiveValue::{NotSet, Set};
@ -46,6 +49,10 @@ pub fn translations(l10n: &mut oswilno_view::TranslationStorage) {
.add("Location", "Miejsce") .add("Location", "Miejsce")
.add("Spot", "Miejsce postojowe") .add("Spot", "Miejsce postojowe")
.add("Register parking space", "Zarejestruj miejsce postojowe") .add("Register parking space", "Zarejestruj miejsce postojowe")
.add("Owned parking spaces", "Posiadane miejsca postojowe")
.add("Pending", "Oczekuje na akceptację")
.add("Approved", "Zaakceptowane")
.add("Rejected", "Odrzucone")
.done(); .done();
} }
@ -62,8 +69,8 @@ async fn root() -> HttpResponse {
#[template(path = "../templates/parking-spaces/all-partial.html")] #[template(path = "../templates/parking-spaces/all-partial.html")]
struct AllPartialParkingSpace { struct AllPartialParkingSpace {
parking_space_rents: Vec<parking_space_rents::Model>, parking_space_rents: Vec<parking_space_rents::Model>,
parking_space_by_id: BTreeMap<i32, Rc<parking_spaces::Model>>, parking_space_by_id: BTreeMap<i32, Rc<ParkingSpace>>,
parking_spaces: Vec<Rc<parking_spaces::Model>>, parking_spaces: Vec<Rc<ParkingSpace>>,
account_by_id: BTreeMap<i32, accounts::Model>, account_by_id: BTreeMap<i32, accounts::Model>,
#[allow(dead_code)] #[allow(dead_code)]
locations: Vec<Rc<parking_space_locations::Model>>, locations: Vec<Rc<parking_space_locations::Model>>,
@ -88,7 +95,7 @@ async fn all_parking_spaces(
tracing::debug!("session {session:?}"); tracing::debug!("session {session:?}");
let mut parking_spaces = load_parking_spaces(db, account_id, htx).await; let mut parking_spaces = load_parking_spaces(db, account_id, hcx.clone()).await;
parking_spaces.session = session.clone(); parking_spaces.session = session.clone();
let main = Main { let main = Main {
body: parking_spaces, body: parking_spaces,
@ -101,6 +108,7 @@ async fn all_parking_spaces(
}), }),
..Default::default() ..Default::default()
}, },
hcx: hcx.clone(),
}; };
HttpResponse::Ok() HttpResponse::Ok()
.append_header(("HX-Retarget", "main")) .append_header(("HX-Retarget", "main"))
@ -215,7 +223,7 @@ async fn form_show(
form: Default::default(), form: Default::default(),
locations: load_locations(db.clone()).await, locations: load_locations(db.clone()).await,
errors: Default::default(), errors: Default::default(),
hcx, hcx: hcx.clone(),
}; };
let main = Main { let main = Main {
body, body,
@ -225,6 +233,7 @@ async fn form_show(
search: None, search: None,
session: Some(session), session: Some(session),
}, },
hcx: hcx.clone(),
}; };
let html = if is_partial(&req) { let html = if is_partial(&req) {
main.render() main.render()
@ -341,10 +350,9 @@ async fn ensure_locations(db: Arc<sea_orm::DatabaseConnection>) {
async fn edit_show( async fn edit_show(
req: HttpRequest, req: HttpRequest,
session: Authenticated, session: Authenticated,
t: Data<TranslationStorage>,
lang: Lang,
db: Data<DatabaseConnection>, db: Data<DatabaseConnection>,
id: Path<i32>, id: Path<i32>,
hcx: HelperContext,
) -> HttpResponse { ) -> HttpResponse {
let db = db.into_inner(); let db = db.into_inner();
let id = id.into_inner(); let id = id.into_inner();
@ -368,9 +376,8 @@ async fn edit_show(
id: Some(id), id: Some(id),
}, },
locations: load_locations(db.clone()).await, locations: load_locations(db.clone()).await,
lang,
errors: Default::default(), errors: Default::default(),
t: t.into_inner(), hcx: hcx.clone(),
}; };
let main = Main { let main = Main {
body, body,
@ -380,6 +387,7 @@ async fn edit_show(
search: None, search: None,
session: Some(session), session: Some(session),
}, },
hcx: hcx.clone(),
}; };
let html = if is_partial(&req) { let html = if is_partial(&req) {
main.render() main.render()
@ -397,8 +405,7 @@ async fn update(
db: Data<sea_orm::DatabaseConnection>, db: Data<sea_orm::DatabaseConnection>,
p: Form<CreateParkingSpace>, p: Form<CreateParkingSpace>,
session: Authenticated, session: Authenticated,
t: Data<TranslationStorage>, hcx: HelperContext,
lang: Lang,
) -> HttpResponse { ) -> HttpResponse {
use oswilno_contract::parking_spaces::*; use oswilno_contract::parking_spaces::*;
let CreateParkingSpace { let CreateParkingSpace {
@ -442,10 +449,9 @@ async fn update(
spot, spot,
id: Some(id), id: Some(id),
}, },
t: t.into_inner(),
lang,
errors: Default::default(), errors: Default::default(),
locations: load_locations(db.clone()).await, locations: load_locations(db.clone()).await,
hcx,
} }
.render() .render()
.unwrap(), .unwrap(),
@ -469,10 +475,9 @@ struct ParkingSpaceRentForm {
#[template(path = "../templates/parking-space-rents/form.html")] #[template(path = "../templates/parking-space-rents/form.html")]
struct ParkingSpaceRentFormTemplate { struct ParkingSpaceRentFormTemplate {
pub form: ParkingSpaceRentForm, pub form: ParkingSpaceRentForm,
pub parking_space: oswilno_contract::parking_spaces::Model, pub parking_space: ParkingSpace,
pub location: oswilno_contract::parking_space_locations::Model, pub location: ParkingSpaceLocation,
lang: Lang, hcx: HelperContext,
t: Arc<TranslationStorage>,
} }
#[get("/{parking_space_id}/parking-space-rents/form")] #[get("/{parking_space_id}/parking-space-rents/form")]
@ -481,14 +486,11 @@ async fn parking_space_rent_form(
db: Data<sea_orm::DatabaseConnection>, db: Data<sea_orm::DatabaseConnection>,
session: MaybeAuthenticated, session: MaybeAuthenticated,
parking_space_id: Path<i32>, parking_space_id: Path<i32>,
t: Data<TranslationStorage>, hcx: HelperContext,
lang: Lang,
) -> HttpResponse { ) -> HttpResponse {
let parking_space_id = parking_space_id.into_inner(); let parking_space_id = parking_space_id.into_inner();
let db = db.into_inner(); let db = db.into_inner();
let session = session.into_option();
let _account_id = session.as_ref().map(|s| s.account_id()); let _account_id = session.as_ref().map(|s| s.account_id());
let session = session.map(Into::into);
let parking_space = { let parking_space = {
use ::oswilno_contract::parking_spaces::{Column, Entity}; use ::oswilno_contract::parking_spaces::{Column, Entity};
let res = Entity::find() let res = Entity::find()
@ -524,27 +526,14 @@ async fn parking_space_rent_form(
} }
} }
}; };
let body = ParkingSpaceRentFormTemplate { let html = render_rent_form(
ParkingSpaceRentForm::default(),
&req,
parking_space, parking_space,
location, location,
form: ParkingSpaceRentForm::default(), session,
lang, hcx,
t: t.into_inner(), );
};
let main = Main {
body,
title: Blank,
opts: MainOpts {
show: true,
search: None,
session,
},
};
let html = if is_partial(&req) {
main.render()
} else {
Layout { main }.render()
};
HttpResponse::Ok() HttpResponse::Ok()
.append_header(( .append_header((
"HX-Redirect", "HX-Redirect",
@ -555,7 +544,7 @@ async fn parking_space_rent_form(
.as_str(), .as_str(),
)) ))
.append_header(("HX-Retarget", "main")) .append_header(("HX-Retarget", "main"))
.body(html.unwrap()) .body(html)
} }
#[get("/{parking_space_id}/parking-space-rents/edit/{id}")] #[get("/{parking_space_id}/parking-space-rents/edit/{id}")]
async fn parking_space_rent_edit(_id: Path<i32>) -> HttpResponse { async fn parking_space_rent_edit(_id: Path<i32>) -> HttpResponse {
@ -574,13 +563,19 @@ async fn parking_space_rent_update(form: Form<ParkingSpaceRentForm>) -> HttpResp
todo!() todo!()
} }
fn render_rent_form(form: ParkingSpaceRentForm, req: &HttpRequest) -> String { fn render_rent_form(
form: ParkingSpaceRentForm,
req: &HttpRequest,
parking_space: ParkingSpace,
location: ParkingSpaceLocation,
session: MaybeAuthenticated,
hcx: HelperContext,
) -> String {
let body = ParkingSpaceRentFormTemplate { let body = ParkingSpaceRentFormTemplate {
parking_space, parking_space,
location, location,
form, form,
lang, hcx: hcx.clone(),
t: t.into_inner(),
}; };
let main = Main { let main = Main {
body, body,
@ -588,12 +583,14 @@ fn render_rent_form(form: ParkingSpaceRentForm, req: &HttpRequest) -> String {
opts: MainOpts { opts: MainOpts {
show: true, show: true,
search: None, search: None,
session, session: session.into_option().map(Into::into),
}, },
hcx: hcx.clone(),
}; };
if is_partial(&req) { if is_partial(&req) {
main.render() main.render()
} else { } else {
Layout { main }.render() Layout { main }.render()
} }
.unwrap()
} }

View File

@ -23,7 +23,7 @@
for="price" for="price"
class="block mb-2 text-sm text-gray-600" class="block mb-2 text-sm text-gray-600"
> >
{{ "Price"|t(lang,t) }} {{ "Price"|t(hcx) }}
</label> </label>
<div class="flex w-full"> <div class="flex w-full">
<input <input
@ -44,9 +44,9 @@
<input <input
type="submit" type="submit"
{% if let Some(id) = form.id %} {% if let Some(id) = form.id %}
value="{{"Update parking space rent"|t(lang,t)}}" value="{{"Update parking space rent"|t(hcx)}}"
{% else %} {% else %}
value="{{"Register parking space rent"|t(lang,t)}}" value="{{"Register parking space rent"|t(hcx)}}"
{% endif %} {% endif %}
class="w-64 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2" class="w-64 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2"
/> />

View File

@ -28,7 +28,9 @@
class="w-full p-4 bg-white border border-white-200 rounded-lg shadow sm:p-8 dark:bg-white-800 dark:border-white-700 mt-6" class="w-full p-4 bg-white border border-white-200 rounded-lg shadow sm:p-8 dark:bg-white-800 dark:border-white-700 mt-6"
> >
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<h5 class="text-xl font-bold leading-none text-gray-900 dark:text-black">Owned parking spaces</h5> <h5 class="text-xl font-bold leading-none text-gray-900 dark:text-black">
{{"Owned parking spaces"|t(hcx)}}
</h5>
</div> </div>
<div class="flow-root"> <div class="flow-root">
<ul role="list" class="divide-y divide-white-200 dark:divide-white-700"> <ul role="list" class="divide-y divide-white-200 dark:divide-white-700">
@ -53,13 +55,14 @@
id="create-rent-{{parking_space.id}}" id="create-rent-{{parking_space.id}}"
hx-get="/parking-spaces/{{parking_space.id}}/parking-space-rents/form" hx-get="/parking-spaces/{{parking_space.id}}/parking-space-rents/form"
hx-headers='{"Accept":"text/html-partial"}' hx-headers='{"Accept":"text/html-partial"}'
> >
<svg height="48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 171.439 171.439" xml:space="preserve" fill="#000000A"> <svg height="48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 171.439 171.439" xml:space="preserve" fill="#000000A">
<path style="fill:#000002;" d="M21.803,171.439c-0.463,0-0.922-0.129-1.322-0.378c-0.563-0.351-0.963-0.91-1.113-1.557L1.182,91.241 c-0.313-1.345,0.524-2.688,1.869-3.001l6.729-1.563l76.692-64.254l-4.435-4.012c-1.514,0.934-3.295,1.472-5.2,1.472 c-5.482,0-9.941-4.46-9.941-9.941S71.355,0,76.837,0s9.941,4.46,9.941,9.941c0,1.766-0.463,3.426-1.273,4.864l4.837,4.375 l1.117-0.936c0.902-0.757,2.21-0.781,3.141-0.058l48.281,37.561l6.189-1.438c1.347-0.309,2.688,0.525,3.001,1.87l18.187,78.263 c0.313,1.345-0.524,2.688-1.869,3.001L22.369,171.375C22.182,171.418,21.992,171.439,21.803,171.439z M6.618,92.545l17.054,73.394 l141.149-32.8l-17.055-73.393l-4.879,1.134c-0.022,0.006-0.045,0.011-0.068,0.016L11.556,91.397 c-0.041,0.011-0.082,0.021-0.124,0.029L6.618,92.545z M90.216,25.809L20.553,84.174L136.61,57.205L96.188,25.759 c-0.038,0.539-0.25,1.07-0.64,1.502c-0.925,1.024-2.506,1.104-3.531,0.178L90.216,25.809z M76.837,5 c-2.725,0-4.941,2.217-4.941,4.941s2.217,4.941,4.941,4.941c1.361,0,2.596-0.554,3.491-1.447c0.026-0.027,0.052-0.055,0.079-0.081 c0.849-0.888,1.372-2.091,1.372-3.413C81.778,7.217,79.562,5,76.837,5z M40.256,140.785c-1.135,0-2.162-0.778-2.432-1.931 l-6.447-27.504c-0.315-1.344,0.519-2.689,1.864-3.004c0.829-0.194,1.659,0.048,2.247,0.579c1.199-1.163,2.694-1.983,4.362-2.374 c2.429-0.569,4.937-0.16,7.058,1.156c2.121,1.315,3.603,3.378,4.173,5.809c1.176,5.016-1.949,10.055-6.965,11.23 c-0.386,0.091-0.773,0.156-1.158,0.196l12.745,7.904c1.173,0.729,1.534,2.27,0.807,3.442c-0.728,1.174-2.268,1.533-3.442,0.808 l-12.309-7.635l1.934,8.251c0.315,1.344-0.52,2.689-1.864,3.004C40.637,140.763,40.445,140.785,40.256,140.785z M41.992,111.303 c-0.333,0-0.668,0.039-1,0.116c-1.13,0.266-2.089,0.954-2.701,1.94c-0.612,0.986-0.803,2.151-0.538,3.281 c0.546,2.331,2.888,3.778,5.222,3.239c2.332-0.548,3.785-2.89,3.238-5.223c-0.265-1.13-0.954-2.089-1.94-2.7 C43.577,111.525,42.792,111.303,41.992,111.303z M67.849,133.016c-1.135,0-2.162-0.778-2.432-1.931l-2.969-12.666 c-0.003-0.011-0.005-0.021-0.008-0.033c-0.002-0.011-0.005-0.021-0.007-0.033l-3.14-13.396c0-0.002-0.001-0.005-0.002-0.008 c-0.315-1.344,0.52-2.689,1.864-3.004L76,98.466c1.343-0.315,2.689,0.52,3.004,1.863s-0.52,2.689-1.864,3.004l-12.411,2.909 l2.009,8.568l7.462-1.749c1.344-0.316,2.69,0.52,3.005,1.863c0.315,1.344-0.519,2.689-1.863,3.004l-7.463,1.75l1.835,7.831 l12.412-2.908c1.343-0.315,2.689,0.52,3.004,1.863s-0.52,2.689-1.864,3.004l-14.838,3.479c-0.002,0-0.005,0.001-0.007,0.001 C68.23,132.993,68.038,133.016,67.849,133.016z M93.49,127.005c-1.135,0-2.162-0.778-2.432-1.931l-6.126-26.136 c-0.219-0.933,0.116-1.865,0.791-2.455c0.929-1.001,2.494-1.075,3.51-0.155l18.833,17.021l-4.407-18.801 c-0.315-1.344,0.519-2.689,1.863-3.004c1.346-0.315,2.69,0.52,3.005,1.863l6.126,26.136c0.218,0.93-0.115,1.861-0.786,2.45 c-0.927,1.009-2.495,1.083-3.515,0.161L91.52,105.135l4.406,18.799c0.315,1.344-0.519,2.689-1.864,3.004 C93.871,126.982,93.679,127.005,93.49,127.005z M131.954,117.989c-1.135,0-2.162-0.778-2.432-1.931l-5.556-23.702l-6.93,1.624 c-1.344,0.313-2.69-0.52-3.004-1.863c-0.315-1.344,0.519-2.689,1.864-3.004l18.727-4.39c1.344-0.316,2.689,0.52,3.004,1.863 c0.315,1.344-0.519,2.689-1.864,3.004l-6.929,1.625l5.556,23.702c0.315,1.344-0.519,2.689-1.863,3.004 C132.335,117.967,132.143,117.989,131.954,117.989z"> <path style="fill:#000002;" d="M21.803,171.439c-0.463,0-0.922-0.129-1.322-0.378c-0.563-0.351-0.963-0.91-1.113-1.557L1.182,91.241 c-0.313-1.345,0.524-2.688,1.869-3.001l6.729-1.563l76.692-64.254l-4.435-4.012c-1.514,0.934-3.295,1.472-5.2,1.472 c-5.482,0-9.941-4.46-9.941-9.941S71.355,0,76.837,0s9.941,4.46,9.941,9.941c0,1.766-0.463,3.426-1.273,4.864l4.837,4.375 l1.117-0.936c0.902-0.757,2.21-0.781,3.141-0.058l48.281,37.561l6.189-1.438c1.347-0.309,2.688,0.525,3.001,1.87l18.187,78.263 c0.313,1.345-0.524,2.688-1.869,3.001L22.369,171.375C22.182,171.418,21.992,171.439,21.803,171.439z M6.618,92.545l17.054,73.394 l141.149-32.8l-17.055-73.393l-4.879,1.134c-0.022,0.006-0.045,0.011-0.068,0.016L11.556,91.397 c-0.041,0.011-0.082,0.021-0.124,0.029L6.618,92.545z M90.216,25.809L20.553,84.174L136.61,57.205L96.188,25.759 c-0.038,0.539-0.25,1.07-0.64,1.502c-0.925,1.024-2.506,1.104-3.531,0.178L90.216,25.809z M76.837,5 c-2.725,0-4.941,2.217-4.941,4.941s2.217,4.941,4.941,4.941c1.361,0,2.596-0.554,3.491-1.447c0.026-0.027,0.052-0.055,0.079-0.081 c0.849-0.888,1.372-2.091,1.372-3.413C81.778,7.217,79.562,5,76.837,5z M40.256,140.785c-1.135,0-2.162-0.778-2.432-1.931 l-6.447-27.504c-0.315-1.344,0.519-2.689,1.864-3.004c0.829-0.194,1.659,0.048,2.247,0.579c1.199-1.163,2.694-1.983,4.362-2.374 c2.429-0.569,4.937-0.16,7.058,1.156c2.121,1.315,3.603,3.378,4.173,5.809c1.176,5.016-1.949,10.055-6.965,11.23 c-0.386,0.091-0.773,0.156-1.158,0.196l12.745,7.904c1.173,0.729,1.534,2.27,0.807,3.442c-0.728,1.174-2.268,1.533-3.442,0.808 l-12.309-7.635l1.934,8.251c0.315,1.344-0.52,2.689-1.864,3.004C40.637,140.763,40.445,140.785,40.256,140.785z M41.992,111.303 c-0.333,0-0.668,0.039-1,0.116c-1.13,0.266-2.089,0.954-2.701,1.94c-0.612,0.986-0.803,2.151-0.538,3.281 c0.546,2.331,2.888,3.778,5.222,3.239c2.332-0.548,3.785-2.89,3.238-5.223c-0.265-1.13-0.954-2.089-1.94-2.7 C43.577,111.525,42.792,111.303,41.992,111.303z M67.849,133.016c-1.135,0-2.162-0.778-2.432-1.931l-2.969-12.666 c-0.003-0.011-0.005-0.021-0.008-0.033c-0.002-0.011-0.005-0.021-0.007-0.033l-3.14-13.396c0-0.002-0.001-0.005-0.002-0.008 c-0.315-1.344,0.52-2.689,1.864-3.004L76,98.466c1.343-0.315,2.689,0.52,3.004,1.863s-0.52,2.689-1.864,3.004l-12.411,2.909 l2.009,8.568l7.462-1.749c1.344-0.316,2.69,0.52,3.005,1.863c0.315,1.344-0.519,2.689-1.863,3.004l-7.463,1.75l1.835,7.831 l12.412-2.908c1.343-0.315,2.689,0.52,3.004,1.863s-0.52,2.689-1.864,3.004l-14.838,3.479c-0.002,0-0.005,0.001-0.007,0.001 C68.23,132.993,68.038,133.016,67.849,133.016z M93.49,127.005c-1.135,0-2.162-0.778-2.432-1.931l-6.126-26.136 c-0.219-0.933,0.116-1.865,0.791-2.455c0.929-1.001,2.494-1.075,3.51-0.155l18.833,17.021l-4.407-18.801 c-0.315-1.344,0.519-2.689,1.863-3.004c1.346-0.315,2.69,0.52,3.005,1.863l6.126,26.136c0.218,0.93-0.115,1.861-0.786,2.45 c-0.927,1.009-2.495,1.083-3.515,0.161L91.52,105.135l4.406,18.799c0.315,1.344-0.519,2.689-1.864,3.004 C93.871,126.982,93.679,127.005,93.49,127.005z M131.954,117.989c-1.135,0-2.162-0.778-2.432-1.931l-5.556-23.702l-6.93,1.624 c-1.344,0.313-2.69-0.52-3.004-1.863c-0.315-1.344,0.519-2.689,1.864-3.004l18.727-4.39c1.344-0.316,2.689,0.52,3.004,1.863 c0.315,1.344-0.519,2.689-1.864,3.004l-6.929,1.625l5.556,23.702c0.315,1.344-0.519,2.689-1.863,3.004 C132.335,117.967,132.143,117.989,131.954,117.989z">
</path> </path>
</svg> </svg>
</a> </a>
{% endif %} {% endif %}
{% if parking_space.state != ParkingSpaceState::Banned %}
<a <a
href="/parking-spaces/edit/{{parking_space.id}}" href="/parking-spaces/edit/{{parking_space.id}}"
hx-target="main" hx-target="main"
@ -94,6 +97,7 @@
</path> </path>
</svg> </svg>
</a> </a>
{% endif %}
</div> </div>
</div> </div>

View File

@ -1,8 +1,8 @@
<section id="main-view" class="lg:min-h-ffh xl:min-h-ffhl flex items-top justify-center"> <section id="main-view" class="lg:min-h-ffh xl:min-h-ffhl flex items-top justify-center">
<section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg"> <section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
<h2 class="text-xl text-gray-900 mb-2">{{ "Register parking space"|t(lang,t) }}</h2> <h2 class="text-xl text-gray-900 mb-2">{{ "Register parking space"|t(hcx) }}</h2>
{% for error in errors.global() %} {% for error in errors.global() %}
<oswilno-error>{{error|t(lang,t)}}</oswilno-error> <oswilno-error>{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
<form <form
{% if let Some(id) = form.id %} {% if let Some(id) = form.id %}
@ -20,7 +20,7 @@
for="location_id" for="location_id"
class="block mb-2 text-sm text-gray-600" class="block mb-2 text-sm text-gray-600"
> >
{{ "Location"|t(lang,t) }} {{ "Location"|t(hcx) }}
</label> </label>
<select <select
id="location_id" id="location_id"
@ -40,7 +40,7 @@
{% endfor %} {% endfor %}
</select> </select>
{% for error in errors.field("login") %} {% for error in errors.field("login") %}
<oswilno-error>{{error|t(lang,t)}}</oswilno-error> <oswilno-error>{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
</div> </div>
<div class="mb-4"> <div class="mb-4">
@ -48,7 +48,7 @@
for="spot" for="spot"
class="block mb-2 text-sm text-gray-600" class="block mb-2 text-sm text-gray-600"
> >
{{ "Spot"|t(lang,t) }} {{ "Spot"|t(hcx) }}
</label> </label>
<input <input
id="spot" id="spot"
@ -65,9 +65,9 @@
<input <input
type="submit" type="submit"
{% if let Some(id) = form.id %} {% if let Some(id) = form.id %}
value="{{"Update parking space"|t(lang,t)}}" value="{{"Update parking space"|t(hcx)}}"
{% else %} {% else %}
value="{{"Register parking space"|t(lang,t)}}" value="{{"Register parking space"|t(hcx)}}"
{% endif %} {% endif %}
class="w-64 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2" class="w-64 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2"
/> />

View File

@ -1,14 +1,13 @@
{% match parking_space.state %} {% match parking_space.state %}
{% when ParkingSpaceState::Pending %} {% when ParkingSpaceState::Pending %}
<div class="text-center p-1 text-sm text-yellow-400 bg-transparent rounded-sm hover:bg-yellow-200 hover:text-yellow-900 dark:hover:bg-yellow-800 dark:hover:text-yellow-300"> <div class="inline-flex items-center text-base text-center p-1 text-sm text-yellow-400 bg-transparent rounded-sm hover:bg-yellow-200 hover:text-yellow-900 dark:hover:bg-yellow-800 dark:hover:text-yellow-300">
{{"Pending"|t(lang,t)}} {{"Pending"|t(hcx)}}
</div> </div>
{% when ParkingSpaceState::Verified %} {% when ParkingSpaceState::Verified %}
<div class="text-center p-1 text-sm text-blue-400 bg-transparent rounded-sm hover:bg-blue-200 hover:text-blue-900 dark:hover:bg-blue-800 dark:hover:text-blue-300"> <div>
{{"Accepted"|t(lang,t)}}
</div> </div>
{% when ParkingSpaceState::Banned %} {% when ParkingSpaceState::Banned %}
<div class="text-center p-1 text-sm text-red-400 bg-transparent rounded-sm hover:bg-red-200 hover:text-red-900 dark:hover:bg-red-800 dark:hover:text-red-300"> <div class="inline-flex items-center text-base text-center p-1 text-sm text-red-400 bg-transparent rounded-sm hover:bg-red-200 hover:text-red-900 dark:hover:bg-red-800 dark:hover:text-red-300">
{{"Rejected"|t(lang,t)}} {{"Rejected"|t(hcx)}}
</div> </div>
{% endmatch %} {% endmatch %}

View File

@ -7,9 +7,7 @@ use actix_web::{get, post, HttpRequest, HttpResponse};
use askama_actix::Template; use askama_actix::Template;
use autometrics::autometrics; use autometrics::autometrics;
use garde::Validate; use garde::Validate;
use oswilno_view::{ use oswilno_view::{Blank, Errors, HelperContext, Layout, Main, MainOpts};
Blank, Errors, HelperContext, Lang, Layout, Main, MainOpts, TranslationStorage,
};
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -168,7 +166,7 @@ async fn login_view(req: HttpRequest, hcx: HelperContext) -> HttpResponse {
body: SignInPartialTemplate { body: SignInPartialTemplate {
form: SignInPayload::default(), form: SignInPayload::default(),
errors: Errors::default(), errors: Errors::default(),
hcx, hcx: hcx.clone(),
}, },
opts: MainOpts { opts: MainOpts {
show: true, show: true,
@ -176,6 +174,7 @@ async fn login_view(req: HttpRequest, hcx: HelperContext) -> HttpResponse {
session: None, session: None,
}, },
title: Blank, title: Blank,
hcx,
} }
.render() .render()
} else { } else {
@ -184,13 +183,14 @@ async fn login_view(req: HttpRequest, hcx: HelperContext) -> HttpResponse {
body: SignInPartialTemplate { body: SignInPartialTemplate {
form: SignInPayload::default(), form: SignInPayload::default(),
errors: Errors::default(), errors: Errors::default(),
hcx, hcx: hcx.clone(),
}, },
opts: MainOpts { opts: MainOpts {
show: true, show: true,
..Default::default() ..Default::default()
}, },
title: Blank, title: Blank,
hcx,
}, },
} }
.render() .render()
@ -436,15 +436,14 @@ struct AccountInfo {
} }
#[get("/register")] #[get("/register")]
async fn register_view(req: HttpRequest, t: Data<TranslationStorage>) -> HttpResponse { async fn register_view(req: HttpRequest, hcx: HelperContext) -> HttpResponse {
HttpResponse::Ok().body( HttpResponse::Ok().body(
if oswilno_view::is_partial(&req) { if oswilno_view::is_partial(&req) {
Main { Main {
body: RegisterPartialTemplate { body: RegisterPartialTemplate {
form: AccountInfo::default(), form: AccountInfo::default(),
t: t.into_inner(),
lang: Lang::Pl,
errors: oswilno_view::Errors::default(), errors: oswilno_view::Errors::default(),
hcx: hcx.clone(),
}, },
title: Blank, title: Blank,
opts: MainOpts { opts: MainOpts {
@ -452,6 +451,7 @@ async fn register_view(req: HttpRequest, t: Data<TranslationStorage>) -> HttpRes
search: None, search: None,
session: None, session: None,
}, },
hcx,
} }
.render() .render()
} else { } else {
@ -459,12 +459,12 @@ async fn register_view(req: HttpRequest, t: Data<TranslationStorage>) -> HttpRes
main: Main { main: Main {
body: RegisterPartialTemplate { body: RegisterPartialTemplate {
form: AccountInfo::default(), form: AccountInfo::default(),
t: t.into_inner(),
lang: Lang::Pl,
errors: oswilno_view::Errors::default(), errors: oswilno_view::Errors::default(),
hcx: hcx.clone(),
}, },
title: Blank, title: Blank,
opts: MainOpts::default(), opts: MainOpts::default(),
hcx,
}, },
} }
.render() .render()
@ -477,9 +477,8 @@ async fn register_view(req: HttpRequest, t: Data<TranslationStorage>) -> HttpRes
#[template(path = "./register/partial.html")] #[template(path = "./register/partial.html")]
struct RegisterPartialTemplate { struct RegisterPartialTemplate {
form: AccountInfo, form: AccountInfo,
t: Arc<TranslationStorage>,
lang: Lang,
errors: oswilno_view::Errors, errors: oswilno_view::Errors,
hcx: HelperContext,
} }
#[autometrics] #[autometrics]
@ -488,10 +487,8 @@ async fn register(
req: HttpRequest, req: HttpRequest,
db: Data<DatabaseConnection>, db: Data<DatabaseConnection>,
payload: Form<AccountInfo>, payload: Form<AccountInfo>,
t: Data<oswilno_view::TranslationStorage>, hcx: HelperContext,
lang: Lang,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let t = t.into_inner();
let mut errors = oswilno_view::Errors::default(); let mut errors = oswilno_view::Errors::default();
Ok( Ok(
match register_internal(req, db.into_inner(), payload.into_inner(), &mut errors).await { match register_internal(req, db.into_inner(), payload.into_inner(), &mut errors).await {
@ -499,9 +496,8 @@ async fn register(
Err(p) => HttpResponse::BadRequest().body( Err(p) => HttpResponse::BadRequest().body(
RegisterPartialTemplate { RegisterPartialTemplate {
form: p, form: p,
t,
lang,
errors, errors,
hcx,
} }
.render() .render()
.unwrap(), .unwrap(),

View File

@ -1,11 +1,11 @@
<section id="main-view" class="lg:min-h-ffh xl:min-h-ffhl flex items-top justify-center"> <section id="main-view" class="lg:min-h-ffh xl:min-h-ffhl flex items-top justify-center">
<section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg"> <section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
{% for error in errors.global() %} {% for error in errors.global() %}
<oswilno-error>{{error|t(lang,t)}}</oswilno-error> <oswilno-error>{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
<form hx-post="/register" hx-target="#main-view" hx-replace-url="true" hx-headers='{"Accept":"text/html-partial"}'> <form hx-post="/register" hx-target="#main-view" hx-replace-url="true" hx-headers='{"Accept":"text/html-partial"}'>
<div class="mb-4"> <div class="mb-4">
<label for="login" class="block mb-2 text-sm text-gray-600">{{"Login"|t(lang,t)}}</label> <label for="login" class="block mb-2 text-sm text-gray-600">{{"Login"|t(hcx)}}</label>
<input <input
id="login" id="login"
name="login" name="login"
@ -14,11 +14,11 @@
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500"
/> />
{% for error in errors.field("input_login") %} {% for error in errors.field("input_login") %}
<oswilno-error class="mb-2 mt-2">{{error|t(lang,t)}}</oswilno-error> <oswilno-error class="mb-2 mt-2">{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="email" class="block mb-2 text-sm text-gray-600">{{"E-Mail"|t(lang,t)}}</label> <label for="email" class="block mb-2 text-sm text-gray-600">{{"E-Mail"|t(hcx)}}</label>
<input <input
id="email" id="email"
name="email" name="email"
@ -28,11 +28,11 @@
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500"
/> />
{% for error in errors.field("email") %} {% for error in errors.field("email") %}
<oswilno-error class="mb-2 mt-2">{{error|t(lang,t)}}</oswilno-error> <oswilno-error class="mb-2 mt-2">{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="password" class="block mb-2 text-sm text-gray-600">{{"Password"|t(lang,t)}}</label> <label for="password" class="block mb-2 text-sm text-gray-600">{{"Password"|t(hcx)}}</label>
<input <input
id="password" id="password"
name="password" name="password"
@ -42,11 +42,11 @@
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500"
/> />
{% for error in errors.field("password") %} {% for error in errors.field("password") %}
<oswilno-error class="mb-2 mt-2">{{error|t(lang,t)}}</oswilno-error> <oswilno-error class="mb-2 mt-2">{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="password_confirmation" class="block mb-2 text-sm text-gray-600">{{"Password confirmation"|t(lang,t)}}</label> <label for="password_confirmation" class="block mb-2 text-sm text-gray-600">{{"Password confirmation"|t(hcx)}}</label>
<input <input
id="password_confirmation" id="password_confirmation"
name="password_confirmation" name="password_confirmation"
@ -55,19 +55,19 @@
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500"
/> />
{% for error in errors.field("password_confirmation") %} {% for error in errors.field("password_confirmation") %}
<oswilno-error class="mb-2 mt-2">{{error|t(lang,t)}}</oswilno-error> <oswilno-error class="mb-2 mt-2">{{error|t(hcx)}}</oswilno-error>
{% endfor %} {% endfor %}
</div> </div>
<div class="mb-6"> <div class="mb-6">
<input <input
type="submit" type="submit"
value="{{"Submit"|t(lang,t)}}" value="{{"Submit"|t(hcx)}}"
class="w-32 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2" class="w-32 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2"
/> />
</div> </div>
</form> </form>
<div> <div>
<a href="/login" hx-get="/login" hx-replace-url="true" hx-target="main" hx-headers='{"Accept":"text/html-partial"}'>{{"Sign in"|t(lang,t)}}</a> <a href="/login" hx-get="/login" hx-replace-url="true" hx-target="main" hx-headers='{"Accept":"text/html-partial"}'>{{"Sign in"|t(hcx)}}</a>
</div> </div>
</section> </section>
</section> </section>

View File

@ -1,7 +1,9 @@
<section id="main-view" class="lg:min-h-ffh xl:min-h-ffhl flex items-top justify-center"> <section id="main-view" class="lg:min-h-ffh xl:min-h-ffhl flex items-top justify-center">
<section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg"> <section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
{% for error in errors.global() %} {% for error in errors.global() %}
<oswilno-error>{{error|t(lang,t)}}</oswilno-error> <oswilno-error>
{{error|t(hcx)}}
</oswilno-error>
{% endfor %} {% endfor %}
<form hx-post="/login" hx-target="#main-view" hx-headers='{"Accept":"text/html-partial"}' hx-replace-url="true"> <form hx-post="/login" hx-target="#main-view" hx-headers='{"Accept":"text/html-partial"}' hx-replace-url="true">
<div class="mb-4"> <div class="mb-4">
@ -14,19 +16,29 @@
<label for="password" class="block mb-2 text-sm text-gray-600">Password</label> <label for="password" class="block mb-2 text-sm text-gray-600">Password</label>
<input id="password" name="password" type="password" value="" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500" /> <input id="password" name="password" type="password" value="" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500" />
{% for error in errors.field("password") %} {% for error in errors.field("password") %}
<oswilno-error>{{error|t(lang,t)}}</oswilno-error> <oswilno-error>
{{error|t(hcx)}}
</oswilno-error>
{% endfor %} {% endfor %}
</div> </div>
<div class="mb-6"> <div class="mb-6">
<input <input
type="submit" type="submit"
value="{{"Submit"|t(lang,t)}}" value="{{"Submit"|t(hcx)}}"
class="w-32 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2" class="w-32 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2"
/> />
</div> </div>
</form> </form>
<div> <div>
<a href="/register" hx-get="/register" hx-replace-url="true" hx-target="main" hx-headers='{"Accept":"text/html-partial"}'>{{"Register"|t(lang,t)}}</a> <a
href="/register"
hx-get="/register"
hx-replace-url="true"
hx-target="main"
hx-headers='{"Accept":"text/html-partial"}'
>
{{"Register"|t(hcx)}}
</a>
</div> </div>
</section> </section>
</section> </section>

View File

@ -72,15 +72,16 @@ impl Default for MainOpts {
#[template(source = "", ext = "txt")] #[template(source = "", ext = "txt")]
pub struct Blank; pub struct Blank;
#[derive(Debug, Default, askama_actix::Template)] #[derive(Debug, askama_actix::Template)]
#[template(path = "../templates/main.html")] #[template(path = "../templates/main.html")]
pub struct Main<BodyTemplate: askama::Template, TitleTemplate: askama::Template = Blank> { pub struct Main<BodyTemplate: askama::Template, TitleTemplate: askama::Template = Blank> {
pub title: TitleTemplate, pub title: TitleTemplate,
pub body: BodyTemplate, pub body: BodyTemplate,
pub opts: MainOpts, pub opts: MainOpts,
pub hcx: HelperContext,
} }
#[derive(Debug, Default, askama_actix::Template)] #[derive(Debug, askama_actix::Template)]
#[template(path = "../templates/base.html")] #[template(path = "../templates/base.html")]
pub struct Layout<BodyTemplate: askama::Template> { pub struct Layout<BodyTemplate: askama::Template> {
pub main: Main<BodyTemplate>, pub main: Main<BodyTemplate>,
@ -143,6 +144,9 @@ impl TranslationStorage {
Self { Self {
storage: Arc::new(RwLock::new(HashMap::with_capacity(32))), storage: Arc::new(RwLock::new(HashMap::with_capacity(32))),
} }
.with_lang(Lang::Pl)
.add("Marketplace", "Targowisko")
.done()
} }
pub fn to_lang(&self, lang: Lang, s: &str) -> String { pub fn to_lang(&self, lang: Lang, s: &str) -> String {

View File

@ -10,7 +10,7 @@
class="block py-2 pl-3 pr-4 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 md:dark:text-blue-500" class="block py-2 pl-3 pr-4 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 md:dark:text-blue-500"
aria-current="page" aria-current="page"
> >
Home {{"Home"|t(hcx)}}
</a> </a>
</li> </li>
<li> <li>
@ -20,8 +20,8 @@
hx-headers='{"Accept":"text/html-partial"}' hx-headers='{"Accept":"text/html-partial"}'
hx-target="main" hx-target="main"
class="block py-2 pl-3 pr-4 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700" class="block py-2 pl-3 pr-4 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
> >
Targowisko {{"Marketplace"|t(hcx)}}
</a> </a>
</li> </li>
<li> <li>

View File

@ -8,10 +8,10 @@
</svg> </svg>
</div> </div>
<input <input
type="search" type="search"
id="search-navbar" id="search-navbar"
class="block w-full min-w-[35rem] p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" class="block w-full min-w-[35rem] p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Search..." placeholder='{"Search.."|t(hcx)}'
> >
</div> </div>
</div> </div>