Empty-graph chrome: Import Notes stays, search + settings wait for nodes

Owner ruling on the empty graph (honesty principle — dead controls are
lies): the top-chrome actions row now gates per control.

- Import Notes renders ALWAYS (graph enabled) — the one action that
  works on an empty graph, the entry point itself. It used to hide with
  everything else, leaving the empty state a dead end with no entry.
- Search + settings render only when the snapshot has nodes, and their
  appear-once mount carries a deliberate 200ms fade (graph-chrome-fade-in,
  globals.css — the settings-pop register, reduced-motion appears
  instantly). Computed animationName verified live.
- The row's body is now the exported pure GraphChromeRow (the
  DeleteNodeBody pattern) — the no-match note's truth (visibleIds +
  snapshot) stays upstream, computed by the wrapper.
- The empty-state placeholder copy is LEFT AS-IS (SCOPE rule: it already
  has copy — icon, title, and the session-mapping paragraph).

Pins (tests/render-graph-chrome.test.tsx): empty → Import Notes present,
search/settings absent, no fade carriers; populated → all three, exactly
two fade carriers; the no-match note follows its upstream truth. SSR of
GraphChromeRow both ways.

Live-verified on :3001 with scratch data: empty graph → Import Notes
only + placeholder intact; a real import through the button (file input
via DataTransfer) → nodes land, search + settings fade in (computed
chrome-fade-in on both carriers); wipe → reload → back to Import Notes
only (the reverse path). Scratch graph restored byte-identical.
932/932, tsc/lint/build green.
This commit is contained in:
amosblomqvist
2026-09-25 01:26:42 +03:00
parent 66090ed769
commit 81be55f35c
3 changed files with 196 additions and 57 deletions
+24
View File
@@ -438,6 +438,30 @@ body {
}
}
/* Graph chrome fade-in (empty-graph chrome wave, owner 2026-09-25): the
search + settings controls appear ONCE, as the first nodes land —
Import Notes always renders (the empty graph's entry point), the other
two mount only when the snapshot has nodes. Same understated register
as settings-pop (a plain fade); reduced-motion appears instantly. */
@keyframes chrome-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.graph-chrome-fade-in {
animation: chrome-fade-in 200ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
.graph-chrome-fade-in {
animation: none;
}
}
/* ─────────────────────────────────────────────────────────────────────────
Electron merged chrome (owner, 2026-09-17). The system title bar is
hidden (titleBarStyle: "hiddenInset" in electron/main.cjs); the app's