Rename Tape to Options and Replace the Web Rail
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
/optionsviaapps/web/app/options/page.tsxand changedapps/web/app/tape/page.tsxto redirect to it. - Updated route helpers in
apps/web/app/terminal.tsxso/optionsis canonical while/taperemains accepted during transition. - Renamed top-level navigation copy from
TapetoOptions. - Replaced the persistent web rail with a sticky header plus overlay drawer in
apps/web/app/terminal.tsxandapps/web/app/globals.css. - Changed the Options page layout to a full-width two-section stack:
OptionsPanefirst,FlowPanebelow with titlePackets, and removedEquitiesPanefrom this route. - Updated route, redirect, and desktop trust tests plus desktop README guidance to prefer
/optionswhile documenting/tapecompatibility.
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.
Important Implementation Details
normalizeTerminalPathname()now treats/tapeas 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, andflow. - The drawer closes on route change, backdrop click, and
Escapevia client-side state inTerminalAppShell. - Desktop trust remains origin-based, so no Electron security model change was required. The desktop updates only clarify preferred route examples and add explicit
/optionscoverage.
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 buildincluding production build, TypeScript, and app-route generation for/optionsand/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 toOptions. - 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,Escapedismissal, 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.