Skip to content

Commit

Permalink
On mobile view ports, remove the dropdown button and scroll to top. D…
Browse files Browse the repository at this point in the history
…ropdown button links are now visible in a modal to make clicking much easier.
  • Loading branch information
majora2007 committed Aug 11, 2024
1 parent 2c7979f commit 81c7ba4
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 33 deletions.
54 changes: 32 additions & 22 deletions UI/Web/src/app/nav/_components/nav-header/nav-header.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -159,40 +159,50 @@
}
</ul>


@if (!searchFocused) {
@if (backToTopNeeded) {
<div class="back-to-top">
<button class="btn btn-icon scroll-to-top" (click)="scrollToTop()">
<i class="fa fa-angle-double-up nav" aria-hidden="true"></i>
<span class="visually-hidden">{{t('scroll-to-top-alt')}}</span>
</button>
</div>
@if((breakpoint$ | async)! > Breakpoint.Tablet) {
@if (backToTopNeeded) {
<div class="back-to-top">
<button class="btn btn-icon scroll-to-top" (click)="scrollToTop()">
<i class="fa fa-angle-double-up nav" aria-hidden="true"></i>
<span class="visually-hidden">{{t('scroll-to-top-alt')}}</span>
</button>
</div>
}
}

@if (accountService.currentUser$ | async; as user) {
<div class="nav-item">
<app-nav-events-toggle [user]="user"></app-nav-events-toggle>
</div>
<div class="nav-item not-xs-only">
<a routerLink="/settings" [fragment]="SettingsTabId.Preferences" class="dark-exempt btn btn-icon" [title]="t('settings')">
<i class="fa fa-cogs nav" aria-hidden="true"></i>
<span class="visually-hidden">{{t('settings')}}</span>
</a>
</div>


<div ngbDropdown class="nav-item dropdown" display="dynamic" placement="bottom-right">
<button class="btn btn-outline-secondary primary-text" ngbDropdownToggle>
@if((breakpoint$ | async)! <= Breakpoint.Mobile) {
<button class="btn btn-outline-secondary primary-text" (click)="openLinkSelectionMenu()">
<i class="fa-solid fa-user-circle align-self-center phone-hidden d-xs-inline-block d-sm-inline-block d-md-none"></i>
<span class="d-none d-xs-none d-sm-none d-md-inline-block">{{user.username | sentenceCase}}</span>
</button>
<div ngbDropdownMenu>
<a ngbDropdownItem routerLink="/all-filters/">{{t('all-filters')}}</a>
<a ngbDropdownItem routerLink="/announcements/">{{t('announcements')}}</a>
<a ngbDropdownItem [href]="WikiLink.Guides" rel="noopener noreferrer" target="_blank">{{t('help')}}</a>
<a ngbDropdownItem (click)="logout()">{{t('logout')}}</a>
} @else {
<div class="nav-item not-xs-only">
<a routerLink="/settings" [fragment]="SettingsTabId.Preferences" class="dark-exempt btn btn-icon" [title]="t('settings')">
<i class="fa fa-cogs nav" aria-hidden="true"></i>
<span class="visually-hidden">{{t('settings')}}</span>
</a>
</div>
</div>

<div ngbDropdown class="nav-item dropdown d-sm-none d-md-block" display="dynamic" placement="bottom-right">
<button class="btn btn-outline-secondary primary-text" ngbDropdownToggle>
<i class="fa-solid fa-user-circle align-self-center phone-hidden d-xs-inline-block d-sm-inline-block d-md-none"></i>
<span class="d-none d-xs-none d-sm-none d-md-inline-block">{{user.username | sentenceCase}}</span>
</button>
<div ngbDropdownMenu>
<a ngbDropdownItem routerLink="/all-filters/">{{t('all-filters')}}</a>
<a ngbDropdownItem routerLink="/announcements/">{{t('announcements')}}</a>
<a ngbDropdownItem [href]="WikiLink.Guides" rel="noopener noreferrer" target="_blank">{{t('help')}}</a>
<a ngbDropdownItem (click)="logout()">{{t('logout')}}</a>
</div>
</div>
}
}
}

Expand Down
35 changes: 25 additions & 10 deletions UI/Web/src/app/nav/_components/nav-header/nav-header.component.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {AsyncPipe, DOCUMENT, NgOptimizedImage} from '@angular/common';
import {AsyncPipe, DOCUMENT, NgOptimizedImage, NgTemplateOutlet} from '@angular/common';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
ElementRef,
ElementRef, HostListener,
inject,
Inject,
OnInit,
ViewChild
} from '@angular/core';
import {NavigationEnd, Router, RouterLink, RouterLinkActive} from '@angular/router';
import {fromEvent} from 'rxjs';
import {BehaviorSubject, fromEvent, Observable} from 'rxjs';
import {debounceTime, distinctUntilChanged, filter, tap} from 'rxjs/operators';
import {Chapter} from 'src/app/_models/chapter';
import {UserCollection} from 'src/app/_models/collection-tag';
Expand All @@ -29,12 +29,12 @@ import {SearchService} from 'src/app/_services/search.service';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {SentenceCasePipe} from '../../../_pipes/sentence-case.pipe';
import {PersonRolePipe} from '../../../_pipes/person-role.pipe';
import {NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle} from '@ng-bootstrap/ng-bootstrap';
import {NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle, NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {EventsWidgetComponent} from '../events-widget/events-widget.component';
import {SeriesFormatComponent} from '../../../shared/series-format/series-format.component';
import {ImageComponent} from '../../../shared/image/image.component';
import {GroupedTypeaheadComponent, SearchEvent} from '../grouped-typeahead/grouped-typeahead.component';
import {TranslocoDirective} from "@jsverse/transloco";
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {FilterUtilitiesService} from "../../../shared/_services/filter-utilities.service";
import {FilterStatement} from "../../../_models/metadata/v2/filter-statement";
import {FilterField} from "../../../_models/metadata/v2/filter-field";
Expand All @@ -48,6 +48,10 @@ import {PromotedIconComponent} from "../../../shared/_components/promoted-icon/p
import {SettingsTabId} from "../../../sidenav/preference-nav/preference-nav.component";
import {Breakpoint, UtilityService} from "../../../shared/_services/utility.service";
import {WikiLink} from "../../../_models/wiki";
import {
GenericListModalComponent
} from "../../../statistics/_components/_modals/generic-list-modal/generic-list-modal.component";
import {NavLinkModalComponent} from "../nav-link-modal/nav-link-modal.component";

@Component({
selector: 'app-nav-header',
Expand All @@ -57,7 +61,7 @@ import {WikiLink} from "../../../_models/wiki";
standalone: true,
imports: [RouterLink, RouterLinkActive, NgOptimizedImage, GroupedTypeaheadComponent, ImageComponent,
SeriesFormatComponent, EventsWidgetComponent, NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgbDropdownItem,
AsyncPipe, PersonRolePipe, SentenceCasePipe, TranslocoDirective, ProviderImagePipe, ProviderNamePipe, CollectionOwnerComponent, PromotedIconComponent]
AsyncPipe, PersonRolePipe, SentenceCasePipe, TranslocoDirective, ProviderImagePipe, ProviderNamePipe, CollectionOwnerComponent, PromotedIconComponent, NgTemplateOutlet]
})
export class NavHeaderComponent implements OnInit {

Expand All @@ -71,6 +75,7 @@ export class NavHeaderComponent implements OnInit {
protected readonly navService = inject(NavService);
protected readonly imageService = inject(ImageService);
protected readonly utilityService = inject(UtilityService);
protected readonly modalService = inject(NgbModal);

protected readonly FilterField = FilterField;
protected readonly WikiLink = WikiLink;
Expand All @@ -90,6 +95,15 @@ export class NavHeaderComponent implements OnInit {
searchFocused: boolean = false;
scrollElem: HTMLElement;

breakpointSource = new BehaviorSubject<Breakpoint>(this.utilityService.getActiveBreakpoint());
breakpoint$: Observable<Breakpoint> = this.breakpointSource.asObservable();

@HostListener('window:resize', ['$event'])
@HostListener('window:orientationchange', ['$event'])
onResize(){
this.breakpointSource.next(this.utilityService.getActiveBreakpoint());
}

constructor(@Inject(DOCUMENT) private document: Document) {
this.scrollElem = this.document.body;
}
Expand Down Expand Up @@ -134,10 +148,6 @@ export class NavHeaderComponent implements OnInit {
this.document.getElementById('content')?.focus();
}





onChangeSearch(evt: SearchEvent) {
this.isLoading = true;
this.searchTerm = evt.value.trim();
Expand Down Expand Up @@ -290,4 +300,9 @@ export class NavHeaderComponent implements OnInit {
this.navService.toggleSideNav();
}

openLinkSelectionMenu() {
const ref = this.modalService.open(NavLinkModalComponent, {fullscreen: 'sm'});
ref.componentInstance.logoutFn = this.logout.bind(this);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@


<ng-container *transloco="let t; read:'nav-header'">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{t('nav-link-header')}}</h4>
<button type="button" class="btn-close" [attr.aria-label]="t('close')" (click)="close()"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<a routerLink="/settings" [fragment]="SettingsTabId.Preferences" [title]="t('settings')">{{t('settings')}}</a>
</div>
<div class="mb-3">
<a routerLink="/all-filters/">{{t('all-filters')}}</a>
</div>
<div class="mb-3">
<a routerLink="/announcements/">{{t('announcements')}}</a>
</div>
<div class="mb-3">
<a [href]="WikiLink.Guides" rel="noopener noreferrer" target="_blank">{{t('help')}}</a>
</div>
<div class="mb-3">
<a href="javascript:void(0);" (click)="logout()">{{t('logout')}}</a>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" (click)="close()">{{t('close')}}</button>
</div>

</ng-container>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {Component, inject, Input} from '@angular/core';
import {WikiLink} from "../../../_models/wiki";
import {NgbActiveModal, NgbDropdownItem} from "@ng-bootstrap/ng-bootstrap";
import {RouterLink} from "@angular/router";
import {FilterPipe} from "../../../_pipes/filter.pipe";
import {ReactiveFormsModule} from "@angular/forms";
import {Select2Module} from "ng-select2-component";
import {TranslocoDirective} from "@jsverse/transloco";
import {SettingsTabId} from "../../../sidenav/preference-nav/preference-nav.component";

@Component({
selector: 'app-nav-link-modal',
standalone: true,
imports: [
NgbDropdownItem,
RouterLink,
FilterPipe,
ReactiveFormsModule,
Select2Module,
TranslocoDirective
],
templateUrl: './nav-link-modal.component.html',
styleUrl: './nav-link-modal.component.scss'
})
export class NavLinkModalComponent {

@Input({required: true}) logoutFn!: () => void;

private readonly modal = inject(NgbActiveModal);

protected readonly WikiLink = WikiLink;

close() {
this.modal.close();
}

logout() {
this.logoutFn();
}

protected readonly SettingsTabId = SettingsTabId;
}
4 changes: 3 additions & 1 deletion UI/Web/src/assets/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,9 @@
"help": "{{common.help}}",
"announcements": "Announcements",
"logout": "Logout",
"all-filters": "Smart Filters"
"all-filters": "Smart Filters",
"nav-link-header": "Navigation Options",
"close": "{{common.close}}"
},

"promoted-icon": {
Expand Down

0 comments on commit 81c7ba4

Please sign in to comment.