Skip to content

Commit

Permalink
Refactored navbar button system
Browse files Browse the repository at this point in the history
Now buttons are defined in code. This will let them more easily be duplicated
into the hamburger menu, hopefully.
  • Loading branch information
SimplyBoo6 committed Nov 29, 2023
1 parent 68ea9fe commit 35e37cb
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 128 deletions.
75 changes: 19 additions & 56 deletions client/src/app/components/navbar/navbar.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<nav class="navbar navbar-expand-xl navbar-dark bg-dark navbar-override fixed-top" [class.height-override]="!isExpanded">
<div class="container-fluid">
<div class="btn-group btn-group-toggle nav-button-group" *ngIf="getRoute() === '/viewer && showDirButtons'; else emptyNav" title="Toggle Tags">
<div class="btn-group btn-group-toggle nav-button-group" *ngIf="showToggleTags | async; else emptyNav" title="Toggle Tags">
<button class="btn btn-primary" (click)="toggleTagsOpen()">
<fa-icon [icon]="faTags" size="xl"></fa-icon>
</button>
Expand All @@ -10,55 +10,18 @@
<div class="btn-group"></div>
</ng-template>

<ng-container *ngIf="getRoute() === '/viewer' || getRoute() === '/metadata' || getRoute() === '/gallery' || getRoute() === '/clone-resolver'">
<div class="btn-group">
<button
*ngIf="(getRoute() === '/viewer' || getRoute() === '/metadata' || getRoute() === '/clone-resolver') && showDirButtons"
(click)="previousDirectory()"
class="btn btn-outline-success"
type="submit"
title="Previous Directory"
>
<fa-icon [icon]="faBackward" size="xl"></fa-icon>
</button>
<button class="btn btn-outline-success" type="submit" (click)="previous()" title="Previous">
<fa-icon [icon]="faArrowLeft" size="xl"></fa-icon>
</button>
<button *ngIf="getRoute() === '/gallery'" class="btn btn-outline-success" type="submit" (click)="collectionService.shuffle()" title="Shuffle">
<fa-icon [icon]="faShuffle" size="xl"></fa-icon>
</button>

<ng-container *ngIf="getRoute() === '/viewer' || getRoute() === '/metadata' || getRoute() === '/clone-resolver'">
<button class="btn btn-outline-success" type="submit" (click)="collectionService.deleteCurrent()" title="Delete">
<fa-icon [icon]="faTrash" size="xl"></fa-icon>
<div class="btn-group">
<ng-container *ngFor="let navItem of navItems; trackBy: trackNavItem">
<ng-container *ngIf="navItem.visible | async">
<button *ngIf="navItem.type === 'button'" class="btn btn-outline-success" [title]="navItem.title" (click)="navItem.click()">
<fa-icon [icon]="navItem.icon" size="xl"></fa-icon>
</button>
<button class="btn btn-outline-success" type="submit" (click)="viewFolder()" title="View Folder">
<fa-icon [icon]="faFolderOpen" size="xl"></fa-icon>
</button>
</ng-container>

<ng-container *ngIf="getRoute() === '/gallery'">
<div class="btn btn-outline-success paginator" type="submit" title="Page">{{ this.page.current + 1 }} of {{ this.page.max }}</div>
<div *ngIf="navItem.type === 'paginator' && (navItem.page | async) as page" class="btn btn-outline-success paginator" type="submit" title="Page">
{{ page.current + 1 }} of {{ page.max }}
</div>
</ng-container>

<button class="btn btn-outline-success" type="submit" (click)="collectionService.goto(getRoute() === '/gallery')" title="Goto">
<fa-icon [icon]="faDiamondTurnRight" size="xl"></fa-icon>
</button>

<button class="btn btn-outline-success" type="submit" (click)="next()" title="Next">
<fa-icon [icon]="faArrowRight" size="xl"></fa-icon>
</button>
<button
*ngIf="(getRoute() === '/viewer' || getRoute() === '/metadata' || getRoute() === '/clone-resolver') && showDirButtons"
class="btn btn-outline-success"
type="submit"
title="Next Directory"
(click)="nextDirectory()"
>
<fa-icon [icon]="faForward" size="xl"></fa-icon>
</button>
</div>
</ng-container>
</ng-container>
</div>

<button
class="navbar-toggler"
Expand All @@ -73,28 +36,28 @@

