replace alerts with in-page toast messages

This commit is contained in:
Izalia Mae 2024-03-15 21:57:44 -04:00
parent 2be96a8ca5
commit a966f9c1cf
9 changed files with 134 additions and 24 deletions

View file

@ -13,7 +13,9 @@
%meta(name="viewport" content="width=device-width, initial-scale=1")
%link(rel="stylesheet" type="text/css" href="/theme/{{config.theme}}.css" nonce="{{view.request['hash']}}")
%link(rel="stylesheet" type="text/css" href="/static/style.css" nonce="{{view.request['hash']}}")
%link(rel="stylesheet" type="text/css" href="/static/toast.css" nonce="{{view.request['hash']}}")
%script(type="application/javascript" src="/static/menu.js" nonce="{{view.request['hash']}}", defer)
%script(type="application/javascript" src="/static/toast.js" nonce="{{view.request['hash']}}", defer)
%script(type="application/javascript" src="/static/api.js" nonce="{{view.request['hash']}}", defer)
-block head
@ -37,6 +39,8 @@
-else
{{menu_item("Login", "/login")}}
%ul#notifications
#container
#header.section
%span#menu-open << &#8286;

View file

@ -18,7 +18,7 @@ async function handle_config_change(event) {
await request("POST", "v1/config", params);
} catch (error) {
alert(error);
toast(error);
return;
}
@ -26,6 +26,8 @@ async function handle_config_change(event) {
document.querySelector("#header .title").innerHTML = params.value;
document.querySelector("title").innerHTML = params.value;
}
toast("Updated config", "message");
}

View file

@ -40,7 +40,7 @@ async function ban() {
}
if (values.domain === "") {
alert("Domain is required");
toast("Domain is required");
return;
}
@ -48,7 +48,7 @@ async function ban() {
var ban = await request("POST", "v1/domain_ban", values);
} catch (err) {
alert(err);
toast(err);
return
}
@ -58,8 +58,6 @@ async function ban() {
remove: `<a href="#" title="Unban domain">&#10006;</a>`
});
console.log(row.querySelector(".update-ban"));
console.log(row.querySelector(".remove a"));
add_row_listeners(row);
elems.domain.value = null;
@ -67,6 +65,7 @@ async function ban() {
elems.note.value = null;
document.querySelector("details.section").open = false;
toast("Banned domain", "message");
}
@ -88,11 +87,12 @@ async function update_ban(domain) {
await request("PATCH", "v1/domain_ban", values)
} catch (error) {
alert(error);
toast(error);
return;
}
row.querySelector("details").open = false;
toast("Updated baned domain", "message");
}
@ -101,11 +101,12 @@ async function unban(domain) {
await request("DELETE", "v1/domain_ban", {"domain": domain});
} catch (error) {
alert(error);
toast(error);
return;
}
document.getElementById(domain).remove();
toast("Unbanned domain", "message");
}

View file

@ -35,7 +35,7 @@ async function add_instance() {
}
if (values.actor === "") {
alert("Actor is required");
toast("Actor is required");
return;
}
@ -43,7 +43,7 @@ async function add_instance() {
var instance = await request("POST", "v1/instance", values);
} catch (err) {
alert(err);
toast(err);
return
}
@ -62,6 +62,7 @@ async function add_instance() {
elems.software.value = null;
document.querySelector("details.section").open = false;
toast("Added instance", "message");
}
@ -70,7 +71,7 @@ async function del_instance(domain) {
await request("DELETE", "v1/instance", {"domain": domain});
} catch (error) {
alert(error);
toast(error);
return;
}
@ -88,7 +89,7 @@ async function req_response(domain, accept) {
await request("POST", "v1/request", params);
} catch (error) {
alert(error);
toast(error);
return;
}
@ -115,6 +116,8 @@ async function req_response(domain, accept) {
add_instance_listeners(row);
}
});
toast("Removed instance", "message");
}

View file

