|
|
|
@@ -3,7 +3,7 @@
|
|
|
|
|
* input, per-file progress bars, and success/failed states. Injected by
|
|
|
|
|
* `collectScripts` only on pages that contain `data-uploader` (same mechanism as
|
|
|
|
|
* `validate.js`). Self-contained: it injects its own themed stylesheet (using
|
|
|
|
|
* `--wire-*` tokens) and posts each file via XHR so upload progress is live.
|
|
|
|
|
* `--wrn-*` tokens) and posts each file via XHR so upload progress is live.
|
|
|
|
|
*
|
|
|
|
|
* Markup it enhances (also a valid no-JS `<form>` fallback if you wrap it):
|
|
|
|
|
* <div data-uploader="public" data-endpoint="/api/upload"
|
|
|
|
@@ -21,35 +21,35 @@ export const UPLOAD_JS_HREF = "/__wrnexus/uploader.js";
|
|
|
|
|
export const UPLOAD_RUNTIME = `
|
|
|
|
|
(function () {
|
|
|
|
|
if (typeof document === "undefined") return;
|
|
|
|
|
var CSRF_COOKIE = "wire-csrf";
|
|
|
|
|
var CSRF_COOKIE = "wrn-csrf";
|
|
|
|
|
|
|
|
|
|
var CSS =
|
|
|
|
|
".wire-uploader{display:block}" +
|
|
|
|
|
".wire-uploader-zone{display:flex;align-items:center;justify-content:center;text-align:center;" +
|
|
|
|
|
"min-height:8rem;padding:1.25rem;border:2px dashed var(--wire-border,#cbd5e1);border-radius:12px;" +
|
|
|
|
|
"background:var(--wire-surface,transparent);color:var(--wire-muted,#64748b);cursor:pointer;" +
|
|
|
|
|
".wrn-uploader{display:block}" +
|
|
|
|
|
".wrn-uploader-zone{display:flex;align-items:center;justify-content:center;text-align:center;" +
|
|
|
|
|
"min-height:8rem;padding:1.25rem;border:2px dashed var(--wrn-border,#cbd5e1);border-radius:12px;" +
|
|
|
|
|
"background:var(--wrn-surface,transparent);color:var(--wrn-muted,#64748b);cursor:pointer;" +
|
|
|
|
|
"transition:border-color .15s ease,background-color .15s ease;position:relative}" +
|
|
|
|
|
".wire-uploader-zone:hover,.wire-uploader-zone:focus-visible{border-color:var(--wire-brand,#3f7dff);outline:none}" +
|
|
|
|
|
".wire-uploader-zone.is-drag{border-color:var(--wire-brand,#3f7dff);background:color-mix(in oklab,var(--wire-brand,#3f7dff) 8%,transparent)}" +
|
|
|
|
|
".wire-uploader-prompt{font-size:.9rem;pointer-events:none}" +
|
|
|
|
|
".wire-uploader-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}" +
|
|
|
|
|
".wire-uploader-list{list-style:none;margin:.75rem 0 0;padding:0;display:flex;flex-direction:column;gap:.5rem}" +
|
|
|
|
|
".wire-uploader-item{display:grid;grid-template-columns:1fr auto;gap:.15rem .75rem;align-items:center;" +
|
|
|
|
|
"font-size:.82rem;padding:.5rem .7rem;border:1px solid var(--wire-border,#e2e8f0);border-radius:8px}" +
|
|
|
|
|
".wire-uploader-name{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--wire-text,#0f172a)}" +
|
|
|
|
|
".wire-uploader-meta{color:var(--wire-muted,#94a3b8);font-variant-numeric:tabular-nums}" +
|
|
|
|
|
".wire-uploader-bar{grid-column:1/-1;height:5px;border-radius:999px;background:var(--wire-border,#e2e8f0);overflow:hidden}" +
|
|
|
|
|
".wire-uploader-fill{height:100%;width:0;border-radius:999px;background:var(--wire-brand,#3f7dff);transition:width .15s ease}" +
|
|
|
|
|
".wire-uploader-status{grid-column:1/-1;font-size:.75rem;color:var(--wire-muted,#94a3b8);font-variant-numeric:tabular-nums}" +
|
|
|
|
|
".wire-uploader-item.is-done .wire-uploader-fill{background:var(--wire-success,#16a34a)}" +
|
|
|
|
|
".wire-uploader-item.is-done .wire-uploader-status{color:var(--wire-success,#16a34a)}" +
|
|
|
|
|
".wire-uploader-item.is-error .wire-uploader-fill{background:var(--wire-danger,#dc2626)}" +
|
|
|
|
|
".wire-uploader-item.is-error .wire-uploader-status{color:var(--wire-danger,#dc2626)}";
|
|
|
|
|
".wrn-uploader-zone:hover,.wrn-uploader-zone:focus-visible{border-color:var(--wrn-brand,#3f7dff);outline:none}" +
|
|
|
|
|
".wrn-uploader-zone.is-drag{border-color:var(--wrn-brand,#3f7dff);background:color-mix(in oklab,var(--wrn-brand,#3f7dff) 8%,transparent)}" +
|
|
|
|
|
".wrn-uploader-prompt{font-size:.9rem;pointer-events:none}" +
|
|
|
|
|
".wrn-uploader-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}" +
|
|
|
|
|
".wrn-uploader-list{list-style:none;margin:.75rem 0 0;padding:0;display:flex;flex-direction:column;gap:.5rem}" +
|
|
|
|
|
".wrn-uploader-item{display:grid;grid-template-columns:1fr auto;gap:.15rem .75rem;align-items:center;" +
|
|
|
|
|
"font-size:.82rem;padding:.5rem .7rem;border:1px solid var(--wrn-border,#e2e8f0);border-radius:8px}" +
|
|
|
|
|
".wrn-uploader-name{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--wrn-text,#0f172a)}" +
|
|
|
|
|
".wrn-uploader-meta{color:var(--wrn-muted,#94a3b8);font-variant-numeric:tabular-nums}" +
|
|
|
|
|
".wrn-uploader-bar{grid-column:1/-1;height:5px;border-radius:999px;background:var(--wrn-border,#e2e8f0);overflow:hidden}" +
|
|
|
|
|
".wrn-uploader-fill{height:100%;width:0;border-radius:999px;background:var(--wrn-brand,#3f7dff);transition:width .15s ease}" +
|
|
|
|
|
".wrn-uploader-status{grid-column:1/-1;font-size:.75rem;color:var(--wrn-muted,#94a3b8);font-variant-numeric:tabular-nums}" +
|
|
|
|
|
".wrn-uploader-item.is-done .wrn-uploader-fill{background:var(--wrn-success,#16a34a)}" +
|
|
|
|
|
".wrn-uploader-item.is-done .wrn-uploader-status{color:var(--wrn-success,#16a34a)}" +
|
|
|
|
|
".wrn-uploader-item.is-error .wrn-uploader-fill{background:var(--wrn-danger,#dc2626)}" +
|
|
|
|
|
".wrn-uploader-item.is-error .wrn-uploader-status{color:var(--wrn-danger,#dc2626)}";
|
|
|
|
|
|
|
|
|
|
function injectCss() {
|
|
|
|
|
if (document.getElementById("wire-uploader-css")) return;
|
|
|
|
|
if (document.getElementById("wrn-uploader-css")) return;
|
|
|
|
|
var s = document.createElement("style");
|
|
|
|
|
s.id = "wire-uploader-css";
|
|
|
|
|
s.id = "wrn-uploader-css";
|
|
|
|
|
s.textContent = CSS;
|
|
|
|
|
document.head.appendChild(s);
|
|
|
|
|
}
|
|
|
|
@@ -98,18 +98,18 @@ export const UPLOAD_RUNTIME = `
|
|
|
|
|
.filter(Boolean);
|
|
|
|
|
var promptText = root.getAttribute("data-label") || "Drag files here or click to browse";
|
|
|
|
|
|
|
|
|
|
root.classList.add("wire-uploader");
|
|
|
|
|
var zone = el("div", "wire-uploader-zone");
|
|
|
|
|
root.classList.add("wrn-uploader");
|
|
|
|
|
var zone = el("div", "wrn-uploader-zone");
|
|
|
|
|
zone.setAttribute("role", "button");
|
|
|
|
|
zone.setAttribute("tabindex", "0");
|
|
|
|
|
zone.appendChild(el("div", "wire-uploader-prompt", promptText));
|
|
|
|
|
zone.appendChild(el("div", "wrn-uploader-prompt", promptText));
|
|
|
|
|
var input = document.createElement("input");
|
|
|
|
|
input.type = "file";
|
|
|
|
|
input.className = "wire-uploader-input";
|
|
|
|
|
input.className = "wrn-uploader-input";
|
|
|
|
|
if (multiple) input.multiple = true;
|
|
|
|
|
if (accept) input.accept = accept;
|
|
|
|
|
zone.appendChild(input);
|
|
|
|
|
var listEl = el("ul", "wire-uploader-list");
|
|
|
|
|
var listEl = el("ul", "wrn-uploader-list");
|
|
|
|
|
root.appendChild(zone);
|
|
|
|
|
root.appendChild(listEl);
|
|
|
|
|
|
|
|
|
@@ -137,14 +137,14 @@ export const UPLOAD_RUNTIME = `
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function row(file) {
|
|
|
|
|
var li = el("li", "wire-uploader-item");
|
|
|
|
|
li.appendChild(el("span", "wire-uploader-name", file.name));
|
|
|
|
|
li.appendChild(el("span", "wire-uploader-meta", fmt(file.size)));
|
|
|
|
|
var bar = el("div", "wire-uploader-bar");
|
|
|
|
|
var fill = el("div", "wire-uploader-fill");
|
|
|
|
|
var li = el("li", "wrn-uploader-item");
|
|
|
|
|
li.appendChild(el("span", "wrn-uploader-name", file.name));
|
|
|
|
|
li.appendChild(el("span", "wrn-uploader-meta", fmt(file.size)));
|
|
|
|
|
var bar = el("div", "wrn-uploader-bar");
|
|
|
|
|
var fill = el("div", "wrn-uploader-fill");
|
|
|
|
|
bar.appendChild(fill);
|
|
|
|
|
li.appendChild(bar);
|
|
|
|
|
var status = el("span", "wire-uploader-status", "");
|
|
|
|
|
var status = el("span", "wrn-uploader-status", "");
|
|
|
|
|
li.appendChild(status);
|
|
|
|
|
listEl.appendChild(li);
|
|
|
|
|
return { li: li, fill: fill, status: status };
|
|
|
|
|