feat(aio): add helper CSS classes to the `aio-shell` for fine grained styling

Alternative to #16564
Closes #16549
This commit is contained in:
Peter Bacon Darwin 2017-05-05 10:02:33 +01:00 committed by Matias Niemelä
parent 9da63408b0
commit 309ada5df5
2 changed files with 57 additions and 20 deletions

View File

@ -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', () => { describe('currentDocument', () => {
it('should display a guide page (guide/pipes)', () => { it('should display a guide page (guide/pipes)', () => {
@ -274,22 +292,6 @@ describe('AppComponent', () => {
expect(docViewer.innerText).toMatch(/Features/i); 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', () => { it('should update the document title', () => {
const titleService = TestBed.get(Title); const titleService = TestBed.get(Title);
spyOn(titleService, 'setTitle'); spyOn(titleService, 'setTitle');

View File

@ -22,13 +22,33 @@ export class AppComponent implements OnInit {
currentNode: CurrentNode; currentNode: CurrentNode;
currentPath: string; currentPath: string;
dtOn = false; dtOn = false;
/**
* An HTML friendly identifier for the currently displayed page.
* This is computed from the `currentDocument.id` by replacing `/` with `-`
*/
pageId: string; 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; currentDocument: DocumentContents;
footerNodes: NavigationNode[]; footerNodes: NavigationNode[];
@HostBinding('class.marketing')
isMarketing = false;
isStarting = true; isStarting = true;
isSideBySide = false; isSideBySide = false;
private isSideNavDoc = false; private isSideNavDoc = false;
@ -79,6 +99,8 @@ export class AppComponent implements OnInit {
this.documentService.currentDocument.subscribe(doc => { this.documentService.currentDocument.subscribe(doc => {
this.currentDocument = doc; this.currentDocument = doc;
this.setPageId(doc.id); this.setPageId(doc.id);
this.setFolderId(doc.id);
this.updateHostClasses();
}); });
this.locationService.currentPath.subscribe(path => { this.locationService.currentPath.subscribe(path => {
@ -93,12 +115,12 @@ export class AppComponent implements OnInit {
this.navigationService.currentNode.subscribe(currentNode => { this.navigationService.currentNode.subscribe(currentNode => {
this.currentNode = currentNode; this.currentNode = currentNode;
this.updateHostClasses();
// Toggle the sidenav if side-by-side and the kind of view changed // Toggle the sidenav if side-by-side and the kind of view changed
if (this.previousNavView === currentNode.view) { return; } if (this.previousNavView === currentNode.view) { return; }
this.previousNavView = currentNode.view; this.previousNavView = currentNode.view;
this.isSideNavDoc = currentNode.view === sideNavView; this.isSideNavDoc = currentNode.view === sideNavView;
this.isMarketing = !this.isSideNavDoc;
this.sideNavToggle(this.isSideNavDoc && this.isSideBySide); this.sideNavToggle(this.isSideNavDoc && this.isSideBySide);
}); });
@ -174,4 +196,17 @@ export class AppComponent implements OnInit {
// Special case the home page // Special case the home page
this.pageId = (id === 'index') ? 'home' : id.replace('/', '-'); 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}`;
}
} }