diff --git a/docs/architecture/portal-detail-navigation.md b/docs/architecture/portal-detail-navigation.md index 3b66e8676..4ce2e3f1c 100644 --- a/docs/architecture/portal-detail-navigation.md +++ b/docs/architecture/portal-detail-navigation.md @@ -25,12 +25,13 @@ catalog scroll positions retain the existing navigation contract below. The shell owns the page's Back action, but the workspace header renders it. While `backAvailable()` is true, the shell registers a target with -`WorkspaceBackNavigationService` (`@iptvnator/portal/shared/util`): a label (the -host's `backLabel`, else the translated "Back"), whether Escape currently runs -it, and `run()`, which emits `backClicked`. The service keeps a stack in which -the newest registration wins, and each release removes only its own target. A -loading shell replaced by the loaded one therefore cannot clear its successor, -whichever is destroyed first. The header shows the target as an `arrow_back` +`WorkspaceBackNavigationService` (`@iptvnator/portal/shared/data-access`). The +target, the `WorkspaceBackTarget` contract in `@iptvnator/portal/shared/util`, +carries a label (the host's `backLabel`, else the translated "Back"), whether +Escape currently runs it, and `run()`, which emits `backClicked`. The service +keeps a stack in which the newest registration wins, and each release removes +only its own target. A loading shell replaced by the loaded one therefore +cannot clear its successor, whichever is destroyed first. The header shows the target as an `arrow_back` icon button in its leading slot (`data-test-id="workspace-header-back"`), to the right of the macOS traffic lights. That is where desktop apps and Material's top app bar keep navigation. The header never scrolls, so the control stays diff --git a/libs/portal/downloads/feature/src/lib/offline-detail/download-offline-detail.component.spec.ts b/libs/portal/downloads/feature/src/lib/offline-detail/download-offline-detail.component.spec.ts index 163ae5104..f3eb0a1e7 100644 --- a/libs/portal/downloads/feature/src/lib/offline-detail/download-offline-detail.component.spec.ts +++ b/libs/portal/downloads/feature/src/lib/offline-detail/download-offline-detail.component.spec.ts @@ -10,10 +10,8 @@ import { SettingsStore, } from '@iptvnator/services'; import type { DownloadMetadataSnapshot } from '@iptvnator/shared/interfaces'; -import { - WorkspaceBackNavigationService, - type WorkspaceNavigationTarget, -} from '@iptvnator/portal/shared/util'; +import { WorkspaceBackNavigationService } from '@iptvnator/portal/shared/data-access'; +import type { WorkspaceNavigationTarget } from '@iptvnator/portal/shared/util'; import { BehaviorSubject } from 'rxjs'; import type { DownloadActionResult, diff --git a/libs/portal/shared/data-access/src/index.ts b/libs/portal/shared/data-access/src/index.ts index e6ea97322..f34f8b9d1 100644 --- a/libs/portal/shared/data-access/src/index.ts +++ b/libs/portal/shared/data-access/src/index.ts @@ -6,3 +6,5 @@ export * from './lib/live-channel-playback-queue'; export * from './lib/source-health.service'; export * from './lib/source-cleanup.service'; + +export * from './lib/workspace-back-navigation.service'; diff --git a/libs/portal/shared/util/src/lib/workspace-back-navigation.service.spec.ts b/libs/portal/shared/data-access/src/lib/workspace-back-navigation.service.spec.ts similarity index 93% rename from libs/portal/shared/util/src/lib/workspace-back-navigation.service.spec.ts rename to libs/portal/shared/data-access/src/lib/workspace-back-navigation.service.spec.ts index 5a4bd2bba..a229d8e42 100644 --- a/libs/portal/shared/util/src/lib/workspace-back-navigation.service.spec.ts +++ b/libs/portal/shared/data-access/src/lib/workspace-back-navigation.service.spec.ts @@ -1,9 +1,7 @@ import { signal } from '@angular/core'; import { TestBed } from '@angular/core/testing'; -import { - WorkspaceBackNavigationService, - WorkspaceBackTarget, -} from './workspace-back-navigation.service'; +import { WorkspaceBackTarget } from '@iptvnator/portal/shared/util'; +import { WorkspaceBackNavigationService } from './workspace-back-navigation.service'; describe('WorkspaceBackNavigationService', () => { function createService(): WorkspaceBackNavigationService { diff --git a/libs/portal/shared/util/src/lib/workspace-back-navigation.service.ts b/libs/portal/shared/data-access/src/lib/workspace-back-navigation.service.ts similarity index 74% rename from libs/portal/shared/util/src/lib/workspace-back-navigation.service.ts rename to libs/portal/shared/data-access/src/lib/workspace-back-navigation.service.ts index e64397a51..ec983282a 100644 --- a/libs/portal/shared/util/src/lib/workspace-back-navigation.service.ts +++ b/libs/portal/shared/data-access/src/lib/workspace-back-navigation.service.ts @@ -1,13 +1,5 @@ -import { computed, Injectable, Signal, signal } from '@angular/core'; - -/** A page's Back action, rendered in the workspace header's leading slot. */ -export interface WorkspaceBackTarget { - /** Accessible name and tooltip; null falls back to the generic "Back". */ - readonly label: Signal; - /** True while Escape on the page runs the same action. */ - readonly escapeShortcut: Signal; - run(): void; -} +import { computed, Injectable, signal } from '@angular/core'; +import { WorkspaceBackTarget } from '@iptvnator/portal/shared/util'; /** * Owns the header's Back slot. Pages register while they offer Back; the most diff --git a/libs/portal/shared/util/src/index.ts b/libs/portal/shared/util/src/index.ts index 10fc54308..583980bc1 100644 --- a/libs/portal/shared/util/src/index.ts +++ b/libs/portal/shared/util/src/index.ts @@ -23,7 +23,7 @@ export * from './lib/category-sort-state.service'; export * from './lib/keyboard'; export * from './lib/keyboard-shortcuts'; export * from './lib/remote-channel-navigation'; -export * from './lib/workspace-back-navigation.service'; +export * from './lib/workspace-back-target'; export * from './lib/workspace-header-context.service'; export * from './lib/workspace-view-command.types'; export * from './lib/workspace-view-command.service'; diff --git a/libs/portal/shared/util/src/lib/workspace-back-target.ts b/libs/portal/shared/util/src/lib/workspace-back-target.ts new file mode 100644 index 000000000..0c4ebcba1 --- /dev/null +++ b/libs/portal/shared/util/src/lib/workspace-back-target.ts @@ -0,0 +1,10 @@ +import { Signal } from '@angular/core'; + +/** A page's Back action, rendered in the workspace header's leading slot. */ +export interface WorkspaceBackTarget { + /** Accessible name and tooltip; null falls back to the generic "Back". */ + readonly label: Signal; + /** True while Escape on the page runs the same action. */ + readonly escapeShortcut: Signal; + run(): void; +} diff --git a/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.spec.ts b/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.spec.ts index c68093d25..3b540b449 100644 --- a/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.spec.ts +++ b/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.spec.ts @@ -1,7 +1,7 @@ import { Component, signal } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; -import { WorkspaceBackNavigationService } from '@iptvnator/portal/shared/util'; +import { WorkspaceBackNavigationService } from '@iptvnator/portal/shared/data-access'; import { DetailActionsTemplateDirective, DetailMetaTemplateDirective, diff --git a/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.ts b/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.ts index fd2e4e822..9eab2c209 100644 --- a/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.ts +++ b/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.ts @@ -12,10 +12,8 @@ import { output, ChangeDetectionStrategy, } from '@angular/core'; -import { - WorkspaceBackNavigationService, - WorkspaceBackTarget, -} from '@iptvnator/portal/shared/util'; +import { WorkspaceBackNavigationService } from '@iptvnator/portal/shared/data-access'; +import { WorkspaceBackTarget } from '@iptvnator/portal/shared/util'; import { ContentHeroComponent } from '../content-hero/content-hero.component'; import { ContentAboutComponent } from './content-about.component'; import { diff --git a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts index 1989ded30..d1f53bf6e 100644 --- a/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts +++ b/libs/workspace/shell/feature/src/lib/workspace-shell/services/workspace-shell.facade.ts @@ -3,9 +3,9 @@ import { toSignal } from '@angular/core/rxjs-interop'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { startWith } from 'rxjs'; +import { WorkspaceBackNavigationService } from '@iptvnator/portal/shared/data-access'; import { PORTAL_EXTERNAL_PLAYBACK, - WorkspaceBackNavigationService, WorkspaceHeaderContextService, WorkspaceResolvedCommandItem, } from '@iptvnator/portal/shared/util';