removing handwritten JS

This commit is contained in:
Priec
2026-05-16 22:00:39 +02:00
parent 4938314889
commit 86c18c552d
2 changed files with 67 additions and 41 deletions

View File

@@ -67,19 +67,30 @@
}
}
/* Mobile: a backdrop behind an open navbar dropdown. It absorbs taps
outside the menu — closing the dropdown rather than letting the tap
reach the page — and dims the page to show the menu is modal. It sits
below the dropdown content (z-50) so the menu items stay tappable. */
/* Mobile: a dimming backdrop behind an open navbar dropdown, driven by
CSS alone. `:has()` shows it whenever a dropdown holds focus; a tap
outside the menu blurs the trigger, which closes the dropdown. The
delayed `visibility` transition keeps the backdrop hit-testable for a
beat after that tap, so the tap lands on the backdrop instead of
falling through to the page. It sits below the dropdown content
(z-50) so the menu items stay tappable. */
#nav-backdrop { display: none; }
@media (max-width: 767px) {
#nav-backdrop {
display: block;
position: fixed;
inset: 0;
z-index: 40;
background-color: rgba(0, 0, 0, 0.25);
opacity: 0;
visibility: hidden;
transition: opacity 0.15s ease, visibility 0s linear 0.2s;
}
.navbar:has(.dropdown:focus-within) ~ #nav-backdrop {
opacity: 1;
visibility: visible;
transition: opacity 0.15s ease, visibility 0s;
}
#nav-backdrop.nav-backdrop--on { display: block; }
}
</style>
{% block head %}{% endblock head %}
@@ -139,11 +150,15 @@
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>
</div>
<!-- The language buttons submit this form; the /lang handler sets
the `lang` cookie and redirects back. The theme buttons are
type="button" so they never submit. -->
<form method="post" action="/lang">
<ul tabindex="0"
class="menu dropdown-content z-50 mt-3 w-56 rounded-box border border-base-300 bg-base-100 p-2 shadow-lg">
<li class="menu-title">{{ t(key="settings-language", lang=lang) }}</li>
<li>
<button type="button" onclick="setLang('en')" class="{% if lang == 'en' %}active{% endif %}">
<button type="submit" name="lang" value="en" class="{% if lang == 'en' %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="h-4 w-4">
<path stroke-linecap="round" stroke-linejoin="round"
@@ -159,7 +174,7 @@
</button>
</li>
<li>
<button type="button" onclick="setLang('sk')" class="{% if lang == 'sk' %}active{% endif %}">
<button type="submit" name="lang" value="sk" class="{% if lang == 'sk' %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="h-4 w-4">
<path stroke-linecap="round" stroke-linejoin="round"
@@ -218,6 +233,7 @@
</button>
</li>
</ul>
</form>
</div>
</nav>
</div>
@@ -229,38 +245,6 @@
{% block content %}{% endblock content %}
</main>
<script>
function setLang(l) {
document.cookie = 'lang=' + l + ';path=/;max-age=31536000';
location.reload();
}
// Mobile: while a navbar dropdown is open, a full-screen backdrop covers
// the page so a tap outside the menu only closes it, instead of also
// activating whatever sat underneath. Preventing the backdrop's mousedown
// keeps the trigger focused (menu open) until the tap's click lands on the
// backdrop itself, which then blurs the trigger to close the menu.
(function () {
var backdrop = document.getElementById('nav-backdrop');
if (!backdrop) return;
var hide = function () { backdrop.classList.remove('nav-backdrop--on'); };
document.querySelectorAll('.navbar .dropdown').forEach(function (dd) {
dd.addEventListener('focusin', function () {
backdrop.classList.add('nav-backdrop--on');
});
dd.addEventListener('focusout', function (e) {
if (!dd.contains(e.relatedTarget)) hide();
});
});
backdrop.addEventListener('mousedown', function (e) { e.preventDefault(); });
backdrop.addEventListener('click', function () {
if (document.activeElement && document.activeElement.blur) {
document.activeElement.blur();
}
hide();
});
})();
</script>
{% block js %}{% endblock js %}
</body>

View File

@@ -6,6 +6,8 @@
//! court. Booked slots are coloured; free slots are blank. The same grid is
//! reused by the admin dashboard with `is_admin = true`.
use axum::http::{header, HeaderMap};
use axum::response::Redirect;
use axum_extra::extract::cookie::CookieJar;
use chrono::{Datelike, Duration, NaiveDate, Utc};
use loco_rs::prelude::*;
@@ -312,6 +314,46 @@ pub async fn index(
format::render().view(&v, "calendar/week.html", &page)
}
pub fn routes() -> Routes {
Routes::new().add("/", get(index))
#[derive(Debug, Deserialize)]
pub struct LangForm {
pub lang: String,
}
/// Switches the UI language. The navbar's language buttons post here; the
/// `lang` cookie is set server-side and the visitor is bounced back to the
/// page they came from. This replaces the old client-side `setLang` script.
#[debug_handler]
pub async fn set_lang(headers: HeaderMap, Form(form): Form<LangForm>) -> Result<Response> {
// Only the two supported languages; anything else falls back to Slovak,
// matching `current_lang`.
let lang = if form.lang == "en" { "en" } else { "sk" };
let cookie = format!("lang={lang}; Path=/; Max-Age=31536000; SameSite=Lax");
Ok((
[(header::SET_COOKIE, cookie)],
Redirect::to(&back_path(&headers)),
)
.into_response())
}
/// On-site path of the page that submitted the form, read from `Referer`.
/// Scheme and host are stripped so a stale or foreign header can only ever
/// bounce the visitor to a path on this site, never off it.
fn back_path(headers: &HeaderMap) -> String {
let raw = headers
.get(header::REFERER)
.and_then(|v| v.to_str().ok())
.unwrap_or("/");
match raw.split_once("://") {
Some((_, rest)) => match rest.find('/') {
Some(i) => rest[i..].to_string(),
None => "/".to_string(),
},
None => raw.to_string(),
}
}
pub fn routes() -> Routes {
Routes::new()
.add("/", get(index))
.add("/lang", post(set_lang))
}