You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Vim navigation is per-page. Every view (info, ideas, economics, news cards, sketch metrics, AI trading panels, financials rows, SEC filings rows, sector items …) has its own j / k / h / l / Enter handler hand-coded in terminal.js. Each handler knows about the specific DOM structure it operates on. Side-effects:
New pages start broken. The crypto / forex / index / ETF stubs from Security types — foundation (routes + dispatch + legacy redirect) #98 ship with no tab navigation — pressing j/k does nothing because none of the existing per-page handlers match. The user has to mouse to switch tabs until each type's vim handler is bolted on.
Adding a new tab or section means editing both the page's render code AND the corresponding handler block in terminal.js. Easy to forget; easy to drift.
Cross-page nav semantics differ (e.g. j in news cards advances cards; j in AI tab enters content focus; j in financials tab enters rows). Inconsistent friction.
Insert mode (Esc) and search (s) work fine — they're global. Navigation should be too.
What we want
A first-class navigable element concept. Any element in any template can opt in by declaring itself navigable (e.g. data-vim="item" or a CSS class). The shared vim core handles:
j / k move focus to the next / previous navigable element in DOM order.
h / l move across a sibling group (tabs row, sub-tabs row, column grids) — defined by a navigable element being a "group".
Enter triggers the element's primary action (defined by data-vim-action="…" or by being a link / button).
Selected state via a single shared .vim-selected CSS class — no more per-page selection classes.
Scoping: a "focused container" (the current view's content area) is the default search root. Nested navigable groups can be entered/exited with j/k boundaries.
Page authors should add nav by adding attributes to the template, not by writing a JS handler.
Why this matters beyond consistency
This is a prerequisite for #94 (per-paragraph p → pop chart) and the broader "pin a paragraph + chart to an idea" goal. Once paragraphs are first-class navigable elements, pinning, sharing, and attachment all become annotations on the same primitive.
It also lets the new type-specific pages from #97 (crypto / forex / index / etf) ship navigation for free instead of duplicating the info-tab handlers four times.
Out of scope (for the eventual plan)
Not a complete rewrite of terminal.js — keep the global key dispatcher and the search bar / insert-mode plumbing as-is.
Not a swap to a framework. Vanilla JS, in-place refactor.
Pre-work / context
Current per-page handlers live in internal/server/static/terminal.js (see vimHandlers.{ideas, economics, watchlist, graph, news, info} and info._focus = main|sub|content).
The financials tab (_finGetRows), SEC tab (_secGetRows), trading-panels (_tradingVimHandler) all expose the same shape (rows + selected idx + enter handler) through window.* globals — strong signal these should unify.
When this gets picked up, plan it as its own epic with discrete migration issues per existing view.
Stub. Plan in detail when we get to it.
Problem
Vim navigation is per-page. Every view (
info,ideas,economics, news cards, sketch metrics, AI trading panels, financials rows, SEC filings rows, sector items …) has its ownj/k/h/l/Enterhandler hand-coded interminal.js. Each handler knows about the specific DOM structure it operates on. Side-effects:j/kdoes nothing because none of the existing per-page handlers match. The user has to mouse to switch tabs until each type's vim handler is bolted on.terminal.js. Easy to forget; easy to drift.jin news cards advances cards;jin AI tab enters content focus;jin financials tab enters rows). Inconsistent friction.Insert mode (
Esc) and search (s) work fine — they're global. Navigation should be too.What we want
A first-class navigable element concept. Any element in any template can opt in by declaring itself navigable (e.g.
data-vim="item"or a CSS class). The shared vim core handles:j/kmove focus to the next / previous navigable element in DOM order.h/lmove across a sibling group (tabs row, sub-tabs row, column grids) — defined by a navigable element being a "group".Entertriggers the element's primary action (defined bydata-vim-action="…"or by being a link / button)..vim-selectedCSS class — no more per-page selection classes.j/kboundaries.Page authors should add nav by adding attributes to the template, not by writing a JS handler.
Why this matters beyond consistency
This is a prerequisite for #94 (per-paragraph
p→ pop chart) and the broader "pin a paragraph + chart to an idea" goal. Once paragraphs are first-class navigable elements, pinning, sharing, and attachment all become annotations on the same primitive.It also lets the new type-specific pages from #97 (crypto / forex / index / etf) ship navigation for free instead of duplicating the info-tab handlers four times.
Out of scope (for the eventual plan)
terminal.js— keep the global key dispatcher and the search bar / insert-mode plumbing as-is.Pre-work / context
internal/server/static/terminal.js(seevimHandlers.{ideas, economics, watchlist, graph, news, info}andinfo._focus = main|sub|content).data-trading-vimattribute pattern — a small precedent for declarative nav._finGetRows), SEC tab (_secGetRows), trading-panels (_tradingVimHandler) all expose the same shape (rows + selected idx + enter handler) throughwindow.*globals — strong signal these should unify.When this gets picked up, plan it as its own epic with discrete migration issues per existing view.