diff --git a/relay/frontend/base.haml b/relay/frontend/base.haml
index 4b4a3d1..d58c98b 100644
--- a/relay/frontend/base.haml
+++ b/relay/frontend/base.haml
@@ -13,9 +13,6 @@
%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']}}" class="theme")
%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
diff --git a/relay/frontend/static/api.js b/relay/frontend/static/api.js
index d064d7b..65423ba 100644
--- a/relay/frontend/static/api.js
+++ b/relay/frontend/static/api.js
@@ -1,3 +1,61 @@
+// toast notifications
+
+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 = `${text}✖`
+
+ toast.querySelector("a").addEventListener("click", async (event) => {
+ event.preventDefault();
+ await remove_toast(toast);
+ });
+
+ notifications.appendChild(toast);
+ toast.timeoutId = setTimeout(() => remove_toast(toast), timeout * 1000);
+}
+
+
+// menu
+
+const body = document.getElementById("container")
+const menu = document.getElementById("menu");
+const menu_open = document.getElementById("menu-open");
+const menu_close = document.getElementById("menu-close");
+
+
+menu_open.addEventListener("click", (event) => {
+ var new_value = menu.attributes.visible.nodeValue === "true" ? "false" : "true";
+ menu.attributes.visible.nodeValue = new_value;
+});
+
+menu_close.addEventListener("click", (event) => {
+ menu.attributes.visible.nodeValue = "false"
+});
+
+body.addEventListener("click", (event) => {
+ if (event.target === menu_open) {
+ return;
+ }
+
+ menu.attributes.visible.nodeValue = "false";
+});
+
+
+// misc
+
function get_date_string(date) {
var year = date.getFullYear().toString();
var month = date.getMonth().toString();
diff --git a/relay/frontend/static/menu.js b/relay/frontend/static/menu.js
deleted file mode 100644
index ebd494f..0000000
--- a/relay/frontend/static/menu.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const body = document.getElementById("container")
-const menu = document.getElementById("menu");
-const menu_open = document.getElementById("menu-open");
-const menu_close = document.getElementById("menu-close");
-
-menu_open.addEventListener("click", (event) => {
- var new_value = menu.attributes.visible.nodeValue === "true" ? "false" : "true";
- menu.attributes.visible.nodeValue = new_value;
-});
-
-menu_close.addEventListener("click", (event) => {
- menu.attributes.visible.nodeValue = "false"
-});
-
-body.addEventListener("click", (event) => {
- if (event.target === menu_open) {
- return;
- }
-
- menu.attributes.visible.nodeValue = "false";
-});
diff --git a/relay/frontend/static/style.css b/relay/frontend/static/style.css
index e1ac3eb..635aa55 100644
--- a/relay/frontend/static/style.css
+++ b/relay/frontend/static/style.css
@@ -204,6 +204,37 @@ textarea {
text-align: center;
}
+#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;
+}
+
#footer {
display: grid;
grid-template-columns: auto auto;
@@ -296,6 +327,44 @@ textarea {
}
+@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));
+ }
+}
+
+
@media (max-width: 1026px) {
body {
margin: 0px;
diff --git a/relay/frontend/static/toast.css b/relay/frontend/static/toast.css
deleted file mode 100644
index e544dcd..0000000
--- a/relay/frontend/static/toast.css
+++ /dev/null
@@ -1,68 +0,0 @@
-#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));
- }
-}
diff --git a/relay/frontend/static/toast.js b/relay/frontend/static/toast.js
deleted file mode 100644
index e4ca8cc..0000000
--- a/relay/frontend/static/toast.js
+++ /dev/null
@@ -1,26 +0,0 @@
-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 = `${text}✖`
-
- toast.querySelector("a").addEventListener("click", async (event) => {
- event.preventDefault();
- await remove_toast(toast);
- });
-
- notifications.appendChild(toast);
- toast.timeoutId = setTimeout(() => remove_toast(toast), timeout * 1000);
-}