This commit is contained in:
@@ -41,6 +41,31 @@ body {
|
||||
background-size: 100% 100%, 48px 48px;
|
||||
}
|
||||
|
||||
.submit-progress {
|
||||
position: fixed;
|
||||
inset: 0 0 auto;
|
||||
z-index: 100;
|
||||
height: 3px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.submit-progress[hidden] { display: none; }
|
||||
|
||||
.submit-progress-bar {
|
||||
display: block;
|
||||
width: 35%;
|
||||
height: 100%;
|
||||
background: var(--signal);
|
||||
box-shadow: 0 0 12px var(--signal);
|
||||
animation: submit-progress 900ms ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes submit-progress {
|
||||
from { transform: translateX(-100%); }
|
||||
to { transform: translateX(300%); }
|
||||
}
|
||||
|
||||
img, svg { display: block; }
|
||||
|
||||
a {
|
||||
@@ -253,6 +278,12 @@ a {
|
||||
|
||||
.btn-primary:hover { filter: brightness(1.08); }
|
||||
|
||||
.btn:disabled {
|
||||
cursor: wait;
|
||||
opacity: 0.65;
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
@@ -763,6 +794,10 @@ input:focus, textarea:focus, .btn:focus-visible, .chip:focus-visible, .vote-btn:
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.btn-primary:hover { filter: none; }
|
||||
.submit-progress-bar {
|
||||
width: 100%;
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-users { margin-top: 20px; overflow-x: auto; }
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
(() => {
|
||||
const formSelector = "form[data-submit-once]";
|
||||
|
||||
function progressIndicator() {
|
||||
return document.getElementById("submit-progress");
|
||||
}
|
||||
|
||||
function resetForm(form) {
|
||||
form.removeAttribute("aria-busy");
|
||||
delete form.dataset.submitting;
|
||||
|
||||
const button = form.querySelector("[data-submit-button]");
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
button.disabled = false;
|
||||
button.removeAttribute("aria-disabled");
|
||||
if (button.dataset.idleLabel) {
|
||||
button.textContent = button.dataset.idleLabel;
|
||||
delete button.dataset.idleLabel;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("submit", (event) => {
|
||||
const form = event.target.closest(formSelector);
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
if (form.dataset.submitting === "true") {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
form.dataset.submitting = "true";
|
||||
form.setAttribute("aria-busy", "true");
|
||||
|
||||
const button = event.submitter || form.querySelector("[data-submit-button]");
|
||||
if (button) {
|
||||
button.dataset.idleLabel = button.textContent;
|
||||
button.textContent = form.dataset.submittingLabel || "Posting…";
|
||||
button.disabled = true;
|
||||
button.setAttribute("aria-disabled", "true");
|
||||
}
|
||||
|
||||
const progress = progressIndicator();
|
||||
if (progress) {
|
||||
progress.hidden = false;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("pageshow", () => {
|
||||
document.querySelectorAll(formSelector).forEach(resetForm);
|
||||
const progress = progressIndicator();
|
||||
if (progress) {
|
||||
progress.hidden = true;
|
||||
}
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user