feat(ui): add clear queue flow and expose ISO expiry
- Add `formatBrowserTime()` and include ISO-8601 `expires_at` in box status JSON and `ExpiresAtISO` in the box view for browser-friendly rendering. - Refresh UI styling (switch to MonoCraft/PixelOperatorMono, tweak base font size) and treat `aria-disabled="true"` like `disabled` for consistent button states. - Introduce a clear-queue action with confirmation to reset upload state, unlock controls, and provide user feedback.feat(ui): add clear queue flow and expose ISO expiry - Add `formatBrowserTime()` and include ISO-8601 `expires_at` in box status JSON and `ExpiresAtISO` in the box view for browser-friendly rendering. - Refresh UI styling (switch to MonoCraft/PixelOperatorMono, tweak base font size) and treat `aria-disabled="true"` like `disabled` for consistent button states. - Introduce a clear-queue action with confirmation to reset upload state, unlock controls, and provide user feedback.
This commit is contained in:
48
static/js/warpbox-ui.js
Normal file
48
static/js/warpbox-ui.js
Normal file
@@ -0,0 +1,48 @@
|
||||
window.WarpBoxUI = (() => {
|
||||
let toastTimer = null;
|
||||
|
||||
function toast(message, type = "info", options = {}) {
|
||||
const target = options.target || document.querySelector("#toast");
|
||||
if (!target) return;
|
||||
target.textContent = message;
|
||||
target.classList.remove("toast-info", "toast-warning", "toast-error", "is-visible");
|
||||
target.classList.add(`toast-${type}`, "is-visible");
|
||||
clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(() => target.classList.remove("is-visible"), options.duration || 2600);
|
||||
}
|
||||
|
||||
function popupElements(options = {}) {
|
||||
return {
|
||||
popup: options.popup || document.querySelector("#doc-popup"),
|
||||
title: options.title || document.querySelector("#doc-popup-title"),
|
||||
body: options.body || document.querySelector("#doc-popup-body"),
|
||||
backdrop: options.backdrop || document.querySelector("#modal-backdrop"),
|
||||
};
|
||||
}
|
||||
|
||||
function openPopup(titleText, html, options = {}) {
|
||||
const parts = popupElements(options);
|
||||
if (!parts.popup || !parts.title || !parts.body) return;
|
||||
parts.title.textContent = titleText;
|
||||
parts.body.innerHTML = html;
|
||||
parts.popup.classList.toggle("is-about-popup", Boolean(options.about));
|
||||
parts.popup.classList.toggle("is-properties-popup", Boolean(options.properties));
|
||||
parts.popup.classList.toggle("is-preview-popup", Boolean(options.preview));
|
||||
parts.popup.classList.add("is-visible");
|
||||
parts.backdrop?.classList.add("is-visible");
|
||||
}
|
||||
|
||||
function closePopup(options = {}) {
|
||||
const parts = popupElements(options);
|
||||
parts.popup?.classList.remove("is-visible", "is-about-popup", "is-properties-popup", "is-preview-popup");
|
||||
parts.backdrop?.classList.remove("is-visible");
|
||||
}
|
||||
|
||||
function renderTemplate(template, data = {}) {
|
||||
return String(template).replace(/\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g, (_, key) => {
|
||||
return Object.prototype.hasOwnProperty.call(data, key) ? String(data[key]) : "";
|
||||
});
|
||||
}
|
||||
|
||||
return { toast, openPopup, closePopup, renderTemplate };
|
||||
})();
|
||||
Reference in New Issue
Block a user