<div class="collapse navbar-collapse justify-content-end" id="navbarDefault" [ngbCollapse]="!isExpanded">
<ul class="navbar-nav">
<li class="nav-item" [class.active]="isActive('/viewer')">
<li class="nav-item" [class.active]="currentRoute === '/viewer'">
<a class="nav-link" routerLink="/viewer" (click)="isExpanded = false">Viewer</a>
</li>
<li class="nav-item" [class.active]="isActive('/metadata')">
<li class="nav-item" [class.active]="currentRoute === '/metadata'">
<a class="nav-link" routerLink="/metadata" (click)="isExpanded = false">Metadata</a>
</li>
<li class="nav-item" [class.active]="isActive('/clone-resolver')">
<li class="nav-item" [class.active]="currentRoute === '/clone-resolver'">
<a class="nav-link" routerLink="/clone-resolver" (click)="isExpanded = false">Clone Resolver</a>
</li>
<li class="nav-item" [class.active]="isActive('/gallery')">
<li class="nav-item" [class.active]="currentRoute === '/gallery'">
<a class="nav-link" routerLink="/gallery" (click)="isExpanded = false">Gallery</a>
</li>
<li class="nav-item" [class.active]="isActive('/search')">
<li class="nav-item" [class.active]="currentRoute === '/search'">
<a class="nav-link" routerLink="/search" (click)="isExpanded = false">Search</a>
</li>
<li class="nav-item" [class.active]="isActive('/playlists')">
<li class="nav-item" [class.active]="currentRoute === '/playlists'">
<a class="nav-link" routerLink="/playlists" (click)="isExpanded = false">Playlists</a>
</li>
<li class="nav-item" [class.active]="isActive('/config')">
<li class="nav-item" [class.active]="currentRoute === '/config'">
<a class="nav-link" routerLink="/config" (click)="isExpanded = false">Config</a>
</li>
<li class="nav-item" [class.active]="isActive('/insights')">
<li class="nav-item" [class.active]="currentRoute === '/insights'">
<a class="nav-link" routerLink="/insights" (click)="isExpanded = false">Insights</a>
</li>
</ul>
Expand Down
217 changes: 148 additions & 69 deletions client/src/app/components/navbar/navbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { UiService } from 'services/ui.service';
import { GalleryService, Page } from 'services/gallery.service';
import { CollectionService } from 'services/collection.service';
import { MediaService } from 'services/media.service';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Router, NavigationEnd } from '@angular/router';
import { Subscription, Observable, combineLatest } from 'rxjs';
import { map, filter } from 'rxjs/operators';
import {
faArrowLeft,
faArrowRight,
Expand All @@ -16,68 +17,182 @@ import {
faTrash,
faFolderOpen,
faDiamondTurnRight,
IconDefinition,
} from '@fortawesome/free-solid-svg-icons';

interface NavItemButton {
type: 'button';
click: () => void;
title: string;
icon: IconDefinition;
visible: Observable<boolean>;
}

interface NavItemPaginator {
type: 'paginator';
page: Observable<Page>;
visible: Observable<boolean>;
}

type NavItem = NavItemButton | NavItemPaginator;

@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss'],
})
export class NavbarComponent implements OnInit, OnDestroy {
public tagsOpen = false;
public collectionService: CollectionService;
public searchText?: string;
public isExpanded = false;
public page: Page = { current: 0, max: 0 };
protected showDirButtons: boolean = false;
protected readonly faArrowLeft = faArrowLeft;
protected readonly faArrowRight = faArrowRight;
protected tagsOpen = false;
protected collectionService: CollectionService;
protected searchText?: string;
protected isExpanded = false;
protected navItems: NavItem[];
protected readonly faTags = faTags;
protected readonly faBackward = faBackward;
protected readonly faForward = faForward;
protected readonly faShuffle = faShuffle;
protected readonly faTrash = faTrash;
protected readonly faFolderOpen = faFolderOpen;
protected readonly faDiamondTurnRight = faDiamondTurnRight;

private route: ActivatedRoute;
protected showToggleTags: Observable<boolean>;
protected currentRoute?: string;

private uiService: UiService;
private mediaService: MediaService;
private galleryService: GalleryService;
private subscriptions: Subscription[] = [];
private breakpointObserver: BreakpointObserver;
private routeObservable: Observable<string>;

public constructor(
collectionService: CollectionService,
uiService: UiService,
route: ActivatedRoute,
mediaService: MediaService,
galleryService: GalleryService,
breakpointObserver: BreakpointObserver,
router: Router,
) {
this.uiService = uiService;
this.collectionService = collectionService;
this.mediaService = mediaService;
this.route = route;
this.galleryService = galleryService;
this.breakpointObserver = breakpointObserver;

this.routeObservable = router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(event => (event as NavigationEnd).url),
);

const isBigScreenObservable = this.breakpointObserver.observe(Breakpoints.XSmall).pipe(map(result => !result.matches));
const singularUrls = ['/viewer', '/metadata', '/clone-resolve'];
const isSingularObservable = this.routeObservable.pipe(map(url => singularUrls.includes(url)));
const galleryUrl = '/gallery';
const isGalleryObservable = this.routeObservable.pipe(map(url => url === galleryUrl));
const navEnabledObservable = combineLatest([isSingularObservable, isGalleryObservable]).pipe(map(([isSingular, isGallery]) => isSingular || isGallery));

this.showToggleTags = combineLatest([isBigScreenObservable, this.routeObservable]).pipe(map(([isBigScreen, url]) => isBigScreen && url === '/viewer'));

this.navItems = [
{
type: 'button',
title: 'Previous Directory',
icon: faBackward,
click: () => uiService.offsetDirectory(-1),
visible: combineLatest([isBigScreenObservable, isSingularObservable]).pipe(
map(([isBigScreen, isSingular]) => {
return isBigScreen && isSingular;
}),
),
},
{
type: 'button',
title: 'Previous',
icon: faArrowLeft,
click: () => {
if (this.currentRoute) {
if (singularUrls.includes(this.currentRoute)) {
this.collectionService.offset(-1);
} else if (galleryUrl === this.currentRoute) {
this.galleryService.offset(-1);
}
}
},
visible: navEnabledObservable,
},
{
type: 'button',
title: 'Shuffle',
icon: faShuffle,
click: () => this.collectionService.shuffle(),
visible: isGalleryObservable,
},
{
type: 'button',
title: 'Delete',
icon: faTrash,
click: () => this.collectionService.deleteCurrent(),
visible: isSingularObservable,
},
{
type: 'button',
title: 'View Folder',
icon: faFolderOpen,
click: () => {
if (this.mediaService.media) {
const searchModel = this.uiService.createSearchModel();
searchModel.dir.like = this.mediaService.media.dir;
searchModel.sortBy = 'path';
this.uiService.searchModel.next(searchModel);
this.collectionService.search(this.uiService.createSearch(searchModel), { preserve: true });
}
},
visible: isSingularObservable,
},
{
type: 'paginator',
page: this.galleryService.page,
visible: isGalleryObservable,
},
{
type: 'button',
title: 'Goto',
icon: faDiamondTurnRight,
click: () => this.collectionService.goto(this.currentRoute === galleryUrl),
visible: navEnabledObservable,
},
{
type: 'button',
title: 'Next',
icon: faArrowRight,
click: () => {
if (this.currentRoute) {
if (singularUrls.includes(this.currentRoute)) {
this.collectionService.offset(1);
} else if (galleryUrl === this.currentRoute) {
this.galleryService.offset(1);
}
}
},
visible: navEnabledObservable,
},
{
type: 'button',
title: 'Next Directory',
icon: faForward,
click: () => uiService.offsetDirectory(1),
visible: combineLatest([isBigScreenObservable, isSingularObservable]).pipe(
map(([isBigScreen, isSingular]) => {
return isBigScreen && isSingular;
}),
),
},
];
}

