fix(files): review round 1, the page — honest states, the keyboard, the tray's words

- A library past the list's cap is searched and sorted on the server; the count says "the newest".
- Each folder and each search opens on its first page (DataTable pageScope, useCardPager scope).
- A file dropped where the page takes none never reaches the browser (which would unload the app).
- The viewer's arrows wait while a layer opened from it is on top, and scroll a wide text line;
  a text shows its first 5000 lines and says where the rest is.
- Confirms name the file (no more "your downloads"); the asking menu rows end in "…".
- The tray names a running step beside its bar, shows a pause mark for paused work, polls slowly
  while only paused work waits, and forgets a finished file that was deleted.
- An unchanged rename sends nothing; a paste opens the download dialog only with nothing on top;
  the link box never replaces what was typed.
- Honest states: folders that failed to load, a file no longer there, the storage figure; the rail
  says "nothing downloaded" only when there is nothing.
- Focus after deleting the open folder and when the format form opens; the format name's label.
- ui/Meter (one danger line for both quota bars) and ui/RenameField in the platform layer.
- Copy fixes, stale comments and the speculative hub key; a contract test for the list's
  parameters; e2e: the Files page and the paste intake.
This commit is contained in:
2026-10-13 00:14:09 +02:00
parent 815083bcc4
commit 8b2260c9a8
41 changed files with 920 additions and 218 deletions
+6 -3
View File
@@ -1,4 +1,5 @@
import { ensureNavId, peekNavId } from "./history";
import { anyBlockingLayer } from "./layerStack";
import { createStore } from "./store";
// Downloading a link is an action you start anywhere: the Files page's link box, a link pasted onto
@@ -13,13 +14,15 @@ export function asDownloadLink(text: string | null | undefined): string | null {
return /^https?:\/\/\S+$/i.test(s) ? s : null;
}
/** Whether a paste here is the page's to take: not typed into a field, and no dialog on top (the
* reader is busy with that, and a link pasted at it is not a request to download). */
/** Whether a paste here is the page's to take: not typed into a field, and nothing on top that owns
* the keyboard — a dialog, a player, an open menu (the reader is busy with that, and a link pasted
* at it is not a request to download). The layer stack knows them all; a player marks no
* `aria-modal`, so the markup alone would miss it. */
export function pasteIsForThePage(target: EventTarget | null): boolean {
const el = target instanceof Element ? target : null;
if (el?.closest("input, textarea, select, [contenteditable]:not([contenteditable='false'])"))
return false;
return !document.querySelector("[aria-modal='true']");
return !anyBlockingLayer() && !document.querySelector("[aria-modal='true']");
}
/** Ask to download `url`: the app's download dialog opens on it. */