Rename Tape to Options and Replace the Web Rail

Created: 2026-05-23 19:36 EDT · Repo: islandflow · Branch: sidebar-redesign

Beads: islandflow-7ez Follow-up: islandflow-3by Scope: web shell, routing, desktop compatibility

Summary

The Tape surface is now presented to users as Options, with /options as the canonical web route and /tape preserved as a compatibility redirect. The shared web shell no longer reserves a persistent left rail; every route now gets full-width content under a sticky top header, with navigation, branding, and shell metrics moved into a top-left overlay drawer.

Changes Made

  • Added canonical web route /options via apps/web/app/options/page.tsx and changed apps/web/app/tape/page.tsx to redirect to it.
  • Updated route helpers in apps/web/app/terminal.tsx so /options is canonical while /tape remains accepted during transition.
  • Renamed top-level navigation copy from Tape to Options.
  • Replaced the persistent web rail with a sticky header plus overlay drawer in apps/web/app/terminal.tsx and apps/web/app/globals.css.
  • Changed the Options page layout to a full-width two-section stack: OptionsPane first, FlowPane below with title Packets, and removed EquitiesPane from this route.
  • Updated route, redirect, and desktop trust tests plus desktop README guidance to prefer /options while documenting /tape compatibility.

Context

This change consolidates two related UX issues: the product naming mismatch around the Tape surface, and the layout cost of the always-visible left rail. The product/design context for Islandflow emphasizes investigation workflows, stable rhythm under live updates, and full-width evidence surfaces over decorative chrome.

The drawer keeps navigation and shell instrumentation available without permanently consuming horizontal space on dense data routes.

Important Implementation Details

  • normalizeTerminalPathname() now treats /tape as an alias of /options, which keeps route-feature decisions, live subscriptions, and nav highlighting aligned from one helper.
  • The new Options route intentionally drops the Equities subscription and pane. The canonical route now subscribes only to options, nbbo, and flow.
  • The drawer closes on route change, backdrop click, and Escape via client-side state in TerminalAppShell.
  • Desktop trust remains origin-based, so no Electron security model change was required. The desktop updates only clarify preferred route examples and add explicit /options coverage.

Relevant Diff Snippets

apps/web/app/terminal.tsx · canonical /options routing and nav labels

- export const NAV_ITEMS = [
-   { href: "/", label: "Home" },
-   { href: "/tape", label: "Tape" },
-   { href: "/news", label: "News" }
- ] as const;
+ const CANONICAL_OPTIONS_PATH = "/options";
+ const TAPE_COMPAT_PATH = "/tape";
+ export const normalizeTerminalPathname = (pathname: string): string => {
+   if (pathname === TAPE_COMPAT_PATH) return CANONICAL_OPTIONS_PATH;
+   return KNOWN_TERMINAL_PATHS.has(pathname) ? pathname : "/";
+ };
+ export const NAV_ITEMS = [
+   { href: "/", label: "Home" },
+   { href: "/options", label: "Options" },
+   { href: "/news", label: "News" }
+ ] as const;

apps/web/app/terminal.tsx · sticky header, overlay drawer, and Options page layout

- <aside className="terminal-rail">...</aside>
+ const [drawerOpen, setDrawerOpen] = useState(false);
+ useEffect(() => { setDrawerOpen(false); }, [pathname]);
+ useEffect(() => {
+   if (!drawerOpen) return;
+   const handleKeyDown = (event: KeyboardEvent) => {
+     if (event.key === "Escape") setDrawerOpen(false);
+   };
+   document.addEventListener("keydown", handleKeyDown);
+   return () => document.removeEventListener("keydown", handleKeyDown);
+ }, [drawerOpen]);
+ <header className="terminal-topbar">
+   <button className="terminal-button terminal-menu-trigger">Menu</button>
+   ...
+ </header>
+ {drawerOpen ? <>...overlay drawer...</> : null}
- export function TapeRoute() {
-   return <PageFrame title="Tape">...<EquitiesPane />...</PageFrame>;
- }
+ export function OptionsRoute() {
+   return <PageFrame title="Options">...<FlowPane title="Packets" />...</PageFrame>;
+ }

apps/web/app/globals.css · full-width shell and drawer styling

- --rail-width: 236px;
- .terminal-shell { display: grid; grid-template-columns: var(--rail-width) minmax(0, 1fr); }
- .terminal-rail { ... }
- .page-grid-tape { grid-template-columns: minmax(0, 1.5fr) minmax(320px, 1fr); }
+ --drawer-width: min(320px, calc(100vw - 28px));
+ .terminal-shell { position: relative; min-height: 100vh; }
+ .terminal-nav-drawer { position: fixed; inset: 0 auto 0 0; width: var(--drawer-width); ... }
+ .terminal-drawer-backdrop { position: fixed; inset: 0; ... }
+ .terminal-topbar { justify-content: space-between; backdrop-filter: blur(12px); }
+ .page-grid-options { grid-template-columns: minmax(0, 1fr); }

route + desktop compatibility · redirect and trust coverage

+ // apps/web/app/options/page.tsx
+ import { OptionsRoute } from "../terminal";
+ export default function Page() {
+   return <OptionsRoute />;
+ }

- // apps/web/app/tape/page.tsx
- return <TapeRoute />;
+ redirect("/options");

+ expect(isTrustedAppUrl("https://flow.deltaisland.io/options?symbol=SPY")).toBe(true);
+ expect(isTrustedAppUrl("https://flow.deltaisland.io/tape?symbol=SPY")).toBe(true);

Snippets are rendered client-side with Diffs (diffs.com project) and include inline fallback text for offline viewing.

Expected Impact for End-Users

Users now land on a more clearly named Options route, keep old /tape links working, and get more horizontal space across the web app because navigation no longer consumes a permanent left column. The Options route is simpler and more focused: options flow first, packets below, without the Equities panel competing for width.

Validation

  • Passed: bun test apps/web/app/routes.test.ts apps/web/app/terminal.test.ts apps/desktop/src/security.test.ts (85 passing tests).
  • Passed: bun --cwd=apps/web run build including production build, TypeScript, and app-route generation for /options and /tape.
  • Skipped by request: browser visual probes for the drawer/header refactor.

Issues, Limitations, and Mitigations

  • The current web test suite is still mostly route/helper-level, so the new drawer interactions are not covered by DOM/browser tests yet. Mitigation: filed follow-up issue islandflow-3by.
  • Internal code still uses some Tape-named helpers and hooks. This was left intentionally to keep the rename low-risk while user-facing copy and routing moved to Options.
  • The Options route no longer shows Equities. That is intentional for layout clarity, but it does change the previous multi-pane surface composition.

Follow-up Work

  • islandflow-3by: add interaction coverage for drawer open/close, Escape dismissal, backdrop dismissal, and route-change dismissal.
  • If we later want a broader naming cleanup, isolate internal Tape* renames into a separate low-risk refactor rather than coupling them to route behavior again.