From e1723f751c706ad75412a718f22e674188ee90c8 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sun, 17 May 2026 17:20:23 +0200 Subject: [PATCH] docs(agents): update modal-pattern reference + add files-overlay layout Two updates to AGENTS.md after the files-overlay rewrite: 1. The "canonical pattern" reference at the bottom of the inline-vs- routed modals section pointed at files-overlay.js lines ~599-664. That file is gone. Updated the reference to point at the new single-purpose location: editor.js's document-level click listener and the routedSaveClicked / routedReplaceClicked / routedDeleteClicked functions. 2. Added a "Files overlay: module layout" subsection right after the modals one. Names the four modules under static/js/files-overlay/, what each owns, the window.__filesOverlay action-registry contract, and the recipe for adding a new file-row action. Future agents touching the file manager hit a one-paragraph orientation instead of re-deriving the layout from git log. No behavior change. The "Modals: inline vs routed" decision tree itself stays accurate post-rewrite: editor is routed; new-folder, delete-confirm, conflict stay inline. Co-Authored-By: Claude Opus 4.7 (1M context) --- AGENTS.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2491cec..572b90b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,11 +46,56 @@ Hooks: `` opens (full-page nav fallback if JS - **The outermost element of `{% block content %}` is a `
`, NOT a ``.** The persistent slot in `base.html` already provides top-layer + backdrop + focus-trap + Esc-to-close semantics. Nested `` collapses to 2 px in every browser. - **Close buttons use `data-routed-modal-dismiss`** (NOT the inline-modal attribute). `modals.js` delegates at document level. -- **Form-bearing content needs document-level event delegation** for submit/save/delete, gated on `event.target.closest("#modal-content")`. Direct binding to elements in the swapped-in fragment only works in standalone mode — HTMX-swapped content arrives as fresh DOM nodes with no listeners attached. See `files-overlay.js` lines ~599-664 for the canonical pattern (read `data-*` attributes from the swapped DOM, NOT from JS state set during open). +- **Form-bearing content needs document-level event delegation** for submit/save/delete, gated on `event.target.closest("#modal-content")`. Direct binding to elements in the swapped-in fragment only works in standalone mode — HTMX-swapped content arrives as fresh DOM nodes with no listeners attached. See `static/js/files-overlay/editor.js`'s document-level click listener + the `routedSaveClicked` / `routedReplaceClicked` / `routedDeleteClicked` functions for the canonical pattern (read `data-*` attributes from the swapped DOM, NOT from JS state set during open). - **CSS classes targeting modal chrome are scoped to the outer slot** — `dialog.modal, div.modal` in `components.css`. The inner content div should NOT carry `class="modal modal-wide"` (the outer dialog owns chrome; otherwise both paint card-in-a-card). **Reference:** `docs/superpowers/specs/2026-05-17-url-addressable-modals-design.md` (design + verification matrix) and the plan errata at the top of `docs/superpowers/plans/2026-05-17-url-addressable-modals.md`. +### Files overlay: module layout + +The file-manager JS for files-type overlays is split across four +modules under `l4d2web/l4d2web/static/js/files-overlay/`, all loaded +with `defer` from `templates/overlay_detail.html`. They cooperate via +the `window.__filesOverlay` action registry that `core.js` sets up: + +- **`core.js`** — manager-element detection (`.files-manager` guard), + derived state (`overlayId`, `baseUrl`, `treeRoot`, `csrfToken`), + shared helpers (`joinPath`, `parentOf`, `basename`, `humanSize`, + `fetchJson`, `postJson`, `postForm`, `refreshFolder`, + `findRowByPath`, `cssEscape`, `scheduleRefresh`), and the + document-level click listener that dispatches `[data-action]` + clicks through `__filesOverlay.handleAction(op, path, actionEl)` + into per-feature handlers. +- **`editor.js`** — URL-addressable editor only. Handles the new-file + route (`/files/new?at=...`), edit route for text + binary + (`/files/edit?path=...`), and the save / replace / delete delegated + click handlers scoped to `#modal-content`. Registers `"new-file"` + and `"edit"` into the registry. +- **`dialogs.js`** — the three inline `` modals (new-folder, + delete-confirm, conflict). Module-scope state per dialog (one + delegated listener each, no clone-and-rebind). Exposes + `askConflict(path) → Promise<"overwrite"|"keep-both"|"cancel">` + on `__filesOverlay` for use by editor.js + uploads.js. Registers + `"new-folder"` and `"delete"` into the registry. +- **`uploads.js`** — upload queue (concurrency 3, XHR-based progress, + `data-upload-id` delegated cancel), drag-drop on `treeRoot` + (direct-bound — 5 coordinated events share highlight state), and + the `"zip"` registry handler. Exposes + `withCollisionSuffix(path) → suffixedPath` for the upload + save + conflict paths. Drag-drop on `treeRoot` is the **only** direct-bound + listener block in the four modules; everything else is document-level + delegation (see escape-hatch comments in-source). + +When adding a new file-row action, the contract is: + +1. Render the `