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:
parent
0714139e37
commit
36161d99f6
|
@ -27,6 +27,7 @@
|
||||||
</md-sidenav>
|
</md-sidenav>
|
||||||
|
|
||||||
<section class="sidenav-content" [id]="pageId" role="content">
|
<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-doc-viewer [doc]="currentDocument" (docRendered)="onDocRendered()"></aio-doc-viewer>
|
||||||
<aio-dt [on]="dtOn" [(doc)]="currentDocument"></aio-dt>
|
<aio-dt [on]="dtOn" [(doc)]="currentDocument"></aio-dt>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { of } from 'rxjs/observable/of';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
|
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 { GaService } from 'app/shared/ga.service';
|
||||||
import { LocationService } from 'app/shared/location.service';
|
import { LocationService } from 'app/shared/location.service';
|
||||||
import { Logger } from 'app/shared/logger.service';
|
import { Logger } from 'app/shared/logger.service';
|
||||||
|
@ -332,10 +333,6 @@ describe('AppComponent', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hostClasses', () => {
|
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', () => {
|
it('should set the css classes of the host container based on the current doc and navigation view', () => {
|
||||||
locationService.go('guide/pipes');
|
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', () => {
|
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');
|
locationService.go('guide/pipes');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
@ -376,7 +373,14 @@ describe('AppComponent', () => {
|
||||||
checkHostClass('sidenav', 'open');
|
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) {
|
function checkHostClass(type, value) {
|
||||||
|
const host = fixture.debugElement;
|
||||||
const classes = host.properties['className'];
|
const classes = host.properties['className'];
|
||||||
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
|
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
|
||||||
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
|
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('search', () => {
|
||||||
describe('initialization', () => {
|
describe('initialization', () => {
|
||||||
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
|
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
|
||||||
|
@ -883,7 +905,7 @@ describe('AppComponent', () => {
|
||||||
|
|
||||||
//// test helpers ////
|
//// test helpers ////
|
||||||
|
|
||||||
function createTestingModule(initialUrl: string) {
|
function createTestingModule(initialUrl: string, mode: string = 'stable') {
|
||||||
TestBed.resetTestingModule();
|
TestBed.resetTestingModule();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [ AppModule ],
|
imports: [ AppModule ],
|
||||||
|
@ -894,6 +916,11 @@ function createTestingModule(initialUrl: string) {
|
||||||
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) },
|
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) },
|
||||||
{ provide: Logger, useClass: MockLogger },
|
{ provide: Logger, useClass: MockLogger },
|
||||||
{ provide: SearchService, useClass: MockSearchService },
|
{ provide: SearchService, useClass: MockSearchService },
|
||||||
|
{ provide: Deployment, useFactory: () => {
|
||||||
|
const deployment = new Deployment();
|
||||||
|
deployment.mode = mode;
|
||||||
|
return deployment;
|
||||||
|
}},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { MdSidenav } from '@angular/material';
|
||||||
import { CurrentNodes, NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
|
import { CurrentNodes, NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
|
||||||
import { DocumentService, DocumentContents } from 'app/documents/document.service';
|
import { DocumentService, DocumentContents } from 'app/documents/document.service';
|
||||||
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
|
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 { LocationService } from 'app/shared/location.service';
|
||||||
import { NavMenuComponent } from 'app/layout/nav-menu/nav-menu.component';
|
import { NavMenuComponent } from 'app/layout/nav-menu/nav-menu.component';
|
||||||
import { ScrollService } from 'app/shared/scroll.service';
|
import { ScrollService } from 'app/shared/scroll.service';
|
||||||
|
@ -99,6 +100,7 @@ export class AppComponent implements OnInit {
|
||||||
sidenav: MdSidenav;
|
sidenav: MdSidenav;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
public deployment: Deployment,
|
||||||
private documentService: DocumentService,
|
private documentService: DocumentService,
|
||||||
private hostElement: ElementRef,
|
private hostElement: ElementRef,
|
||||||
private locationService: LocationService,
|
private locationService: LocationService,
|
||||||
|
@ -256,12 +258,13 @@ export class AppComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHostClasses() {
|
updateHostClasses() {
|
||||||
|
const mode = `mode-${this.deployment.mode}`;
|
||||||
const sideNavOpen = `sidenav-${this.sidenav.opened ? 'open' : 'closed'}`;
|
const sideNavOpen = `sidenav-${this.sidenav.opened ? 'open' : 'closed'}`;
|
||||||
const pageClass = `page-${this.pageId}`;
|
const pageClass = `page-${this.pageId}`;
|
||||||
const folderClass = `folder-${this.folderId}`;
|
const folderClass = `folder-${this.folderId}`;
|
||||||
const viewClasses = Object.keys(this.currentNodes || {}).map(view => `view-${view}`).join(' ');
|
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
|
// Dynamically change height of table of contents container
|
||||||
|
|
|
@ -26,8 +26,10 @@ import { SwUpdatesModule } from 'app/sw-updates/sw-updates.module';
|
||||||
import { AppComponent } from 'app/app.component';
|
import { AppComponent } from 'app/app.component';
|
||||||
import { ApiService } from 'app/embedded/api/api.service';
|
import { ApiService } from 'app/embedded/api/api.service';
|
||||||
import { CustomMdIconRegistry, SVG_ICONS } from 'app/shared/custom-md-icon-registry';
|
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 { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
|
||||||
import { DtComponent } from 'app/layout/doc-viewer/dt.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 { EmbeddedModule } from 'app/embedded/embedded.module';
|
||||||
import { GaService } from 'app/shared/ga.service';
|
import { GaService } from 'app/shared/ga.service';
|
||||||
import { Logger } from 'app/shared/logger.service';
|
import { Logger } from 'app/shared/logger.service';
|
||||||
|
@ -90,14 +92,16 @@ export const svgIconProviders = [
|
||||||
DocViewerComponent,
|
DocViewerComponent,
|
||||||
DtComponent,
|
DtComponent,
|
||||||
FooterComponent,
|
FooterComponent,
|
||||||
TopMenuComponent,
|
ModeBannerComponent,
|
||||||
NavMenuComponent,
|
NavMenuComponent,
|
||||||
NavItemComponent,
|
NavItemComponent,
|
||||||
SearchResultsComponent,
|
SearchResultsComponent,
|
||||||
SearchBoxComponent,
|
SearchBoxComponent,
|
||||||
|
TopMenuComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ApiService,
|
ApiService,
|
||||||
|
Deployment,
|
||||||
DocumentService,
|
DocumentService,
|
||||||
GaService,
|
GaService,
|
||||||
Logger,
|
Logger,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class Deployment {
|
||||||
|
mode: string = environment.mode;
|
||||||
|
};
|
Loading…
Reference in New Issue