From 22fce24bca258ae7f2dcbc394c8b1b7beb13d6bf Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Fri, 25 Jul 2025 17:02:17 +0200 Subject: [PATCH] refactor: migrate side panel over mode logic to signals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move isCustomOver logic from right-panel component to layout service - Implement using signals and computed properties for better performance - Add isRightPanelOverCustom computed signal in layout service - Maintain behavior: work-view routes use responsive mode, non-work-view routes force over mode unless on very big screens (≥1270px) - Update right-panel component to use the new signal-based API --- src/app/core-ui/layout/layout.service.ts | 48 +++++++++++++++++-- .../right-panel/right-panel.component.html | 4 +- .../right-panel/right-panel.component.ts | 12 +++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/app/core-ui/layout/layout.service.ts b/src/app/core-ui/layout/layout.service.ts index 689f586390..35ab89de0e 100644 --- a/src/app/core-ui/layout/layout.service.ts +++ b/src/app/core-ui/layout/layout.service.ts @@ -1,4 +1,4 @@ -import { inject, Injectable } from '@angular/core'; +import { inject, Injectable, computed } from '@angular/core'; import { hideAddTaskBar, hideIssuePanel, @@ -22,16 +22,18 @@ import { selectIsShowSideNav, selectIsShowTaskViewCustomizerPanel, } from './store/layout.reducer'; -import { filter, map, switchMap, withLatestFrom } from 'rxjs/operators'; +import { filter, map, switchMap, withLatestFrom, startWith } from 'rxjs/operators'; import { BreakpointObserver } from '@angular/cdk/layout'; -import { NavigationStart, Router } from '@angular/router'; +import { NavigationStart, NavigationEnd, Router } from '@angular/router'; import { WorkContextService } from '../../features/work-context/work-context.service'; import { selectMiscConfig } from '../../features/config/store/global-config.reducer'; +import { toSignal } from '@angular/core/rxjs-interop'; const NAV_ALWAYS_VISIBLE = 1200; const NAV_OVER_RIGHT_PANEL_NEXT = 800; const BOTH_OVER = 720; const XS_MAX = 599; +const VERY_BIG_SCREEN = 1270; @Injectable({ providedIn: 'root', @@ -62,6 +64,46 @@ export class LayoutService { isRightPanelOver$: Observable = this._breakPointObserver .observe([`(min-width: ${BOTH_OVER}px)`]) .pipe(map((result) => !result.matches)); + + // Signals for custom right panel behavior + private readonly _isVeryBigScreen = toSignal( + this._breakPointObserver + .observe([`(min-width: ${VERY_BIG_SCREEN}px)`]) + .pipe(map((result) => result.matches)), + { initialValue: false }, + ); + + private readonly _isWorkViewRoute = toSignal( + this._router.events.pipe( + filter((event): event is NavigationEnd => event instanceof NavigationEnd), + map((event) => this._isWorkViewUrl(event.urlAfterRedirects)), + startWith(this._isWorkViewUrl(this._router.url)), + ), + { initialValue: this._isWorkViewUrl(this._router.url) }, + ); + + private readonly _isRightPanelOverDefault = toSignal(this.isRightPanelOver$, { + initialValue: false, + }); + + // Computed signal for custom right panel over behavior + readonly isRightPanelOverCustom = computed(() => { + const isWorkView = this._isWorkViewRoute(); + const isVeryBigScreen = this._isVeryBigScreen(); + const defaultIsOver = this._isRightPanelOverDefault(); + + // Use default behavior if on work view + if (isWorkView) { + return defaultIsOver; + } + + // For non-work-view routes: use "over" mode unless on very big screen + return !isVeryBigScreen; + }); + + private _isWorkViewUrl(url: string): boolean { + return url.includes('/active/') || url.includes('/tag/') || url.includes('/project/'); + } isNavOver$: Observable = this._store$.select(selectMiscConfig).pipe( switchMap((miscCfg) => { if (miscCfg.isUseMinimalNav) { diff --git a/src/app/features/right-panel/right-panel.component.html b/src/app/features/right-panel/right-panel.component.html index 6eb8cdcce3..121e6ee926 100644 --- a/src/app/features/right-panel/right-panel.component.html +++ b/src/app/features/right-panel/right-panel.component.html @@ -1,7 +1,7 @@ @@ -25,7 +25,7 @@ } @else if (selectedTaskWithDelayForNone$ | async) { @let selectedTaskWithDelayForNone = selectedTaskWithDelayForNone$ | async; (false); + // Use the computed signal from layout service + readonly isCustomOver = computed(() => { + // Always use "over" mode for debugging + if (this.isAlwaysOver()) { + return true; + } + + // Use the layout service's computed signal + return this.layoutService.isRightPanelOverCustom(); + }); + // to still display its data when panel is closing selectedTaskWithDelayForNone$: Observable = this.taskService.selectedTask$.pipe(