mirror of https://github.com/Chocobozzz/PeerTube
Use modal instead of dropdown menu in small/mobile views (#2674)
Co-Authored-By: Rigel Kent <par@rigelk.eu>pull/2706/head
parent
c285180a45
commit
d363ef5360
|
@ -1,10 +1,20 @@
|
||||||
<div class="sub-menu">
|
<div class="sub-menu" [ngClass]="{ 'no-scroll': isModalOpened }">
|
||||||
<ng-container *ngFor="let menuEntry of menuEntries">
|
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
|
||||||
|
|
||||||
<a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>
|
<a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>
|
||||||
|
|
||||||
<div *ngIf="!menuEntry.routerLink" ngbDropdown [container]="container" class="parent-entry" #dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)">
|
<div *ngIf="!menuEntry.routerLink" ngbDropdown [container]="container" class="parent-entry"
|
||||||
|
#dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)">
|
||||||
<span
|
<span
|
||||||
|
*ngIf="isInSmallView"
|
||||||
|
[ngClass]="{ active: !!suffixLabels[menuEntry.label] }"
|
||||||
|
(click)="openModal(id)" role="button" class="title-page title-page-settings">
|
||||||
|
<ng-container i18n>{{ menuEntry.label }}</ng-container>
|
||||||
|
<ng-container *ngIf="!!suffixLabels[menuEntry.label]"> - {{ suffixLabels[menuEntry.label] }}</ng-container>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
*ngIf="!isInSmallView"
|
||||||
(mouseenter)="openDropdownOnHover(dropdown)" [ngClass]="{ active: !!suffixLabels[menuEntry.label] }" ngbDropdownAnchor
|
(mouseenter)="openDropdownOnHover(dropdown)" [ngClass]="{ active: !!suffixLabels[menuEntry.label] }" ngbDropdownAnchor
|
||||||
(click)="dropdownAnchorClicked(dropdown)" role="button" class="title-page title-page-settings"
|
(click)="dropdownAnchorClicked(dropdown)" role="button" class="title-page title-page-settings"
|
||||||
>
|
>
|
||||||
|
@ -20,6 +30,21 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ng-template #modal let-close="close" let-dismiss="dismiss">
|
||||||
|
<div class="modal-body">
|
||||||
|
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
|
||||||
|
<div [ngClass]="{ hidden: id !== currentMenuEntryIndex }">
|
||||||
|
<a *ngFor="let menuChild of menuEntry.children"
|
||||||
|
[ngClass]="{ icon: hasIcons }"
|
||||||
|
[routerLink]="menuChild.routerLink" routerLinkActive="active" (click)="dismissOtherModals()">
|
||||||
|
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName"></my-global-icon>
|
||||||
|
|
||||||
|
{{ menuChild.label }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -25,3 +25,32 @@
|
||||||
|
|
||||||
top: -1px;
|
top: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-menu.no-scroll {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
|
|
||||||
|
color: currentColor;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 9px 12px;
|
||||||
|
text-align: initial;
|
||||||
|
text-transform: unset;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: var(--mainBackgroundColor) !important;
|
||||||
|
background-color: var(--mainHoverColor);
|
||||||
|
opacity: .9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core'
|
import {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
ViewChild
|
||||||
|
} from '@angular/core'
|
||||||
import { filter, take } from 'rxjs/operators'
|
import { filter, take } from 'rxjs/operators'
|
||||||
import { NavigationEnd, Router } from '@angular/router'
|
import { NavigationEnd, Router } from '@angular/router'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { GlobalIconName } from '@app/shared/images/global-icon.component'
|
import { GlobalIconName } from '@app/shared/images/global-icon.component'
|
||||||
import { ScreenService } from '@app/shared/misc/screen.service'
|
import { ScreenService } from '@app/shared/misc/screen.service'
|
||||||
|
|
||||||
|
@ -26,31 +32,40 @@ export type TopMenuDropdownParam = {
|
||||||
export class TopMenuDropdownComponent implements OnInit, OnDestroy {
|
export class TopMenuDropdownComponent implements OnInit, OnDestroy {
|
||||||
@Input() menuEntries: TopMenuDropdownParam[] = []
|
@Input() menuEntries: TopMenuDropdownParam[] = []
|
||||||
|
|
||||||
|
@ViewChild('modal', { static: true }) modal: NgbModal
|
||||||
|
|
||||||
suffixLabels: { [ parentLabel: string ]: string }
|
suffixLabels: { [ parentLabel: string ]: string }
|
||||||
hasIcons = false
|
hasIcons = false
|
||||||
container: undefined | 'body' = undefined
|
container: undefined | 'body' = undefined
|
||||||
|
isModalOpened = false
|
||||||
|
currentMenuEntryIndex: number
|
||||||
|
|
||||||
private openedOnHover = false
|
private openedOnHover = false
|
||||||
private routeSub: Subscription
|
private routeSub: Subscription
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private modalService: NgbModal,
|
||||||
private screen: ScreenService
|
private screen: ScreenService
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
|
get isInSmallView () {
|
||||||
|
return this.screen.isInSmallView()
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.updateChildLabels(window.location.pathname)
|
this.updateChildLabels(window.location.pathname)
|
||||||
|
|
||||||
this.routeSub = this.router.events
|
this.routeSub = this.router.events
|
||||||
.pipe(filter(event => event instanceof NavigationEnd))
|
.pipe(filter(event => event instanceof NavigationEnd))
|
||||||
.subscribe(() => this.updateChildLabels(window.location.pathname))
|
.subscribe(() => this.updateChildLabels(window.location.pathname))
|
||||||
|
|
||||||
this.hasIcons = this.menuEntries.some(
|
this.hasIcons = this.menuEntries.some(
|
||||||
e => e.children && e.children.some(c => !!c.iconName)
|
e => e.children && e.children.some(c => !!c.iconName)
|
||||||
)
|
)
|
||||||
|
|
||||||
// We have to set body for the container to avoid scroll overflow on mobile view
|
// We have to set body for the container to avoid scroll overflow on mobile and small views
|
||||||
if (this.screen.isInMobileView()) {
|
if (this.isInSmallView) {
|
||||||
this.container = 'body'
|
this.container = 'body'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +100,27 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy {
|
||||||
this.openedOnHover = false
|
this.openedOnHover = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openModal (index: number) {
|
||||||
|
this.currentMenuEntryIndex = index
|
||||||
|
this.isModalOpened = true
|
||||||
|
|
||||||
|
this.modalService.open(this.modal, {
|
||||||
|
centered: true,
|
||||||
|
beforeDismiss: async () => {
|
||||||
|
this.onModalDismiss()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onModalDismiss () {
|
||||||
|
this.isModalOpened = false
|
||||||
|
}
|
||||||
|
|
||||||
|
dismissOtherModals () {
|
||||||
|
this.modalService.dismissAll()
|
||||||
|
}
|
||||||
|
|
||||||
private updateChildLabels (path: string) {
|
private updateChildLabels (path: string) {
|
||||||
this.suffixLabels = {}
|
this.suffixLabels = {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue