Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[58454] Sidebar menu should be hidden when page width is reduced #17003

Merged
106 changes: 60 additions & 46 deletions frontend/src/app/core/main-menu/main-menu-toggle.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,18 @@ export class MainMenuToggleService {
private changeData = new BehaviorSubject<any>({});

public changeData$ = this.changeData.asObservable();
private wasHiddenDueToResize = false;

private wasCollapsedByUser = false;

constructor(
protected I18n:I18nService,
public injector:Injector,
readonly deviceService:DeviceService,
) {
this.initializeMenu();
// Add resize event listener
window.addEventListener('resize', this.onWindowResize.bind(this));
}

public initializeMenu():void {
Expand All @@ -80,45 +86,57 @@ export class MainMenuToggleService {
}

this.elementWidth = parseInt(window.OpenProject.guardedLocalStorage(this.localStorageKey) as string);
const menuCollapsed = window.OpenProject.guardedLocalStorage(this.localStorageStateKey) as string;
const menuCollapsed = window.OpenProject.guardedLocalStorage(this.localStorageStateKey) === 'true';

// Set the initial value of the collapse tracking flag
this.wasCollapsedByUser = menuCollapsed;

if (!this.elementWidth) {
this.saveWidth(this.mainMenu.offsetWidth);
} else if (menuCollapsed && JSON.parse(menuCollapsed)) {
} else if (menuCollapsed) {
this.closeMenu();
} else {
this.setWidth();
}

const currentProject:CurrentProjectService = this.injector.get(CurrentProjectService);
if (jQuery(document.body).hasClass('controller-my') && this.elementWidth === 0 || currentProject.id === null) {
this.saveWidth(this.defaultWidth);
}
this.adjustMenuVisibility();
}

// small desktop version default: hide menu on initialization
this.closeWhenOnSmallDesktop();
private onWindowResize():void {
this.adjustMenuVisibility();
}

private adjustMenuVisibility():void {
if (window.innerWidth >= 1012) {
// On larger screens, reopen the menu if it was hidden only due to screen resizing
if (this.wasHiddenDueToResize && !this.wasCollapsedByUser) {
this.setWidth(this.defaultWidth);
this.wasHiddenDueToResize = false; // Reset the flag since the menu is now shown
}
} else if (this.showNavigation) {
this.closeMenu();
this.wasHiddenDueToResize = true; // Indicate that the menu was hidden due to resize
}
}

// click on arrow or hamburger icon
public toggleNavigation(event?:JQuery.TriggeredEvent|Event):void {
if (event) {
event.stopPropagation();
event.preventDefault();
}

if (!this.showNavigation) { // sidebar is hidden -> show menu
if (this.deviceService.isSmallDesktop) { // small desktop version
this.setWidth(window.innerWidth);
} else { // desktop version
const savedWidth = parseInt(window.OpenProject.guardedLocalStorage(this.localStorageKey) as string);
const widthToSave = savedWidth >= this.elementMinWidth ? savedWidth : this.defaultWidth;
// Update the user collapse flag and clear `wasHiddenDueToResize`
this.wasCollapsedByUser = this.showNavigation;
this.wasHiddenDueToResize = false; // Reset because a manual toggle overrides any resize behavior

this.saveWidth(widthToSave);
}
} else { // sidebar is expanded -> close menu
if (this.showNavigation) {
this.closeMenu();
} else {
this.openMenu();
}

// Save the collapsed state in localStorage
window.OpenProject.guardedLocalStorage(this.localStorageStateKey, String(!this.showNavigation));
// Set focus on first visible main menu item.
// This needs to be called after AngularJS has rendered the menu, which happens some when after(!) we leave this
// method here. So we need to set the focus after a timeout.
Expand All @@ -129,48 +147,43 @@ export class MainMenuToggleService {

public closeMenu():void {
this.setWidth(0);
window.OpenProject.guardedLocalStorage(this.localStorageStateKey, 'true');
jQuery('.searchable-menu--search-input').blur();
}

public closeWhenOnSmallDesktop():void {
if (this.deviceService.isSmallDesktop) {
this.closeMenu();
window.OpenProject.guardedLocalStorage(this.localStorageStateKey, 'false');
}
}

public saveWidth(width?:number):void {
this.setWidth(width);
window.OpenProject.guardedLocalStorage(this.localStorageKey, String(this.elementWidth));
window.OpenProject.guardedLocalStorage(this.localStorageStateKey, String(this.elementWidth === 0));
public openMenu():void {
this.setWidth(this.defaultWidth);
}

public setWidth(width?:any):void {
public setWidth(width?:number):void {
if (width !== undefined) {
// Leave a minimum amount of space for space for the content
const maxMenuWidth = this.deviceService.isSmallDesktop ? window.innerWidth - 120 : window.innerWidth - 520;
if (width > maxMenuWidth) {
this.elementWidth = maxMenuWidth;
} else {
this.elementWidth = width as number;
}
this.elementWidth = width;
}

// Apply the width directly to the main menu
this.mainMenu.style.width = `${this.elementWidth}px`;

// Apply to root CSS variable for any related layout adjustments
this.htmlNode.style.setProperty('--main-menu-width', `${this.elementWidth}px`);

// Check if menu is open or closed and apply CSS class if needed
this.toggleClassHidden();
this.snapBack();
this.setToggleTitle();
this.toggleClassHidden();

this.global.showNavigation = this.showNavigation;
this.htmlNode.style.setProperty('--main-menu-width', `${this.elementWidth}px`);
// Save the width if it's open
if (this.elementWidth > 0) {
window.OpenProject.guardedLocalStorage(this.localStorageKey, String(this.elementWidth));
}
}

// Send change event when size of menu is changing (menu toggled or resized)
const changeEvent = jQuery.Event('change');
this.changeData.next(changeEvent);
public saveWidth(width?:number):void {
this.setWidth(width);
window.OpenProject.guardedLocalStorage(this.localStorageKey, String(this.elementWidth));
window.OpenProject.guardedLocalStorage(this.localStorageStateKey, String(this.elementWidth === 0));
}

public get showNavigation():boolean {
return (this.elementWidth >= this.elementMinWidth);
return this.elementWidth >= this.elementMinWidth;
}

private snapBack():void {
Expand All @@ -189,6 +202,7 @@ export class MainMenuToggleService {
}

private toggleClassHidden():void {
this.hideElements.toggleClass('hidden-navigation', !this.showNavigation);
const isHidden = this.elementWidth < this.elementMinWidth;
this.hideElements.toggleClass('hidden-navigation', isHidden);
}
}
Loading