A notebook opens in its own order

The hand-made order is where a notebook's own arrangement lives:
separators show, rows can be put where they belong, nothing slides about
by itself. Starting in "last changed" made both of those look broken
until the sort menu was found — pressing "+ Separator" there drew a line
the order cannot display, so the button appeared dead. A notebook nobody
has arranged still reads newest-first, because untouched rows all carry
position 0, so nothing is lost by starting there. The views keep "last
changed": they are questions asked of every notebook at once and have
nowhere to keep an arrangement. The button that draws a line is now only
offered in the order that can show one.

Removing a chapter left you stuck in the confirmation. Every destructive
action goes through one helper that takes the question down again; this
one set the dialog directly and bypassed it, so the chapter was removed
and the prompt stayed over the app. Closing now happens where the dialog
is rendered, so it happens whoever asked and however they asked.

The suites did not catch that, and the reason is worth keeping: they
read the list straight through the overlay, which is in the DOM the
whole time, and passed while the screen was in fact stuck. Both now
assert the question is gone afterwards.

The separator is no wider than its name. It sat in a fixed 132px slot —
chosen so the row would not jump when renaming began — with a short name
floating in a gap it did not fill.

Thirteen suites green: 345 browser checks, 241 unit tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-12 21:45:03 +02:00
1 parent cc0b58dd2f
commit c96885d5b3
9 files changed
+223 -69

No files matched your search

+4
View File
@@ -14,6 +14,10 @@ export function ConfirmDialog({ title, message, confirmLabel = "Delete", onConfi
);
return (
<div
// Named so a test can say "and the question is gone afterwards". Without
// that, a check reads the list straight through the overlay and passes
// while the screen is in fact stuck behind it.
data-confirm-dialog
style={{
position: "fixed",
inset: 0,
+7 -6
View File
@@ -47,10 +47,11 @@ export function NameDialog({
inputRef.current?.select();
}, []);
const ready = !!name.trim();
const save = () => {
const trimmed = name.trim();
if (!trimmed) return;
onSave(trimmed, color);
if (!ready) return;
onSave(name.trim(), color);
onClose();
};
@@ -157,14 +158,14 @@ export function NameDialog({
</button>
<button
onClick={save}
disabled={!name.trim()}
disabled={!ready}
style={{
padding: "8px 18px",
borderRadius: 10,
border: "none",
background: name.trim() ? T.accent : T.border,
background: ready ? T.accent : T.border,
color: "#fff",
cursor: name.trim() ? "pointer" : "default",
cursor: ready ? "pointer" : "default",
fontSize: 13,
fontWeight: 600,
}}