mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
refactor(portal): move the header Back registry to shared data-access
WorkspaceBackNavigationService is root-provided signal state, which the Nx ownership contract assigns to type:data-access; type:util takes new pure helpers and contracts only. The service and its spec move to @iptvnator/portal/shared/data-access, and the pure WorkspaceBackTarget contract stays in @iptvnator/portal/shared/util. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c031a150d8
commit
930ef5e6c1
10 files changed
+30
-31
No files matched your search
@@ -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
|
||||
|
||||
+2
-4
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
+2
-4
@@ -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 {
|
||||
+2
-10
@@ -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<string | null>;
|
||||
/** True while Escape on the page runs the same action. */
|
||||
readonly escapeShortcut: Signal<boolean>;
|
||||
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
|
||||
@@ -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';
|
||||
|
||||
@@ -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<string | null>;
|
||||
/** True while Escape on the page runs the same action. */
|
||||
readonly escapeShortcut: Signal<boolean>;
|
||||
run(): void;
|
||||
}
|
||||
+1
-1
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
Reference in new issue
Block a user