diff --git a/l4d2web/static/css/components.css b/l4d2web/static/css/components.css index 625e278..e8e4b3f 100644 --- a/l4d2web/static/css/components.css +++ b/l4d2web/static/css/components.css @@ -517,21 +517,29 @@ button.danger-outline:hover { floating Uploads panel. ============================================================ */ -.files-manager { - display: grid; - gap: var(--space-m); +/* The display: flex / grid declarations on the elements below have the + same specificity as the UA's `[hidden]{display:none}` rule and come + later in the cascade, so without this they'd win and elements would + stay visible after JS sets `el.hidden = true`. Targeted rather than + a global `[hidden]!important` so we don't fight unknown UA defaults. */ +.files-uploads[hidden], +.files-editor-binary[hidden], +.files-editor-text[hidden], +.files-editor-replace-idle[hidden], +.files-editor-replace-queued[hidden], +.files-editor-rename-hint[hidden], +.files-uploads-clear[hidden] { + display: none !important; } -.files-manager-toolbar { - display: flex; - align-items: center; - gap: var(--space-m); - flex-wrap: wrap; +.files-manager { + display: grid; + gap: var(--space-s); } .files-manager-hint { - flex: 1; font-size: 0.85em; + margin: 0; } .files-tree-root { @@ -551,6 +559,16 @@ button.danger-outline:hover { background: color-mix(in srgb, var(--color-success) 10%, transparent); } +.files-row-root > .files-row-root-label { + font-style: italic; + color: var(--color-muted); +} + +.files-root-children { + flex-basis: 100%; + margin-top: var(--space-xs); +} + .files-empty { margin: var(--space-s) var(--space-xs); } @@ -613,13 +631,6 @@ button.danger-outline:hover { border-color: var(--color-danger); } -.files-root-actions { - margin-left: auto; - display: inline-flex; - align-items: center; - gap: var(--space-xs); -} - .files-row.is-drag-source { opacity: 0.5; } diff --git a/l4d2web/static/js/file-tree.js b/l4d2web/static/js/file-tree.js index 5cfd006..f9ade86 100644 --- a/l4d2web/static/js/file-tree.js +++ b/l4d2web/static/js/file-tree.js @@ -4,13 +4,18 @@ // carries `data-files-url`. First expand fires a fetch and innerHTMLs the // returned partial into the next `.file-tree-children`; subsequent clicks // just toggle visibility — no re-fetch. +// +// Children-div lookup goes through the row's
  • rather than the button's +// nextElementSibling so the files-overlay variant — where a per-row action +// column sits between the toggle button and the children div — works too. (function () { document.addEventListener("click", function (event) { const button = event.target.closest(".file-tree-toggle"); if (!button) return; - const children = button.nextElementSibling; - if (!children || !children.classList.contains("file-tree-children")) return; + const row = button.closest(".file-tree-row"); + const children = row ? row.querySelector(":scope > .file-tree-children") : null; + if (!children) return; const wasExpanded = button.getAttribute("aria-expanded") === "true"; button.setAttribute("aria-expanded", wasExpanded ? "false" : "true"); diff --git a/l4d2web/static/js/files-overlay.js b/l4d2web/static/js/files-overlay.js index d3c500a..0654d4f 100644 --- a/l4d2web/static/js/files-overlay.js +++ b/l4d2web/static/js/files-overlay.js @@ -136,20 +136,22 @@ } if (!path) { - // Overlay root — replace the tree-root container's children. - const empty = treeRoot.querySelector(".files-empty"); + // Overlay root — swap into the synthetic root row's children div. + const target = manager.querySelector(".files-root-children"); + if (!target) return; + const empty = target.querySelector(".files-empty"); if (empty) empty.remove(); - const existingUl = treeRoot.querySelector(":scope > ul.file-tree"); + const existingUl = target.querySelector(":scope > ul.file-tree"); if (existingUl) existingUl.remove(); - treeRoot.insertAdjacentHTML("beforeend", html); + target.insertAdjacentHTML("beforeend", html); // If the new content is also empty, restore the placeholder. - const newUl = treeRoot.querySelector(":scope > ul.file-tree"); + const newUl = target.querySelector(":scope > ul.file-tree"); if (newUl && newUl.children.length === 0) { newUl.remove(); const p = document.createElement("p"); p.className = "muted files-empty"; - p.textContent = 'Empty — drop files here, or click "+ new file" above.'; - treeRoot.appendChild(p); + p.textContent = 'Empty — drop files here, or click "+ new file" on this row.'; + target.appendChild(p); } return; } @@ -602,21 +604,22 @@ } }); - input.addEventListener( - "keydown", - (event) => { - if (event.key === "Enter") { - event.preventDefault(); - fresh.click(); - } - }, - { once: true } - ); - newFolderDialog.showModal(); setTimeout(() => input.focus(), 0); } + // Enter on the new-folder input submits — bound once at module init so + // it survives multiple openings of the dialog. (A previous version used + // `{once: true}` inside openNewFolder, which was consumed by the first + // letter the user typed and never saw Enter.) + newFolderDialog + .querySelector(".files-new-folder-name") + .addEventListener("keydown", (event) => { + if (event.key !== "Enter") return; + event.preventDefault(); + newFolderDialog.querySelector(".files-new-folder-create")?.click(); + }); + // ---------- upload queue + progress panel ------------------------------- const uploadQueue = []; diff --git a/l4d2web/templates/overlay_detail.html b/l4d2web/templates/overlay_detail.html index e927e68..d2d9add 100644 --- a/l4d2web/templates/overlay_detail.html +++ b/l4d2web/templates/overlay_detail.html @@ -65,27 +65,32 @@
    -
    - Drop files / folders onto a folder row to upload, drag rows to move - - - - - -
    -
    - {% if not file_tree_root_entries %} -

    Empty — drop files here, or click "+ new file" above.

    - {% else %} - {% set entries = file_tree_root_entries %} - {% set truncated = file_tree_truncated %} - {% set truncated_count = file_tree_truncated_count %} - {% set files_base_url = "/overlays/" ~ overlay.id %} - {% set download_supported = True %} - {% set files_overlay = True %} - {% include "_overlay_file_tree.html" %} - {% endif %} -
    +

    Drop files or folders onto a folder row to upload. Drag rows inside the tree to move them.

    +
    {% else %} {% if not file_tree_root_entries %}