-
-
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.
-