@ -39,7 +39,7 @@ async function ban() {
}
if (values.name === "") {
alert("Domain is required");
toast("Domain is required");
return;
}
@ -47,7 +47,7 @@ async function ban() {
var ban = await request("POST", "v1/software_ban", values);
} catch (err) {
alert(err);
toast(err);
return
}
@ -64,6 +64,7 @@ async function ban() {
elems.note.value = null;
document.querySelector("details.section").open = false;
toast("Banned software", "message");
}
@ -85,11 +86,12 @@ async function update_ban(name) {
await request("PATCH", "v1/software_ban", values)
} catch (error) {
alert(error);
toast(error);
return;
}
row.querySelector("details").open = false;
toast("Updated software ban", "message");
}
@ -98,11 +100,12 @@ async function unban(name) {
await request("DELETE", "v1/software_ban", {"name": name});
} catch (error) {
alert(error);
toast(error);
return;
}
document.getElementById(name).remove();
toast("Unbanned software", "message");
}

View file

@ -0,0 +1,68 @@
#notifications {
position: fixed;
top: 40px;
left: 50%;
transform: translateX(-50%);
}
#notifications li {
position: relative;
overflow: hidden;
list-style: none;
border-radius: 5px;
padding: 5px;;
margin-bottom: var(--spacing);
animation: show_toast 0.3s ease forwards;
display: grid;
grid-template-columns: auto max-content;
grid-gap: 5px;
align-items: center;
}
#notifications a {
font-size: 1.5em;
line-height: 1em;
text-decoration: none;
}
#notifications li.hide {
animation: hide_toast 0.3s ease forwards;
}
@keyframes show_toast {
0% {
transform: translateX(100%);
}
40% {
transform: translateX(-5%);
}
80% {
transform: translateX(0%);
}
100% {
transform: translateX(-10px);
}
}
@keyframes hide_toast {
0% {
transform: translateX(-10px);
}
40% {
transform: translateX(0%);
}
80% {
transform: translateX(-5%);
}
100% {
transform: translateX(calc(100% + 20px));
}
}

View file

@ -0,0 +1,26 @@
const notifications = document.querySelector("#notifications")
function remove_toast(toast) {
toast.classList.add("hide");
if (toast.timeoutId) {
clearTimeout(toast.timeoutId);
}
setTimeout(() => toast.remove(), 300);
}
function toast(text, type="error", timeout=5) {
const toast = document.createElement("li");
toast.className = `section ${type}`
toast.innerHTML = `<span class=".text">${text}</span><a href="#">&#10006;</span>`
toast.querySelector("a").addEventListener("click", async (event) => {
event.preventDefault();
await remove_toast(toast);
});
notifications.appendChild(toast);
toast.timeoutId = setTimeout(() => remove_toast(toast), timeout * 1000);
}

View file

@ -1,5 +1,4 @@
function add_row_listeners(row) {
console.log(row);
row.querySelector(".remove a").addEventListener("click", async (event) => {
event.preventDefault();
await del_user(row.id);
@ -23,12 +22,12 @@ async function add_user() {
}
if (values.username === "" | values.password === "" | values.password2 === "") {
alert("Username, password, and password2 are required");
toast("Username, password, and password2 are required");
return;
}
if (values.password !== values.password2) {
alert("Passwords do not match");
toast("Passwords do not match");
return;
}
@ -36,7 +35,7 @@ async function add_user() {
var user = await request("POST", "v1/user", values);
} catch (err) {
alert(err);
toast(err);
return
}
@ -55,6 +54,7 @@ async function add_user() {
elems.handle.value = null;
document.querySelector("details.section").open = false;
toast("Created user", "message");
}
@ -63,11 +63,12 @@ async function del_user(username) {
await request("DELETE", "v1/user", {"username": username});
} catch (error) {
alert(error);
toast(error);
return;
}
document.getElementById(username).remove();
toast("Deleted user", "message");
}

View file

@ -11,7 +11,7 @@ async function add_whitelist() {
var domain = domain_elem.value.trim();
if (domain === "") {
alert("Domain is required");
toast("Domain is required");
return;
}
@ -19,8 +19,8 @@ async function add_whitelist() {
var item = await request("POST", "v1/whitelist", {"domain": domain});
} catch (err) {
alert(err);
return
toast(err);
return;
}
var row = append_table_row(document.getElementById("whitelist"), item.domain, {
@ -33,6 +33,7 @@ async function add_whitelist() {
domain_elem.value = null;
document.querySelector("details.section").open = false;
toast("Added domain", "message");
}
@ -41,11 +42,12 @@ async function del_whitelist(domain) {
await request("DELETE", "v1/whitelist", {"domain": domain});
} catch (error) {
alert(error);
toast(error);
return;
}
document.getElementById(domain).remove();
toast("Removed domain", "message");
}