public ngOnInit() {
this.updateTagPanelState();

this.subscriptions.push(this.galleryService.page.subscribe(page => (this.page = page)));
this.subscriptions.push(
this.uiService.searchModel.subscribe(searchModel => {
this.searchText = searchModel.keywords;
}),
);

this.subscriptions.push(
this.breakpointObserver.observe(Breakpoints.XSmall).subscribe(result => {
this.showDirButtons = !result.matches;
}),
);
this.subscriptions.push(this.routeObservable.subscribe(route => (this.currentRoute = route)));
}

public ngOnDestroy() {
Expand Down Expand Up @@ -114,14 +229,6 @@ export class NavbarComponent implements OnInit, OnDestroy {
this.isExpanded = false;
}

public isActive(route: string) {
return this.getRoute().startsWith(route);
}

public getRoute(): string {
return (this.route.snapshot as any)._routerState.url as string;
}

public toggleTagsOpen(): void {
this.tagsOpen = !this.tagsOpen;
this.updateTagPanelState();
Expand All @@ -131,41 +238,13 @@ export class NavbarComponent implements OnInit, OnDestroy {
this.uiService.setTagPanelState(this.tagsOpen);
}

public previous() {
switch (this.getRoute()) {
case '/viewer': // Fallthrough
case '/metadata': // Fallthough
case '/clone-resolver':
this.collectionService.offset(-1);
break;
case '/gallery':
this.galleryService.offset(-1);
break;
default:
break;
public trackNavItem(_: number, navItem: NavItem): string {
switch (navItem.type) {
case 'button':
return `button-${navItem.title}`;
case 'paginator':
// Only one.
return 'paginator';
}
}

public next() {
switch (this.getRoute()) {
case '/viewer': // Fallthrough
case '/metadata': // Fallthough
case '/clone-resolver':
this.collectionService.offset(1);
break;
case '/gallery':
this.galleryService.offset(1);
break;
default:
break;
}
}

public previousDirectory(): void {
this.uiService.offsetDirectory(-1);
}

public nextDirectory(): void {
this.uiService.offsetDirectory(1);
}
}
Loading

0 comments on commit 35e37cb

Please sign in to comment.