feat(aio): update UI based on deployment mode

* Add a banner if the mode is "archive"
* Add a `mode-...` class to the `aio-shell` element to enable
mode based theming.

See #18287
This commit is contained in:
Peter Bacon Darwin 2017-07-26 18:36:00 +01:00 committed by Victor Berchet
parent 0714139e37
commit 36161d99f6
6 changed files with 66 additions and 8 deletions

View File

@ -27,6 +27,7 @@
</md-sidenav>
<section class="sidenav-content" [id]="pageId" role="content">
<aio-mode-banner [mode]="deployment.mode" [version]="versionInfo"></aio-mode-banner>
<aio-doc-viewer [doc]="currentDocument" (docRendered)="onDocRendered()"></aio-doc-viewer>
<aio-dt [on]="dtOn" [(doc)]="currentDocument"></aio-dt>
</section>

View File

@ -12,6 +12,7 @@ import { of } from 'rxjs/observable/of';
import { AppComponent } from './app.component';
import { AppModule } from './app.module';
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
import { Deployment } from 'app/shared/deployment.service';
import { GaService } from 'app/shared/ga.service';
import { LocationService } from 'app/shared/location.service';
import { Logger } from 'app/shared/logger.service';
@ -332,10 +333,6 @@ describe('AppComponent', () => {
});
describe('hostClasses', () => {
let host: DebugElement;
beforeEach(() => {
host = fixture.debugElement;
});
it('should set the css classes of the host container based on the current doc and navigation view', () => {
locationService.go('guide/pipes');
@ -359,7 +356,7 @@ describe('AppComponent', () => {
});
it('should set the css class of the host container based on the open/closed state of the side nav', () => {
const sideNav = host.query(By.directive(MdSidenav));
const sideNav = fixture.debugElement.query(By.directive(MdSidenav));
locationService.go('guide/pipes');
fixture.detectChanges();
@ -376,7 +373,14 @@ describe('AppComponent', () => {
checkHostClass('sidenav', 'open');
});
it('should set the css class of the host container based on the initial deployment mode', () => {
createTestingModule('a/b', 'archive');
initializeTest();
checkHostClass('mode', 'archive');
});
function checkHostClass(type, value) {
const host = fixture.debugElement;
const classes = host.properties['className'];
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
@ -627,6 +631,24 @@ describe('AppComponent', () => {
});
});
describe('deployment banner', () => {
it('should show a message if the deployment mode is "archive"', () => {
createTestingModule('a/b', 'archive');
initializeTest();
fixture.detectChanges();
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
expect(banner.textContent).toContain('archived documentation for Angular v4');
});
it('should show no message if the deployment mode is not "archive"', () => {
createTestingModule('a/b', 'stable');
initializeTest();
fixture.detectChanges();
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
expect(banner.textContent.trim()).toEqual('');
});
});
describe('search', () => {
describe('initialization', () => {
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
@ -883,7 +905,7 @@ describe('AppComponent', () => {
//// test helpers ////
function createTestingModule(initialUrl: string) {
function createTestingModule(initialUrl: string, mode: string = 'stable') {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [ AppModule ],
@ -894,6 +916,11 @@ function createTestingModule(initialUrl: string) {
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) },
{ provide: Logger, useClass: MockLogger },
{ provide: SearchService, useClass: MockSearchService },
{ provide: Deployment, useFactory: () => {
const deployment = new Deployment();
deployment.mode = mode;
return deployment;
}},
]
});
}

View File

@ -5,6 +5,7 @@ import { MdSidenav } from '@angular/material';
import { CurrentNodes, NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
import { DocumentService, DocumentContents } from 'app/documents/document.service';
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
import { Deployment } from 'app/shared/deployment.service';
import { LocationService } from 'app/shared/location.service';
import { NavMenuComponent } from 'app/layout/nav-menu/nav-menu.component';
import { ScrollService } from 'app/shared/scroll.service';
@ -99,6 +100,7 @@ export class AppComponent implements OnInit {
sidenav: MdSidenav;
constructor(
public deployment: Deployment,
private documentService: DocumentService,
private hostElement: ElementRef,
private locationService: LocationService,
@ -256,12 +258,13 @@ export class AppComponent implements OnInit {
}
updateHostClasses() {
const mode = `mode-${this.deployment.mode}`;
const sideNavOpen = `sidenav-${this.sidenav.opened ? 'open' : 'closed'}`;
const pageClass = `page-${this.pageId}`;
const folderClass = `folder-${this.folderId}`;
const viewClasses = Object.keys(this.currentNodes || {}).map(view => `view-${view}`).join(' ');
this.hostClasses = `${sideNavOpen} ${pageClass} ${folderClass} ${viewClasses}`;
this.hostClasses = `${mode} ${sideNavOpen} ${pageClass} ${folderClass} ${viewClasses}`;
}
// Dynamically change height of table of contents container

View File

@ -26,8 +26,10 @@ import { SwUpdatesModule } from 'app/sw-updates/sw-updates.module';
import { AppComponent } from 'app/app.component';
import { ApiService } from 'app/embedded/api/api.service';
import { CustomMdIconRegistry, SVG_ICONS } from 'app/shared/custom-md-icon-registry';
import { Deployment } from 'app/shared/deployment.service';
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
import { DtComponent } from 'app/layout/doc-viewer/dt.component';
import { ModeBannerComponent } from 'app/layout/mode-banner/mode-banner.component';
import { EmbeddedModule } from 'app/embedded/embedded.module';
import { GaService } from 'app/shared/ga.service';
import { Logger } from 'app/shared/logger.service';
@ -90,14 +92,16 @@ export const svgIconProviders = [
DocViewerComponent,
DtComponent,
FooterComponent,
TopMenuComponent,
ModeBannerComponent,
NavMenuComponent,
NavItemComponent,
SearchResultsComponent,
SearchBoxComponent,
TopMenuComponent,
],
providers: [
ApiService,
Deployment,
DocumentService,
GaService,
Logger,

View File

@ -0,0 +1,16 @@
import { Component, Input } from '@angular/core';
import { VersionInfo } from 'app/navigation/navigation.service';
@Component({
selector: 'aio-mode-banner',
template: `
<div *ngIf="mode == 'archive'" class="mode-banner">
This is the <strong>archived documentation for Angular v{{version?.major}}.</strong>
Please visit <a href="https://angular.io/">angular.io</a> to see documentation for the current version of Angular.
</div>
`
})
export class ModeBannerComponent {
@Input() mode: string;
@Input() version: VersionInfo;
}

View File

@ -0,0 +1,7 @@
import { Injectable } from '@angular/core';
import { environment } from 'environments/environment';
@Injectable()
export class Deployment {
mode: string = environment.mode;
};