diff --git a/package-lock.json b/package-lock.json index e018842f..9a086bc4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "faceted-search", - "version": "2.0.0", + "version": "2.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "faceted-search", - "version": "2.0.0", + "version": "2.0.1", "dependencies": { "@angular/animations": "^14.2.12", "@angular/cdk": "^14.2.7", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 6d15cf1e..6838616a 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -9,5 +9,5 @@ import { Component } from '@angular/core' styleUrls: ['./app.component.scss'], }) export class AppComponent { - title = 'faceted-search' + title = 'Knowledge Explorer' } diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index b6be697b..d6c4a6ad 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -1,4 +1,4 @@ -
+

Knowledge Explorer: Discovery begins here.

diff --git a/src/app/nav/nav.component.html b/src/app/nav/nav.component.html index 4f121702..69b8495a 100644 --- a/src/app/nav/nav.component.html +++ b/src/app/nav/nav.component.html @@ -47,4 +47,8 @@
+ diff --git a/src/app/nav/nav.component.scss b/src/app/nav/nav.component.scss index ebaab409..2175476c 100644 --- a/src/app/nav/nav.component.scss +++ b/src/app/nav/nav.component.scss @@ -275,4 +275,21 @@ } } } + + .nav-display { + .breadcrumb { + position: absolute; + // Aligns under the logo, left justified + left: 0rem; + top: 7rem; + opacity: 50%; + } + .pagename { + position: absolute; + // Aligns under the logo, left justified + left: 0rem; + top: 10rem; + font-size: x-large; + } + } } diff --git a/src/app/nav/nav.component.ts b/src/app/nav/nav.component.ts index a742ce76..49b9841f 100644 --- a/src/app/nav/nav.component.ts +++ b/src/app/nav/nav.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core' +import { NavInfoService } from '../services/nav.service' +import { Subscription } from 'rxjs/internal/Subscription' /** * Component for the navigation bar. This component encompasses the navigation @@ -10,13 +12,43 @@ import { Component, OnInit } from '@angular/core' styleUrls: ['./nav.component.scss'], }) export class NavComponent implements OnInit { + breadcrumb: string = '' + pageName: string = '' + navChangedSub: Subscription + /** - * An empty constructor; this class is just markup and styling. + * Creates a new nav component. + * + * @param navInfoService: Service with a stream that contains new data to display in the nav area */ - constructor() {} + constructor(private navInfoService: NavInfoService) { + this.navChangedSub = navInfoService.onNavChanged.subscribe((event) => { + this.onNavigationChange(event) + }) + } /** * An empty ngOnInit to satisfy the constraints from OnInit. */ ngOnInit(): void {} + + /** + * Triggered when a page changes in a way that requires the navigation + * display to be updated. The new relative path and full path should be + * included in the fired event. + * + * @param event The navigation change event, carrying the new state information + */ + onNavigationChange(event: NavEvent) { + this.breadcrumb = event.fullPath + this.pageName = event.relativePath + } +} + +/** + * Template for a new navigation state + */ +export interface NavEvent { + relativePath: string + fullPath: string } diff --git a/src/app/search/search.component.ts b/src/app/search/search.component.ts index 7fdfc0fc..79fc73ac 100644 --- a/src/app/search/search.component.ts +++ b/src/app/search/search.component.ts @@ -1,8 +1,17 @@ import { ActivatedRoute, Router } from '@angular/router' -import { Component, OnInit, ChangeDetectorRef, ViewChild } from '@angular/core' +import { + Component, + OnInit, + ChangeDetectorRef, + ViewChild, + Output, + EventEmitter, +} from '@angular/core' import { MatTabChangeEvent } from '@angular/material/tabs' import { MatDialog, MatDialogConfig } from '@angular/material/dialog' import { ErrorModalComponent } from '../error-modal/error-modal.component' +import { NavEvent } from '../nav/nav.component' +import { NavInfoService } from '../services/nav.service' import { Location } from '@angular/common' /** @@ -45,6 +54,8 @@ export class SearchComponent implements OnInit { // Reference to the facets component @ViewChild('appfacets') public appfacets: any + // Event that emitted to the parent component, to tell the navigation component to update + @Output() navChange = new EventEmitter() /** * Called when a facet changes @@ -75,6 +86,7 @@ export class SearchComponent implements OnInit { * @param cd The change detector reference to catch events * @param route: The activated route for this page * @param router: The global router + * @param navInfoService: Service for sending information to the nav component * @param errorModal: A reference to the error modal dialog * @param location: Angular's 'Location' object for this path */ @@ -83,11 +95,13 @@ export class SearchComponent implements OnInit { private route: ActivatedRoute, private router: Router, private errorModal: MatDialog, + private navInfoService: NavInfoService, private location: Location ) { this.totalSize = 0 this.isCounting = true this.isSearching = true + this.navInfoService = navInfoService this.location = location } @@ -147,17 +161,31 @@ export class SearchComponent implements OnInit { case 2: clickedTabName = 'person' } + + this.navInfoService.onNavChanged.next({ + fullPath: `search/${clickedTabName}`, + relativePath: this.capitalizeFirstLetter(clickedTabName), + }) + const queryParams = { tab: clickedTabName } this.location.replaceState(`search?tab=${clickedTabName}`) } /** * When the initialization is ready, check to see if a particular tab should be - * navigated to. + * navigated to and update the nav. */ ngOnInit(): void { // Check to see if a particular tab should be loaded let tab = this.route.snapshot.queryParamMap.get('tab') + if (!tab) { + console.error('Failed to get the tab contents') + return + } + this.navInfoService.onNavChanged.next({ + fullPath: `search/${tab}`, + relativePath: this.capitalizeFirstLetter(tab), + }) switch (tab) { case 'place': @@ -219,4 +247,13 @@ export class SearchComponent implements OnInit { dialogConfig.height = '200px' this.errorModal.open(ErrorModalComponent, dialogConfig) } + + /** + * Makes the first letter in a prase upper cased + * @param phrase: The phrase being capitalized + * @returns 'phrase' but with the first letter of the first word upper cased + */ + capitalizeFirstLetter(phrase: string) { + return phrase.charAt(0).toUpperCase() + phrase.slice(1) + } } diff --git a/src/app/services/nav.service.ts b/src/app/services/nav.service.ts new file mode 100644 index 00000000..137c3fa2 --- /dev/null +++ b/src/app/services/nav.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core' +import { Subject } from 'rxjs/internal/Subject' + +/** + * Service for passing navigation page information from components to + * the navigation component. This is required because the navigation component + * lives in the app root, while other components are rendered conditionally through + * the router which makes it difficult to pass data to the parent app root. + */ +@Injectable({ + providedIn: 'root', +}) +export class NavInfoService { + // Event stream that holds new nav state + onNavChanged = new Subject() + + constructor() {} +}