Servicify menu, close menu on admin for small and medium screens
authorRigel Kent <sendmemail@rigelk.eu>
Sat, 7 Mar 2020 12:50:26 +0000 (13:50 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Tue, 10 Mar 2020 15:22:52 +0000 (16:22 +0100)
client/src/app/app-routing.module.ts
client/src/app/app.component.html
client/src/app/app.component.ts
client/src/app/core/core.module.ts
client/src/app/core/menu/index.ts [new file with mode: 0644]
client/src/app/core/menu/menu.service.ts [new file with mode: 0644]
client/src/app/core/routing/index.ts
client/src/app/core/routing/menu-guard.service.ts [new file with mode: 0644]
client/src/app/core/theme/theme.service.ts
client/src/app/shared/misc/screen.service.ts

index b5a677d15f21c30136006c78a1ae50666f5cf3c4..a87f4ce1babd219fe73280491451dffed623c004 100644 (file)
@@ -4,10 +4,13 @@ import { RouteReuseStrategy, RouterModule, Routes } from '@angular/router'
 import { PreloadSelectedModulesList } from './core'
 import { AppComponent } from '@app/app.component'
 import { CustomReuseStrategy } from '@app/core/routing/custom-reuse-strategy'
+import { MenuGuards } from '@app/core/routing/menu-guard.service'
 
 const routes: Routes = [
   {
     path: 'admin',
+    canActivate: [ MenuGuards.close() ],
+    canDeactivate: [ MenuGuards.open() ],
     loadChildren: () => import('./+admin/admin.module').then(m => m.AdminModule)
   },
   {
@@ -54,6 +57,7 @@ const routes: Routes = [
     })
   ],
   providers: [
+    MenuGuards.guards,
     PreloadSelectedModulesList,
     { provide: RouteReuseStrategy, useClass: CustomReuseStrategy }
   ],
index 54b320f796a81375a8c0103208b2c43f509f2682..d5fec61e6aae7ebb541b96c861bcb2a4b8d11cd1 100644 (file)
@@ -5,8 +5,8 @@
 <div [ngClass]="{ 'user-logged-in': isUserLoggedIn(), 'user-not-logged-in': !isUserLoggedIn() }">
   <div class="header">
 
-    <div class="top-left-block" [ngClass]="{ 'border-bottom': isMenuDisplayed === false }">
-      <span class="icon icon-menu" (click)="toggleMenu()"></span>
+    <div class="top-left-block" [ngClass]="{ 'border-bottom': menu.isMenuDisplayed === false }">
+      <span class="icon icon-menu" (click)="menu.toggleMenu()"></span>
 
       <a class="peertube-title" [routerLink]="defaultRoute" title="Homepage" i18n-title>
         <span class="icon icon-logo"></span>
       </a>
     </div>
 
-    <div class="header-right" [ngClass]="{ 'border-bottom': isMenuDisplayed === false }">
+    <div class="header-right" [ngClass]="{ 'border-bottom': menu.isMenuDisplayed === false }">
       <my-header class="w-100 d-flex justify-content-end"></my-header>
     </div>
   </div>
 
   <div class="sub-header-container">
-    <my-menu *ngIf="isMenuDisplayed"></my-menu>
+    <my-menu *ngIf="menu.isMenuDisplayed"></my-menu>
 
-    <div id="content" tabindex="-1" class="main-col container-fluid" [ngClass]="{ expanded: isMenuDisplayed === false }">
+    <div id="content" tabindex="-1" class="main-col container-fluid" [ngClass]="{ expanded: menu.isMenuDisplayed === false }">
 
       <div class="main-row">
         <router-outlet></router-outlet>
index 59966243b63ae02fbae0f714c1fbb835ee0ed4a3..629549ef234f253bcfe9b7b4f72e5710a131c1eb 100644 (file)
@@ -18,6 +18,7 @@ import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-
 import { ServerConfig, UserRole } from '@shared/models'
 import { User } from '@app/shared'
 import { InstanceService } from '@app/shared/instance/instance.service'
+import { MenuService } from './core/menu/menu.service'
 
 @Component({
   selector: 'my-app',
@@ -28,9 +29,6 @@ export class AppComponent implements OnInit {
   @ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
   @ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
 
-  isMenuDisplayed = true
-  isMenuChangedByUser = false
-
   customCSS: SafeHtml
 
   private serverConfig: ServerConfig
@@ -50,7 +48,8 @@ export class AppComponent implements OnInit {
     private themeService: ThemeService,
     private hooks: HooksService,
     private location: PlatformLocation,
-    private modalService: NgbModal
+    private modalService: NgbModal,
+    public menu: MenuService
   ) { }
 
   get instanceName () {
@@ -78,21 +77,12 @@ export class AppComponent implements OnInit {
       this.authService.refreshUserInformation()
     }
 
-    // Do not display menu on small screens
-    if (this.screenService.isInSmallView()) {
-      this.isMenuDisplayed = false
-    }
-
     this.initRouteEvents()
     this.injectJS()
     this.injectCSS()
 
     this.initHotkeys()
 
-    fromEvent(window, 'resize')
-      .pipe(debounceTime(200))
-      .subscribe(() => this.onResize())
-
     this.location.onPopState(() => this.modalService.dismissAll(POP_STATE_MODAL_DISMISS))
 
     this.openModalsIfNeeded()
@@ -102,15 +92,6 @@ export class AppComponent implements OnInit {
     return this.authService.isLoggedIn()
   }
 
-  toggleMenu () {
-    this.isMenuDisplayed = !this.isMenuDisplayed
-    this.isMenuChangedByUser = true
-  }
-
-  onResize () {
-    this.isMenuDisplayed = window.innerWidth >= 800 && !this.isMenuChangedByUser
-  }
-
   private initRouteEvents () {
     let resetScroll = true
     const eventsObs = this.router.events
@@ -176,7 +157,7 @@ export class AppComponent implements OnInit {
     eventsObs.pipe(
       filter((e: Event): e is GuardsCheckStart => e instanceof GuardsCheckStart),
       filter(() => this.screenService.isInSmallView())
-    ).subscribe(() => this.isMenuDisplayed = false) // User clicked on a link in the menu, change the page
+    ).subscribe(() => this.menu.isMenuDisplayed = false) // User clicked on a link in the menu, change the page
   }
 
   private injectJS () {
@@ -249,7 +230,7 @@ export class AppComponent implements OnInit {
       }, undefined, this.i18n('Focus the search bar')),
 
       new Hotkey('b', (event: KeyboardEvent): boolean => {
-        this.toggleMenu()
+        this.menu.toggleMenu()
         return false
       }, undefined, this.i18n('Toggle the left menu')),
 
index 5943af4da527c4ac62f341bba5b9e6dec5fc99ff..a1734ad80e7be4cc5b6e648b78a0984eb9d91fde 100644 (file)
@@ -13,6 +13,7 @@ import { throwIfAlreadyLoaded } from './module-import-guard'
 import { LoginGuard, RedirectService, UserRightGuard } from './routing'
 import { ServerService } from './server'
 import { ThemeService } from './theme'
+import { MenuService } from './menu'
 import { HotkeyModule } from 'angular2-hotkeys'
 import { CheatSheetComponent } from './hotkeys'
 import { ToastModule } from 'primeng/toast'
@@ -59,6 +60,7 @@ import { HooksService } from '@app/core/plugins/hooks.service'
     ConfirmService,
     ServerService,
     ThemeService,
+    MenuService,
     LoginGuard,
     UserRightGuard,
     UnloggedGuard,
diff --git a/client/src/app/core/menu/index.ts b/client/src/app/core/menu/index.ts
new file mode 100644 (file)
index 0000000..516a49a
--- /dev/null
@@ -0,0 +1 @@
+export * from './menu.service'
diff --git a/client/src/app/core/menu/menu.service.ts b/client/src/app/core/menu/menu.service.ts
new file mode 100644 (file)
index 0000000..46ef72e
--- /dev/null
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core'
+import { ScreenService } from '@app/shared/misc/screen.service'
+import { fromEvent } from 'rxjs'
+import { debounceTime } from 'rxjs/operators'
+
+@Injectable()
+export class MenuService {
+  isMenuDisplayed = true
+  isMenuChangedByUser = false
+
+  constructor(
+    private screenService: ScreenService
+  ) {
+    // Do not display menu on small screens
+    if (this.screenService.isInSmallView()) {
+      this.isMenuDisplayed = false
+    }
+
+    fromEvent(window, 'resize')
+      .pipe(debounceTime(200))
+      .subscribe(() => this.onResize())
+  }
+
+  toggleMenu () {
+    this.isMenuDisplayed = !this.isMenuDisplayed
+    this.isMenuChangedByUser = true
+  }
+
+  onResize () {
+    this.isMenuDisplayed = window.innerWidth >= 800 && !this.isMenuChangedByUser
+  }
+}
index 9f0b4eac5498ad214b43e6cd5c9b715c002f0292..58b83bb2aa90c0e397181fb95a6d748151253b77 100644 (file)
@@ -2,3 +2,4 @@ export * from './login-guard.service'
 export * from './user-right-guard.service'
 export * from './preload-selected-modules-list'
 export * from './redirect.service'
+export * from './menu-guard.service'
diff --git a/client/src/app/core/routing/menu-guard.service.ts b/client/src/app/core/routing/menu-guard.service.ts
new file mode 100644 (file)
index 0000000..907d145
--- /dev/null
@@ -0,0 +1,48 @@
+import { Injectable } from '@angular/core'
+import { CanActivate, CanDeactivate } from '@angular/router'
+import { MenuService } from '@app/core/menu'
+import { ScreenService } from '@app/shared/misc/screen.service'
+
+abstract class MenuGuard implements CanActivate, CanDeactivate<any> {
+  display = true
+  canDeactivate = this.canActivate
+
+  constructor (protected menu: MenuService, protected screen: ScreenService, display: boolean) {
+    this.display = display
+  }
+
+  canActivate (): boolean {
+    // small screens already have the site-wide onResize from screenService
+    // > medium screens have enough space to fit the administrative menus
+    if (!this.screen.isInMobileView() && this.screen.isInMediumView()) {
+      this.menu.isMenuDisplayed = this.display
+    }
+    return true
+  }
+}
+
+@Injectable()
+export class OpenMenuGuard extends MenuGuard {
+  constructor (menu: MenuService, screen: ScreenService) { super(menu, screen, true) }
+}
+
+@Injectable()
+export class CloseMenuGuard extends MenuGuard {
+  constructor (menu: MenuService, screen: ScreenService) { super(menu, screen, false) }
+}
+
+@Injectable()
+export class MenuGuards {
+  public static guards = [
+    OpenMenuGuard,
+    CloseMenuGuard
+  ]
+
+  static open () {
+    return OpenMenuGuard
+  }
+
+  static close () {
+    return CloseMenuGuard
+  }
+}
index 3c066ca7400be456ab9bf35294ac5ebb402c2d9a..c0189ad32029f85a4af9a6c22ede26fcab12ef25 100644 (file)
@@ -8,7 +8,6 @@ import { first } from 'rxjs/operators'
 import { User } from '@app/shared/users/user.model'
 import { UserService } from '@app/shared/users/user.service'
 import { LocalStorageService } from '@app/shared/misc/storage.service'
-import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage'
 
 @Injectable()
 export class ThemeService {
index 220d41d59b732736644afb5efff6c41de7dbb0cd..9c71a8c831587a5df2d7136145f9b537be039b8e 100644 (file)
@@ -14,6 +14,10 @@ export class ScreenService {
     return this.getWindowInnerWidth() < 800
   }
 
+  isInMediumView () {
+    return this.getWindowInnerWidth() < 1100
+  }
+
   isInMobileView () {
     return this.getWindowInnerWidth() < 500
   }