diff --git a/package.json b/package.json index 4c1781cbc407..358669fdba23 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "angular-cli": {}, "scripts": { "start": "npm run build-themes && ng serve --aot --sourcemaps=false", + "start-jit": "npm run build-themes && ng serve --sourcemaps=false", "lint": "tslint \"src/**/*.ts\"", "test": "ng test", "pree2e": "webdriver-manager update", diff --git a/src/app/pages/component-sidenav/_component-sidenav-theme.scss b/src/app/pages/component-sidenav/_component-sidenav-theme.scss index fe4e01adba97..8007d70a2337 100644 --- a/src/app/pages/component-sidenav/_component-sidenav-theme.scss +++ b/src/app/pages/component-sidenav/_component-sidenav-theme.scss @@ -1,36 +1,49 @@ @import '../../../../node_modules/@angular/material/theming'; +@import '../../../styles/constants'; @mixin component-viewer-sidenav-theme($theme) { $primary: map-get($theme, primary); - $accent: map-get($theme, accent); - $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); - $sidenav: '.docs-component-viewer-sidenav'; + $is-dark-theme: map-get($theme, is-dark); + $nav-background-opacity: if($is-dark-theme, 0.2, 0.03); + .docs-component-viewer-nav-content { + background: rgba(0, 0, 0, $nav-background-opacity); - .docs-component-viewer-sidenav { + &::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, .26); + } - // Section divider - h3 { - background: rgba(mat-color($foreground, secondary-text), .32); - color: mat-color($primary, default-contrast); + button { + color: rgba(mat-color($foreground, text), .5); } - // Sidenav navigation items - li { - border-color: rgba(mat-color($foreground, secondary-text), .06); - color: mat-color($foreground, secondary-text); + hr { + border: none; + border-top: solid 1px rgba(mat-color($foreground, secondary-text), .1) + } - > a { + a { color: mat-color($foreground, secondary-text); - &.is-selected, - &:hover, - &:focus { - background: mat-color($background, background); - color: mat-color($primary); - } + &.docs-component-viewer-sidenav-item-selected, + &:hover { + color: mat-color($primary); + } + } + } + + @media (max-width: $small-breakpoint-width) { + .docs-component-viewer-sidenav { + .docs-component-viewer-nav-content { + background: none; + } + } + + .mat-drawer { + &::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, .26); } } } diff --git a/src/app/pages/component-sidenav/component-nav.html b/src/app/pages/component-sidenav/component-nav.html new file mode 100644 index 000000000000..5db30f6bdc66 --- /dev/null +++ b/src/app/pages/component-sidenav/component-nav.html @@ -0,0 +1,23 @@ +
+
+ +
+
\ No newline at end of file diff --git a/src/app/pages/component-sidenav/component-sidenav.html b/src/app/pages/component-sidenav/component-sidenav.html index 5aacd122f275..630ad5592aac 100644 --- a/src/app/pages/component-sidenav/component-sidenav.html +++ b/src/app/pages/component-sidenav/component-sidenav.html @@ -1,23 +1,23 @@ + - + -
- - +
+
+ + + + +
+ +
-
+ \ No newline at end of file diff --git a/src/app/pages/component-sidenav/component-sidenav.scss b/src/app/pages/component-sidenav/component-sidenav.scss index ee2e517cbcd5..3e10381e294a 100644 --- a/src/app/pages/component-sidenav/component-sidenav.scss +++ b/src/app/pages/component-sidenav/component-sidenav.scss @@ -1,88 +1,149 @@ -$sidenav-spacing-unit: 8px; -$sidenav-width: 240px; +@import '../../../styles/constants'; -app-component-sidenav { - display: flex; -} +$sidenav-width: 240px; .docs-component-viewer-sidenav-container { - width: 100%; - - .mat-drawer-content { - position: absolute; - right: 0; - left: 0; - } + box-sizing: border-box; } .docs-component-viewer-sidenav { - box-shadow: 3px 0 6px rgba(0, 0, 0, .24); - padding-bottom: 72px; - width: $sidenav-width; - bottom: 0; overflow: auto; - height: 100%; +} - &.mat-sidenav-opened { - box-shadow: 3px 0 6px rgba(0, 0, 0, .24); - } +.docs-component-sidenav-inner-content { + display: flex; + flex-direction: row; - // Section divider - h3 { - border: none; - font-size: 10px; - letter-spacing: 1px; - line-height: $sidenav-spacing-unit * 3; - text-transform: uppercase; - font-weight: 400; - margin: 0; - padding: 0 ($sidenav-spacing-unit * 2); + // The rule will match the element following the router-outlet which will be the routed component. + router-outlet + * { + flex-grow: 1; } +} - ul { - list-style-type: none; - margin: 0; - padding: 0; +.mat-drawer { + &::-webkit-scrollbar { + height: 4px; + width: 4px; } +} - // Sidenav navigation item - li { - border-bottom-width: 1px; - border-bottom-style: solid; - margin: 0; - padding: 0; +.docs-component-viewer-nav { + position: sticky; + top: 25px; + .docs-component-viewer-nav-content { + margin: 25px; + width: $sidenav-width; + max-height: 75vh; + overflow: auto; - // Hide the border on the last item - &:last-child { - border-color: transparent; + &::-webkit-scrollbar { + height: 4px; + width: 4px; } - > a { - box-sizing: border-box; - display: block; - font-size: 14px; - font-weight: 400; - line-height: ($sidenav-spacing-unit * 6) - 1; - text-decoration: none; - transition: all .3s; - padding: 0 ($sidenav-spacing-unit * 2); + button { + padding: 10px 15px; + font-weight: 700; + line-height: 16px; + margin: 0; + font-size: 13px; + cursor: pointer; position: relative; + display: block; + width: 100%; + text-align: left; + background: none; + border: none; - &.docs-component-viewer-sidenav-item-selected { - font-weight: 600; + &:focus { + outline: none; } + + .mat-icon { + position: absolute; + right: 5px; + font-size: 18px; + } + } + + hr { + padding: 0; + margin: 0; + } + + ul { + list-style-type: none; + margin: -5px 0 5px 0; + padding: 0; + overflow: hidden; + } + + li { + font-size: 13px; + line-height: 16px; + margin: 0; + padding: 5px 15px 5px 20px; + } + + a { + display: block; + text-decoration: none; } } } .docs-component-sidenav-content { - min-height: 100%; display: flex; flex-direction: column; +} - // The rule will match the element following the router-outlet which will be the routed component. - router-outlet + * { - flex-grow: 1; +// Add specific rule to prevent default rule conflict +.docs-component-viewer-sidenav-container.mat-drawer-container{ + display: block; + overflow: hidden; + position: absolute; + // Offset the top by the toolbar height + top: 50px; + bottom: 0; + left: 0; + right: 0; +} + +.docs-component-sidenav-inner-content { + display: flex; + flex-direction: column; +} + +.docs-component-sidenav-body-content { + display: flex; + // footer should always reside at the bottom of the screen. + // if container not 100vh, push min height to that minus + // the offset of the top bar and the footer height + min-height: calc(100vh - 264px); +} + +@media (max-width: $small-breakpoint-width) { + // Add specific rule to prevent default rule conflict + .docs-component-viewer-sidenav-container .docs-component-viewer-sidenav { + // offset the top by the header + tabs on a small screen + top: 42px; + } + + .mat-sidenav-content { + // offset the top by the header + tabs on a small screen + margin-top: 42px; + } + + .docs-component-viewer-nav { + position: relative; + top: 0; + + .docs-component-viewer-nav-content { + box-sizing: border-box; + margin: 0; + max-height: initial; + box-sizing: border-box; + } } } diff --git a/src/app/pages/component-sidenav/component-sidenav.ts b/src/app/pages/component-sidenav/component-sidenav.ts index a2fa5478f8bf..ff7ebb6183d5 100644 --- a/src/app/pages/component-sidenav/component-sidenav.ts +++ b/src/app/pages/component-sidenav/component-sidenav.ts @@ -1,12 +1,18 @@ -import {Component, NgZone, ViewEncapsulation, ViewChild, OnInit, NgModule} from '@angular/core'; +import { + Component, Input, NgZone, ViewEncapsulation, ViewChild, OnInit, NgModule, trigger, state, + animate, transition, style, OnDestroy +} from '@angular/core'; import {DocumentationItems} from '../../shared/documentation-items/documentation-items'; -import {MatSidenav, MatSidenavModule} from '@angular/material'; +import {MatSidenav, MatSidenavModule, MatIconModule} from '@angular/material'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {ActivatedRoute, Params, Router, RouterModule} from '@angular/router'; import {CommonModule} from '@angular/common'; import {ComponentHeaderModule} from '../component-page-header/component-page-header'; import {FooterModule} from '../../shared/footer/footer'; import {Observable} from 'rxjs/Observable'; +import {Subject} from 'rxjs/Subject'; +import 'rxjs/add/operator/switchMap'; +import 'rxjs/add/operator/takeUntil'; const SMALL_WIDTH_BREAKPOINT = 840; @@ -37,10 +43,11 @@ export class ComponentSidenav implements OnInit { this.sidenav.close(); } }); + // Combine params from all of the path into a single object. this.params = Observable.combineLatest( - this._route.pathFromRoot.map(route => route.params), - Object.assign); + this._route.pathFromRoot.map(route => route.params), + Object.assign); } isScreenSmall(): boolean { @@ -48,6 +55,75 @@ export class ComponentSidenav implements OnInit { } } +@Component({ + selector: 'app-component-nav', + templateUrl: './component-nav.html', + animations: [ + trigger('bodyExpansion', [ + state('collapsed', style({height: '0px', visibility: 'hidden'})), + state('expanded', style({height: '*', visibility: 'visible'})), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4,0.0,0.2,1)')), + ]), + ], +}) +export class ComponentNav implements OnInit, OnDestroy { + + @Input() params: Observable; + expansions = {}; + private _onDestroy = new Subject(); + + constructor(public docItems: DocumentationItems, + private _router: Router) { } + + ngOnInit() { + this._router.events + .startWith(null) + .switchMap(() => this.params) + .takeUntil(this._onDestroy) + .subscribe(p => this.setExpansions(p)); + } + + ngOnDestroy() { + this._onDestroy.next(); + this._onDestroy.complete(); + } + + /** Set the expansions based on the route url */ + setExpansions(params: Params) { + const categories = this.docItems.getCategories(params.section); + for (const category of categories) { + if (this.expansions[category.id] === true) { + continue; + } + + let match = false; + for (const item of category.items) { + if (this._router.url.indexOf(item.id) > -1) { + match = true; + break; + } + } + this.expansions[category.id] = match; + } + } + + /** Gets the expanded state */ + _getExpandedState(category: string) { + return this.getExpanded(category) ? 'expanded' : 'collapsed'; + } + + /** Toggles the expanded state */ + toggleExpand(category: string) { + this.expansions[category] = !this.expansions[category]; + } + + /** Gets whether expanded or not */ + getExpanded(category: string): boolean { + return this.expansions[category]; + } + +} + @NgModule({ imports: [ @@ -56,10 +132,11 @@ export class ComponentSidenav implements OnInit { CommonModule, ComponentHeaderModule, FooterModule, - BrowserAnimationsModule + BrowserAnimationsModule, + MatIconModule, ], exports: [ComponentSidenav], - declarations: [ComponentSidenav], + declarations: [ComponentSidenav, ComponentNav], providers: [DocumentationItems], }) export class ComponentSidenavModule {} diff --git a/src/app/pages/component-viewer/component-viewer.scss b/src/app/pages/component-viewer/component-viewer.scss index 86897adc225b..301fa3289477 100644 --- a/src/app/pages/component-viewer/component-viewer.scss +++ b/src/app/pages/component-viewer/component-viewer.scss @@ -2,7 +2,9 @@ app-component-viewer { font-weight: 400; - padding: 20px $content-padding-side 50px; + + // spacing for the component viewer + padding: 20px 50px 50px 20px; @media ($mat-xsmall) { padding-left: $content-padding-side-xs; @@ -10,17 +12,12 @@ app-component-viewer { } } -.docs-component-viewer { - margin: 0 auto; - max-width: 940px; -} - .docs-component-viewer-section-tab { text-transform: uppercase; } .docs-component-viewer-tabbed-content { - margin-bottom: 50px; + margin-bottom: 25px; } .docs-component-viewer-content { @@ -44,7 +41,6 @@ app-component-viewer { .docs-component-overview { width: 80%; - margin-right: 20px; @media (max-width: $small-breakpoint-width) { width: 100%; diff --git a/src/app/shared/table-of-contents/_table-of-contents-theme.scss b/src/app/shared/table-of-contents/_table-of-contents-theme.scss index 454c12ca7b7e..efedf7f81b62 100644 --- a/src/app/shared/table-of-contents/_table-of-contents-theme.scss +++ b/src/app/shared/table-of-contents/_table-of-contents-theme.scss @@ -10,6 +10,7 @@ .docs-link { color: mat-color($foreground, secondary-text); + transition: color 100ms; &:hover, &.docs-active { diff --git a/src/app/shared/table-of-contents/table-of-contents.scss b/src/app/shared/table-of-contents/table-of-contents.scss index 58c745b6be71..03cd881e59bc 100644 --- a/src/app/shared/table-of-contents/table-of-contents.scss +++ b/src/app/shared/table-of-contents/table-of-contents.scss @@ -1,12 +1,15 @@ :host { font-size: 13px; - width: 15%; + // Width is container width minus content width + width: 19%; position: sticky; top: 0; + padding-left: 25px; + box-sizing: border-box; } .docs-toc-container { - padding: 5px 0 10px 12px; + padding: 5px 0 10px 10px; } .docs-toc-heading { diff --git a/src/index.html b/src/index.html index 906843f28c75..082c4d2eee0e 100644 --- a/src/index.html +++ b/src/index.html @@ -16,7 +16,7 @@ sizes="192x192"> - +