feat(ui): the search palette, entry points and a trail that survives the URL (CG-45)
Search: `/` or ⌘K focuses the box; results arrive grouped by kind with their
glyph, signature and file:line, ↑/↓/Enter walk them, Esc dismisses. A group
appears where its best result did, so flattening the groups reproduces the
ranking the keyboard walks — the panel's flat item list IS that concatenation.
A flow question ("how does X reach Y", "X -> Y") is recognised and searches
both endpoints with a note, rather than offering a row that would land on the
phase-2 Flow view.
Entry points answer "where do I start" on the empty screen and in the resting
palette, all derived from the graph: routes, files that run something at module
level (the engine records a top-level statement as an edge out of the file node,
which is what makes src/bin/codegraph.ts the root of the CLI flow — ranked by
calls x the files they reach, so a registration table calling into itself does
not outrank the CLI), and the most depended-on symbols. Tests are excluded from
both derived lists.
Trail: hops record the direction they were walked (→ into a call, ← up to a
caller), clicking one truncates back to it, Clear keeps the place instead of
throwing it away, and the whole walk travels in the URL. A shared or reloaded
trail arrives as ids, so hops learn their names back through a new batch
endpoint and a session name cache — without it, walking back across a
truncation redrew earlier hops as raw hashes. "Read as flow" stays hidden until
there is a Flow view to send it to.
New endpoints: /api/entrypoints and /api/nodes. New engine reads:
getTopCallingFiles, getFileDependentCounts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e9596af1cf
commit
87afc50e76
+10
-4
@@ -9,11 +9,9 @@
|
||||
import FlowView from './views/FlowView.svelte';
|
||||
import NotFoundView from './views/NotFoundView.svelte';
|
||||
import { router, navigate, back, mapHref, flowHref } from './lib/router.svelte';
|
||||
import { trail } from './lib/trail.svelte';
|
||||
import { trail, resolveTrailNames } from './lib/trail.svelte';
|
||||
import { project } from './lib/project.svelte';
|
||||
|
||||
let query = $state('');
|
||||
|
||||
// One `/api/stats` for the whole app: the top bar's counts and the Symbol
|
||||
// view's blast-radius denominator come out of the same payload.
|
||||
$effect(() => {
|
||||
@@ -37,6 +35,14 @@
|
||||
});
|
||||
});
|
||||
|
||||
// Hops restored from a URL carry ids and nothing else; one batched request
|
||||
// turns the bar back into names. Runs after every trail change, and does
|
||||
// nothing when every hop already has one.
|
||||
$effect(() => {
|
||||
void trail.hops.length;
|
||||
void resolveTrailNames();
|
||||
});
|
||||
|
||||
function isTypingTarget(target: EventTarget | null): boolean {
|
||||
if (!(target instanceof HTMLElement)) return false;
|
||||
return (
|
||||
@@ -84,7 +90,7 @@
|
||||
|
||||
<svelte:window {onkeydown} />
|
||||
|
||||
<TopBar bind:this={topbar} bind:query project={project.name} stats={project.summary} />
|
||||
<TopBar bind:this={topbar} project={project.name} stats={project.summary} />
|
||||
<TrailBar />
|
||||
<main>
|
||||
{#if route.view === 'symbol'}
|
||||
|
||||
Reference in New Issue
Block a user