diff --git a/aio/src/app/app.component.spec.ts b/aio/src/app/app.component.spec.ts index 9aa28f33ae..422c3ccb42 100644 --- a/aio/src/app/app.component.spec.ts +++ b/aio/src/app/app.component.spec.ts @@ -254,6 +254,24 @@ describe('AppComponent', () => { }); }); + describe('hostClasses', () => { + it('should set the css classes of the host container based on the current doc and navigation view', () => { + const host = fixture.debugElement; + + locationService.go('guide/pipes'); + fixture.detectChanges(); + expect(host.properties['className']).toEqual('page-guide-pipes folder-guide view-SideNav'); + + locationService.go('features'); + fixture.detectChanges(); + expect(host.properties['className']).toEqual('page-features folder-features view-TopBar'); + + locationService.go(''); + fixture.detectChanges(); + expect(host.properties['className']).toEqual('page-home folder-home view-'); + }); + }); + describe('currentDocument', () => { it('should display a guide page (guide/pipes)', () => { @@ -274,22 +292,6 @@ describe('AppComponent', () => { expect(docViewer.innerText).toMatch(/Features/i); }); - const marketingClassName = 'marketing'; - - it('should not have marketing CSS class on host element for a guide page (guide/pipes)', () => { - locationService.go('guide/pipes'); - fixture.detectChanges(); - const classes: string[] = fixture.nativeElement.className; - expect(classes).not.toContain(marketingClassName); - }); - - it('should have marketing CSS class on host element for a marketing page', () => { - locationService.go('features'); - fixture.detectChanges(); - const classes: string[] = fixture.nativeElement.className; - expect(classes).toContain(marketingClassName); - }); - it('should update the document title', () => { const titleService = TestBed.get(Title); spyOn(titleService, 'setTitle'); diff --git a/aio/src/app/app.component.ts b/aio/src/app/app.component.ts index 1c70960e8d..9b73c367a6 100644 --- a/aio/src/app/app.component.ts +++ b/aio/src/app/app.component.ts @@ -22,13 +22,33 @@ export class AppComponent implements OnInit { currentNode: CurrentNode; currentPath: string; dtOn = false; + + /** + * An HTML friendly identifier for the currently displayed page. + * This is computed from the `currentDocument.id` by replacing `/` with `-` + */ pageId: string; + /** + * An HTML friendly identifer for the "folder" of the currently displayed page. + * This is computed by taking everything up to the first `/` in the `currentDocument.id` + */ + folderId: string; + /** + * These CSS classes are computed from the current state of the application + * (e.g. what document is being viewed) to allow for fine grain control over + * the styling of individual pages. + * You will get three classes: + * + * * `page-...`: computed from the current document id (e.g. news, guide-security, tutorial-toh-pt2) + * * `folder-...`: computed from the top level folder for an id (e.g. guide, tutorial, etc) + * * `view-...`: computef from the navigation view (e.g. SideNav, TopBar, etc) + */ + @HostBinding('class') + hostClasses = ''; + currentDocument: DocumentContents; footerNodes: NavigationNode[]; - @HostBinding('class.marketing') - isMarketing = false; - isStarting = true; isSideBySide = false; private isSideNavDoc = false; @@ -79,6 +99,8 @@ export class AppComponent implements OnInit { this.documentService.currentDocument.subscribe(doc => { this.currentDocument = doc; this.setPageId(doc.id); + this.setFolderId(doc.id); + this.updateHostClasses(); }); this.locationService.currentPath.subscribe(path => { @@ -93,12 +115,12 @@ export class AppComponent implements OnInit { this.navigationService.currentNode.subscribe(currentNode => { this.currentNode = currentNode; + this.updateHostClasses(); // Toggle the sidenav if side-by-side and the kind of view changed if (this.previousNavView === currentNode.view) { return; } this.previousNavView = currentNode.view; this.isSideNavDoc = currentNode.view === sideNavView; - this.isMarketing = !this.isSideNavDoc; this.sideNavToggle(this.isSideNavDoc && this.isSideBySide); }); @@ -174,4 +196,17 @@ export class AppComponent implements OnInit { // Special case the home page this.pageId = (id === 'index') ? 'home' : id.replace('/', '-'); } + + setFolderId(id: string) { + // Special case the home page + this.folderId = (id === 'index') ? 'home' : id.split('/', 1)[0]; + } + + updateHostClasses() { + const pageClass = `page-${this.pageId}`; + const folderClass = `folder-${this.folderId}`; + const viewClass = `view-${this.currentNode && this.currentNode.view}`; + + this.hostClasses = `${pageClass} ${folderClass} ${viewClass}`; + } }