Spaces:
Running
MediaRouter Frontend Workspace Shell v1
Purpose
Workspace Shell v1 is the authenticated application frame around existing MediaRouter routes. It provides one responsive, accessibility-first navigation and command experience without changing page content, backend contracts, or feature business logic.
The shell is composed in frontend/components/app-shell.tsx and wraps the existing authenticated platform routes. Existing pages remain responsible for their own content while the shell owns global chrome only:
AppShell
βββ DiscoveryBootstrap
βββ WorkspaceSidebar
βββ WorkspaceTopbar
βββ existing route content
βββ GlobalSearch (lazy)
βββ WorkspaceActivityDrawer (lazy)
βββ WorkspaceKeyboardShortcuts
Architecture
The implementation builds on the Frontend Architecture v2 boundaries:
features/workspace/navigation/registry.tsis the one navigation manifest.useWorkspaceNavigation()resolves capabilities, permissions, feature flags, and plugin registrations before anything is rendered.features/workspace/stores/workspace-ui-store.tsholds shell-only transient UI state. Only the desktop sidebar collapse preference is persisted.features/commands/registry.tsis the command extension point. Shell commands are registered from resolved navigation rather than being embedded in the palette UI.- Existing shared API/query modules supply backend discovery, global search, and jobs. Shell components never call
fetch()directly.
Navigation
The desktop sidebar, tablet layout, mobile drawer, global search navigation group, and shell navigation commands all use the same manifest. A destination is rendered only if the route exists and its capability, permission, and feature flag requirements resolve for the signed-in user.
Currently enabled destinations, when authorized by backend metadata, are:
| Section | Destinations |
|---|---|
| Workspace | Home, Jobs |
| Create | Create (existing playground) |
| Library | Templates, Assets |
| Publish | Publish (existing social route) |
| Automation | Operations, MCP, API |
| Developer | Developer Portal |
| Settings | Settings, API Keys, Administration |
Sections with no existing authorized destination are omitted. Planned destinations such as Projects, AI Studio, Content Studio, Insights, Team, Calendars, Campaigns, Workflows, and Marketplace are deliberately absent. Their existing routes, where any exist, are preserved but are not advertised prematurely.
features/workspace/navigation/breadcrumbs.ts contains centralized route metadata used by the topbar. It generates route-aware breadcrumb hierarchies without page-specific breadcrumb definitions.
Sidebar and responsive behavior
- Desktop (
mdand above): persistent expanded/collapsed sidebar with hover expansion when collapsed. - Tablet: the same collapsible sidebar remains available.
- Mobile: the same resolved manifest renders inside an off-canvas navigation drawer. The drawer has a visible close control, closes when a destination is selected, and closes with Escape.
- All shell action controls and navigation rows meet a 44px minimum touch target.
- Sidebar collapse is activated with
β/Ctrl+B; on narrow screens this shortcut opens navigation instead.
The drawer backdrop is intentionally non-focusable. Focusable navigation is contained in the labeled drawer, and its close button is the accessible close action.
Workspace switcher and user menu
WorkspaceSwitcher accepts authoritative workspace and recent-workspace values through its typed adapter props. The current backend does not expose workspace membership/discovery or workspace creation endpoints, so the shell does not infer, create, or fabricate workspaces. It instead presents an explicit context-unavailable state until an authoritative adapter supplies data.
The user menu is route- and permission-aware. It exposes Profile, Preferences, Keyboard Shortcuts, Developer Portal when authorized, API Keys for administrators, and Logout. Workspace Settings is intentionally not shown because an authoritative workspace settings destination is not currently available.
Search and commands
The topbar opens global search with βK or Ctrl+K. The lazy-loaded palette combines only:
- already-authorized navigation destinations;
- commands currently registered through
CommandRegistry; and - results returned by the existing backend search/discovery layer, filtered against authorized routes.
There is no client-side mock search index and no fabricated results. Commands currently registered by the shell are resolved navigation commands plus Open activity and Show keyboard shortcuts. Product modules can add commands through features/commands/registry.ts; they should define their own capability/permission requirements and lazy-load the command implementation.
The existing design-system QuickActions primitive remains the extension point for a future floating action surface. Shell v1 deliberately renders no floating action because no upload, project-creation, AI-generation, publishing, import, or recording action has an authoritative implementation to register yet.
Activity and realtime
The lazy-loaded Activity Drawer uses the existing useLiveJobs() adapter only. It uses the existing jobs realtime subscription where the backend advertises one and falls back to the established job polling transport. It never invents jobs, notifications, upload progress, or AI activity:
- unavailable jobs capability: explicit unavailable state;
- no returned jobs: βYouβre all caught upβ; and
- backend jobs: real activity rows.
Notifications, uploads, AI, publishing, transcription, and collaboration can join the drawer later by adding shell-level adapters to their existing shared realtime infrastructure. They should not introduce a separate socket client or write directly into shell state.
Keyboard shortcuts
| Shortcut | Action |
|---|---|
βK / Ctrl+K |
Open global search and commands |
βB / Ctrl+B |
Toggle desktop sidebar; open mobile navigation |
βJ / Ctrl+J |
Open activity drawer |
Escape |
Close mobile navigation; Radix dialogs, menus, and drawers also close through their standard behavior |
Accessibility
The shell uses semantic navigation landmarks, aria-current for the active route, labeled icon controls, Radix focus management for menus/dialogs/drawers, visible design-system focus rings, keyboard operability, and the existing reduced-motion-aware Framer Motion presets. Semantic color tokens and the shared theme system support dark and high-contrast themes. Tooltip-only labels are not relied on for icon control names.
Extension points
To add a real future destination, first preserve the route and then add a navigation manifest entry with its capability, permission, and feature-flag requirements. Its command becomes available automatically when resolved shell commands are registered. To add a new global activity source, create an adapter above the existing realtime/query layer and provide real backend records only.
Do not add raw network calls to shell components, inspect environment variables in UI components, create duplicate Zustand stores, add placeholder counters/actions, or duplicate navigation arrays for mobile and desktop.
Validation
Focused tests cover manifest filtering, active routes, breadcrumbs, persisted shell preference, command registration, keyboard shortcuts, mobile drawer reuse, workspace-switcher no-data behavior, activity empty state, and user-menu authorization. Type checking and linting are part of the shell change validation. Production builds are attempted separately because Android/Termux may not provide Next/Turbopack or Storybook native bindings.