Skip to content

feat(ui): focus search that dims everything outside a match's neighbourhood - #8

Merged
thomasmarsh merged 1 commit into
thomasmarsh:mainfrom
jimmykirk:diagram-focus-search
Aug 16, 2026
Merged

feat(ui): focus search that dims everything outside a match's neighbourhood#8
thomasmarsh merged 1 commit into
thomasmarsh:mainfrom
jimmykirk:diagram-focus-search

Conversation

@jimmykirk

Copy link
Copy Markdown
Contributor

Problem

Whole-codebase diagrams stay hard to read even once they lay out sensibly and
zoom. Every node is drawn at full strength, so finding the part you care about
means visually filtering hundreds of nodes by hand. Zoom helps you get closer;
it does not help you find where to get closer to.

Change

A search box above any rendered diagram. Typing a name fades everything outside
the match's immediate neighbourhood to 7% opacity and outlines the matches in
gold. It reports the match count, and clearing restores the diagram.

It works on every diagram kind and needs no server support or extra request:
graphviz already writes the graph structure into the SVG it emits — each node
is a <g class="node"> whose <title> is its name, each edge a
<g class="edge"> whose <title> is from->to — so adjacency is rebuilt in
the browser from what is already on screen.

Two deliberate choices

One hop is kept, not just the match. A node alone with everything else
dimmed shows you where it is but not what it does. Its immediate neighbours are
what make the match legible, so they stay lit.

Non-matches are dimmed rather than hidden. The surrounding shape stays
faintly visible, so you keep your bearings in the graph — which matters most on
exactly the dense diagrams that motivate this. Filtering non-matches out
entirely would read cleaner and lose that context. Easy to flip if you prefer
the other trade.

Verification

In a browser against a real 3,045-object corpus (fk-graph, 61 nodes / 61 edges):

query result
exact node name 1 match; 59/61 nodes and 60/61 edges dimmed; the match and its one neighbour kept
substring 8 matches, 51 dimmed
no match nothing dimmed, reports "no match"
cleared fully restored, 0 dimmed

Four tests cover neighbourhood dimming, restore-on-clear, the no-match case,
and the box being absent before a diagram renders. pnpm typecheck clean;
pnpm test 980 passed / 75 files.

Note

This is independent of #7 and of the closure work in #6 — it touches only the
Diagrams view and one CSS block, and does not depend on either being taken.

…urhood

Whole-codebase diagrams stay saturated even once they are laid out
legibly and zoomable: every node is drawn at full strength, so finding
the part you care about means visually filtering hundreds of nodes by
hand.

This adds a search box above any rendered diagram. Typing a name fades
everything outside the match's immediate neighbourhood to 7% opacity and
outlines the matches. It applies to every diagram kind, with no server
support and no extra request, because graphviz already writes the graph
structure into the SVG it emits -- nodes carry their name in <title>,
edges carry "from->to" -- so adjacency is rebuilt from what is already on
screen.

Two deliberate choices:

  * One hop is kept, not just the match. A node alone with everything
    else dimmed shows where it is but not what it does; its neighbours
    are what make the match legible.

  * Non-matches are dimmed rather than hidden. The surrounding shape
    stays faintly visible, so you keep your bearings in the graph --
    which matters most on exactly the dense diagrams that motivate this.
    Filtering would read cleaner and lose that.

Verified in a browser against a real 3,045-object corpus: an exact node
name dimmed 59 of 61 nodes and 60 of 61 edges, keeping the match and its
one neighbour; a substring matched 8 and dimmed 51; a nonsense query left
the diagram untouched and reported "no match"; clearing restored
everything.

Four tests cover neighbourhood dimming, restore-on-clear, the no-match
case, and the box being absent before a diagram renders.
@jimmykirk

Copy link
Copy Markdown
Contributor Author

The CI failure here is not this change — it is failing on main too.

Every run since the merge of #1 fails identically, including the merge commits for #5 and #7:

failure   diagram-focus-search            <- this PR
failure   main                            <- merge of #7
failure   fix-coslice-output-sensitive
failure   main                            <- merge of #5
failure   fix-coslice-crossproduct
success   main                            <- merge of #1

It dies in Set up GHC, before anything is compiled:

[Error] The version '3.12.1.0' of the tool cabal is not installed.
Install error was: cabal-3.12.1.0 is already installed; if you really want to
                   reinstall it, you may want to run 'ghcup install cabal --force 3.12.1.0'
Set error was: The version '3.12.1.0' of the tool cabal is not installed.
##[error]All install methods for cabal 3.12.1.0 failed

ghcup reporting the same version as both already-installed and not-installed is the usual sign of a runner image update drifting against the toolchain in the cache. The workflow asks for cabal-version: "3.12", which now resolves to a build the cached ghcup state disagrees about.

Worth noting this PR could not have caused it regardless: it touches only Diagrams.tsx, its test file, and one CSS block — nothing the Haskell job builds.

Usual fixes are pinning the exact patch version (cabal-version: "3.12.1.0"), or busting the toolchain cache key. Happy to send a separate PR for that if it would help, though you may prefer to handle your own CI.

@thomasmarsh
thomasmarsh merged commit 141dd06 into thomasmarsh:main Aug 16, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants