Files
2026-05-03 23:36:48 +02:00

142 lines
5.3 KiB
Markdown

# Workspace Shell
This document records the current workspace-first shell contract. It is the
stable replacement for the older UI refactor summary.
Related:
- [Workspace Dashboard](./workspace-dashboard.md)
## Summary
- `/workspace` is the primary app surface.
- `WorkspaceShellComponent` owns the persistent frame: rail, header, optional
context panel, content outlet, and external playback footer.
- Descendant workspace pages inherit `layout = 'workspace'` from the
`/workspace` root route.
- Provider route trees now bootstrap through route-scoped session providers
instead of nested provider shell components.
Core implementation:
1. `apps/web/src/app/app.routes.ts`
2. `libs/workspace/shell/feature/src/lib/workspace-shell/workspace-shell.component.ts`
3. `libs/workspace/shell/feature/src/lib/workspace-shell/workspace-shell.component.html`
4. `libs/portal/shared/util/src/lib/navigation/portal-route.utils.ts`
5. `libs/portal/shared/util/src/lib/navigation/portal-rail-links.ts`
6. `libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.ts`
## Route Contract
Current workspace routes:
1. `/` -> `/workspace`
2. `/workspace` -> `/workspace/dashboard`
3. `/workspace/dashboard`
4. `/workspace/sources`
5. `/workspace/playlists/:id/:view`
6. `/workspace/global-favorites`
7. `/workspace/downloads`
8. `/workspace/settings`
9. `/workspace/xtreams/:id/...`
10. `/workspace/stalker/:id/...`
Compatibility redirect:
1. `/settings` -> `/workspace/settings`
Provider route integration:
1. `apps/web/src/app/app.routes.ts` marks the `/workspace` root route with
`data.layout = 'workspace'`.
2. `isWorkspaceLayoutRoute(...)` treats that layout marker as inherited route
state for all descendants.
3. Xtream and Stalker parent routes attach route-scoped session providers that
bootstrap the active playlist, sync provider section state, and clean up
provider-local state when the route is destroyed.
4. Workspace routes no longer rely on nested provider shell components for
hidden local chrome.
## Shell Structure
The shell is intentionally split into four persistent regions:
1. Left rail:
1. Static workspace links for dashboard, sources, global favorites, and recently viewed.
2. Provider-aware context links derived from the active or current playlist.
3. Settings remains a persistent footer shortcut in the rail.
2. Top header:
1. Playlist switcher.
2. Route-aware search input and command palette trigger.
3. Add source action.
4. Optional playlist refresh and route-specific shortcut actions.
5. Downloads shortcut in Electron.
3. Main body:
1. Optional left context panel.
2. Main router outlet content.
4. Optional footer:
1. External playback session bar when a docked session is visible.
## Context Panel Rules
The shell decides which secondary panel to show from the current route:
1. `/workspace/sources`
1. `WorkspaceSourcesFiltersPanelComponent`
2. Xtream category sections (`live`, `vod`, `series`)
1. `WorkspaceContextPanelComponent`
3. Stalker category sections (`itv`, `vod`, `series`)
1. `WorkspaceContextPanelComponent`
4. `/workspace/settings`
1. `WorkspaceSettingsContextPanelComponent`
5. Downloads sections
1. `WorkspaceCollectionContextPanelComponent`
The context panel is part of the shell contract. New workspace-level routes
should explicitly decide whether they need one rather than adding local
sidebars inside feature pages.
## Search And Navigation Rules
Search is shell-owned and route-aware:
1. Disabled on settings routes.
2. Enabled on sources routes.
3. Enabled for supported Xtream and Stalker content/search views.
4. Placeholder text and search handling vary by provider and section.
5. Input changes are debounced before route/store updates are applied.
Rail navigation is also shell-owned:
1. Workspace-global entries are static.
2. Provider entries come from `buildPortalRailLinks(...)`.
3. On dashboard, sources, settings, and global favorites, the shell falls back
to the currently selected playlist so provider navigation remains available
even outside a provider route.
Command palette behavior is shell-owned but view-extensible:
1. The shell resolves commands into three groups in fixed order: current view,
this playlist, then global.
2. Shell-owned commands are derived from route context and current playlist
state; empty groups are omitted instead of rendering disabled placeholders.
3. Workspace features contribute current-view commands through
`WorkspaceViewCommandService`.
4. Header shortcut actions can opt into palette exposure by attaching palette
metadata through `WorkspaceHeaderContextService`.
5. Filtering matches command labels, descriptions, and keywords, and keyboard
selection always lands on the first enabled command.
## Maintenance Guidance
Use this document as the source of truth when changing workspace shell behavior.
1. New top-level user destinations should default to child routes under
`/workspace`.
2. Shared provider navigation logic belongs in portal-shared util/UI libraries,
not duplicated inside the shell.
3. If a provider route changes how playlist/session bootstrap works, update the
route-session provider and shell-facing route contract together.
4. Historical migration notes, cleanup lists, and one-off refactor steps should
stay out of this file; track them in issues or PR notes instead.