From 24e7916c6897bbb38e057cdf1a102286006be964 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Wed, 5 Feb 2020 20:54:37 +0100 Subject: Add ListOverflow component to prevent sub-menu overflow --- .../app/shared/misc/list-overflow.component.html | 35 +++++++ .../app/shared/misc/list-overflow.component.scss | 61 +++++++++++ .../src/app/shared/misc/list-overflow.component.ts | 114 +++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 client/src/app/shared/misc/list-overflow.component.html create mode 100644 client/src/app/shared/misc/list-overflow.component.scss create mode 100644 client/src/app/shared/misc/list-overflow.component.ts (limited to 'client/src/app/shared/misc') diff --git a/client/src/app/shared/misc/list-overflow.component.html b/client/src/app/shared/misc/list-overflow.component.html new file mode 100644 index 000000000..986572801 --- /dev/null +++ b/client/src/app/shared/misc/list-overflow.component.html @@ -0,0 +1,35 @@ +
+ + + + + + + +
+ + +
+ + {{ item.label }} + +
+
+
+
+ + + + diff --git a/client/src/app/shared/misc/list-overflow.component.scss b/client/src/app/shared/misc/list-overflow.component.scss new file mode 100644 index 000000000..e26100aca --- /dev/null +++ b/client/src/app/shared/misc/list-overflow.component.scss @@ -0,0 +1,61 @@ +@import '_mixins'; + +:host { + width: 100%; +} + +.list-overflow-parent { + overflow: hidden; +} + +.list-overflow-menu { + position: absolute; + right: 0; +} + +button { + width: 30px; + border: none; + + &::after { + display: none; + } + + &.routeActive { + &::after { + display: inherit; + border: 2px solid var(--mainColor); + position: relative; + right: 95%; + top: 50%; + } + } +} + +::ng-deep .dropdown-menu { + margin-top: 0 !important; + position: static; + right: auto; + bottom: auto +} + +.modal-body { + 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; + } + } +} diff --git a/client/src/app/shared/misc/list-overflow.component.ts b/client/src/app/shared/misc/list-overflow.component.ts new file mode 100644 index 000000000..4f92c0f7c --- /dev/null +++ b/client/src/app/shared/misc/list-overflow.component.ts @@ -0,0 +1,114 @@ +import { + Component, + Input, + TemplateRef, + ViewChildren, + ViewChild, + QueryList, + ChangeDetectionStrategy, + ElementRef, + ChangeDetectorRef, + HostListener +} from '@angular/core' +import { NgbModal, NgbDropdown } from '@ng-bootstrap/ng-bootstrap' +import { uniqueId, lowerFirst } from 'lodash-es' +import { ScreenService } from './screen.service' +import { take } from 'rxjs/operators' + +export interface ListOverflowItem { + label: string + routerLink: string | any[] +} + +@Component({ + selector: 'list-overflow', + templateUrl: './list-overflow.component.html', + styleUrls: [ './list-overflow.component.scss' ], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ListOverflowComponent { + @ViewChild('modal', { static: true }) modal: ElementRef + @ViewChild('itemsParent', { static: true }) parent: ElementRef + @ViewChildren('itemsRendered') itemsRendered: QueryList + @Input() items: T[] + @Input() itemTemplate: TemplateRef<{item: T}> + + showItemsUntilIndexExcluded: number + active = false + isInTouchScreen = false + isInMobileView = false + + private openedOnHover = false + + constructor ( + private cdr: ChangeDetectorRef, + private modalService: NgbModal, + private screenService: ScreenService + ) {} + + isMenuDisplayed () { + return !!this.showItemsUntilIndexExcluded + } + + @HostListener('window:resize', ['$event']) + onWindowResize () { + this.isInTouchScreen = !!this.screenService.isInTouchScreen() + this.isInMobileView = !!this.screenService.isInMobileView() + + const parentWidth = this.parent.nativeElement.getBoundingClientRect().width + let showItemsUntilIndexExcluded: number + let accWidth = 0 + + for (const [index, el] of this.itemsRendered.toArray().entries()) { + accWidth += el.nativeElement.getBoundingClientRect().width + if (showItemsUntilIndexExcluded === undefined) { + showItemsUntilIndexExcluded = (parentWidth < accWidth) ? index : undefined + } + + const e = document.getElementById(this.getId(index)) + const shouldBeVisible = showItemsUntilIndexExcluded ? index < showItemsUntilIndexExcluded : true + e.style.visibility = shouldBeVisible ? 'inherit' : 'hidden' + } + + this.showItemsUntilIndexExcluded = showItemsUntilIndexExcluded + this.cdr.markForCheck() + } + + openDropdownOnHover (dropdown: NgbDropdown) { + this.openedOnHover = true + dropdown.open() + + // Menu was closed + dropdown.openChange + .pipe(take(1)) + .subscribe(() => this.openedOnHover = false) + } + + dropdownAnchorClicked (dropdown: NgbDropdown) { + if (this.openedOnHover) { + this.openedOnHover = false + return + } + + return dropdown.toggle() + } + + closeDropdownIfHovered (dropdown: NgbDropdown) { + if (this.openedOnHover === false) return + + dropdown.close() + this.openedOnHover = false + } + + toggleModal () { + this.modalService.open(this.modal, { centered: true }) + } + + dismissOtherModals () { + this.modalService.dismissAll() + } + + getId (id: number | string = uniqueId()): string { + return lowerFirst(this.constructor.name) + '_' + id + } +} -- cgit v1.2.3