fix(editor): der Sperr-Dialog wählt das andere Dokument im Aufklapp-Feld — die Knopfliste quetschte ihre Beschriftungen ineinander

Gemeldet aus der produktiven Instanz: „die Buttons mit den anderen
Dokumenten überlappen sich und sind unleserlich". Ursache ist eine
Flexbox-Falle, nicht die Zahl der Dokumente: Die Liste war ein
flex-Spaltenkasten mit max-height 9rem, und ihre Knöpfe tragen serienmäßig
flex-shrink 1 — statt zu scrollen, schrumpfte der Kasten sie unter ihre
eigene Textzeile. Nachgemessen bei acht Dokumenten: 14,5 px Kastenhöhe
gegen 32 px Inhalt, 17,5 px Überstand je Knopf bei 4 px Abstand.

Statt der naheliegenden Reparatur (flex-shrink 0, dann scrollt die Liste)
das vom Nutzer gewählte Aufklapp-Feld: eine Zeile hoch, unabhängig von der
Anzahl — der Dialog steckt im Editor-Panel und ist dort ohnehin knapp. Die
Kopfzeile ist jetzt ein echtes <label for>, der Platzhalter ein Strich,
die Auswahl schaltet sofort um (dieselbe Ein-Klick-Geste wie der Knopf).
Kein neuer i18n-Schlüssel.

Nachgemessen: Feld 36 px, kein Überstand, Karte 364 -> 256 px; Auswahl
schaltet um, Dialog schließt, Textfeld wird beschreibbar. D94-Nachtrag und
CHANGELOG nachgezogen; 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-09-02 20:16:58 +02:00
co-authored by Claude Opus 5
parent 4bb9b768b0
commit 7f4c2a3e6a
4 changed files with 60 additions and 17 deletions
+1
View File
@@ -23,6 +23,7 @@ reverse.
- A document created, renamed or deleted in another window shows up without a reload now, and a document deleted elsewhere while open here stays until you type — typing brings it back
- The modal "open more than once" dialog is gone; the one remaining loss case — the same non-shared document open in two windows — is found by a per-document lock, and the second window chooses: open another document, view only until the other window lets go, or edit anyway
- The other-window warning now names the document and says whether it is open in the app or in the browser — and stays silent when nothing collides
- Fix: in the "open in another window" dialog the list of other documents squeezed its buttons until the names ran into each other — picking one is a dropdown now, one line tall however many documents you have
- An MCP server for AI agents recorded as planned: it lives in the backend, runs the one JS parser through GraalJS, hands plans to Claude Code and other agents as resources and tools over streamable HTTP, and writes changes as conflict-safe line diffs — no new runtime, spelled out in an RFC before it is built
## 2026-08-28
+32
View File
@@ -8974,6 +8974,38 @@ mit; Gegenprobe per Mutation gezogen — ohne die Zeile bleibt der Index ohne
das Dokument, während Meta und Text dastehen. Sonst heilt sich der Index
von selbst, weil `indexHint()` die Speicher-Schlüssel mitliest.
**Nachtrag — die Auswahl im Sperr-Dialog ist ein Aufklapp-Feld
(2026-09-02).** Gemeldet aus der produktiven Instanz: „Die Buttons mit den
anderen Dokumenten überlappen sich und sind unleserlich." Die Ursache ist
nicht die Zahl der Dokumente, sondern eine Flexbox-Falle: Die Liste war ein
`flex`-Spaltenkasten mit gedeckelter Höhe (9rem), und ihre Knöpfe tragen
serienmäßig `flex-shrink: 1` — statt zu scrollen, schrumpfte der Kasten sie
unter ihre eigene Textzeile. Nachgemessen bei acht Dokumenten: 14,5 px
Kastenhöhe gegen 32 px Inhalt, also 17,5 px Überstand je Knopf bei 4 px
Abstand — die Beschriftungen liefen ineinander.
Zwei Wege standen offen: `flex-shrink: 0` (dann scrollt die Liste wirklich)
oder ein **Aufklapp-Feld**. Entschieden (Nutzer): das Aufklapp-Feld. Es ist
**eine Zeile hoch, unabhängig von der Anzahl** — und der Dialog liegt in
einem Kasten, der auf dem Telefon oder bei kleinem Editor-Panel ohnehin
knapp ist; eine Liste, die mit der Dokumentenzahl wächst, bleibt dort auch
scrollend unhandlich. Die Auswahl aus vielen gleichartigen Dingen ist
zudem genau das, wofür ein Aufklapp-Feld die vertraute Geste ist.
Gebaut mit dem vorhandenen Vokabular: die Kopfzeile ist jetzt ein echtes
`<label for>`, das Feld trägt einen deaktivierten Platzhalter („—"), und
die Auswahl schaltet sofort um — dieselbe Ein-Klick-Geste wie zuvor der
Knopf. **Kein neuer i18n-Schlüssel**: Der Platzhalter ist ein Strich, den
Kontext trägt das vorhandene `docLockOpenOther`.
**Nachgemessen** im Browser bei acht Dokumenten: Feld 36 px hoch, kein
Überstand (2 px), Karte von 364 auf 256 px geschrumpft; die Auswahl
schaltet um, der Dialog schließt, das Textfeld wird beschreibbar. **Benannt,
nicht behoben:** Ist das Editor-Panel sehr flach (gemessen 172 px, weil das
Diagramm die Höhe hat), ist die Karte immer noch höher als der getönte
Grund, in dem sie steckt, und malt darüber hinaus. Lesbar bleibt sie; wen
es stört, deckelt `.lockdlg` mit `max-height`.
**Offen bleibt die Handarbeit** (RFC §10): installierte PWA neben einem Tab,
Firefox, Safari, ein Browser ohne Locks-API. Werkzeuggrenzen wie gehabt —
die Browser-Fläche war verborgen, getippt wurde per `value` + `input`
+18 -10
View File
@@ -207,27 +207,35 @@ function enterLockDialog(id){
ov.className = 'lockdlg-overlay';
ov.innerHTML = '<div class="lockdlg" role="alertdialog" aria-modal="false">' +
'<h2></h2><p></p>' +
'<div class="lockdlg-listhead"></div><div class="lockdlg-list" role="listbox"></div>' +
'<label class="lockdlg-listhead" for="lockdlgPick"></label>' +
'<select class="lockdlg-pick" id="lockdlgPick"></select>' +
'<div class="lockdlg-btns">' +
'<button type="button" class="lockdlg-view"></button>' +
'<button type="button" class="lockdlg-edit"></button></div></div>';
ov.querySelector('h2').textContent = t('docLockTitle', {name: d.name});
ov.querySelector('p').textContent = t('docLockText');
const kopf = ov.querySelector('.lockdlg-listhead');
const liste = ov.querySelector('.lockdlg-list');
const wahl = ov.querySelector('.lockdlg-pick');
const andere = docs.filter(x => x.id !== id);
/* Ein Aufklapp-Feld statt einer Knopfliste: Die Liste wuchs mit der Zahl
der Dokumente, und in ihrem gedeckelten Kasten schrumpften die Knöpfe
(flex-shrink) unter ihre Textzeile gemessen 14,5 px Kasten gegen
32 px Inhalt, also lief die Beschriftung in die nächste hinein. Ein
Aufklapp-Feld ist immer eine Zeile hoch, unabhängig von der Anzahl,
und die Auswahl ist die vertraute Geste dafür. */
if(andere.length){
kopf.textContent = t('docLockOpenOther');
const leer = document.createElement('option');
leer.value = ''; leer.textContent = '—'; leer.selected = true; leer.disabled = true;
wahl.appendChild(leer);
for(const x of andere){
const b = document.createElement('button');
b.type = 'button';
b.className = 'lockdlg-doc';
b.setAttribute('role', 'option');
b.textContent = x.name;
b.addEventListener('click', () => switchDoc(x.id));
liste.appendChild(b);
const o = document.createElement('option');
o.value = x.id;
o.textContent = x.name;
wahl.appendChild(o);
}
} else { kopf.hidden = true; liste.hidden = true; }
wahl.addEventListener('change', () => { if(wahl.value) switchDoc(wahl.value); });
} else { kopf.hidden = true; wahl.hidden = true; }
const ansehen = ov.querySelector('.lockdlg-view');
const trotzdem = ov.querySelector('.lockdlg-edit');
ansehen.textContent = t('docLockViewOnly');
+9 -7
View File
@@ -1734,14 +1734,16 @@
}
.lockdlg h2{margin:0 0 10px;font-size:1.05rem;color:var(--line)}
.lockdlg p{margin:0 0 12px;line-height:1.45}
.lockdlg-listhead{font-size:.78rem;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);margin:0 0 6px}
.lockdlg-list{display:flex;flex-direction:column;gap:4px;max-height:9rem;overflow-y:auto;margin:0 0 14px}
.lockdlg-doc{
text-align:left;padding:6px 10px;font:inherit;cursor:pointer;
border:1px solid rgba(36,52,71,.3);border-radius:7px;background:none;color:var(--ink);
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
.lockdlg-listhead{display:block;font-size:.78rem;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);margin:0 0 6px}
/* Aufklapp-Feld statt Knopfliste: eine Zeile hoch, egal wie viele Dokumente
es gibt — die Liste schrumpfte ihre Knöpfe sonst unter deren eigene
Textzeile (D94-Nachtrag). */
.lockdlg-pick{
display:block;width:100%;max-width:100%;box-sizing:border-box;margin:0 0 14px;
padding:6px 10px;font:inherit;cursor:pointer;
border:1px solid rgba(36,52,71,.3);border-radius:7px;background:var(--paper);color:var(--ink);
}
.lockdlg-doc:hover{border-color:var(--or)}
.lockdlg-pick:hover{border-color:var(--or)}
.lockdlg-btns{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap}
.lockdlg-btns button{
padding:7px 14px;border-radius:7px;font:inherit;cursor:pointer;