Skip to content

Commit

Permalink
feat(nav): new sidenav UX (angular#300)
Browse files Browse the repository at this point in the history
  • Loading branch information
amcdnl authored and jelbourn committed Oct 30, 2017
1 parent 37ac2f0 commit f1ddeae
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 109 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
51 changes: 32 additions & 19 deletions src/app/pages/component-sidenav/_component-sidenav-theme.scss
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/app/pages/component-sidenav/component-nav.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="docs-component-viewer-nav">
<div class="docs-component-viewer-nav-content">
<nav *ngFor="let category of docItems.getCategories((params | async)?.section); let last = last;">
<button (click)="toggleExpand(category.id)"
[attr.aria-label]="category.name + ', section toggle'"
[attr.aria-controls]="'panel-' + category.id"
[attr.aria-expanded]="getExpanded(category.id)">
{{category.name}}
<mat-icon *ngIf="!getExpanded(category.id)">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="getExpanded(category.id)">keyboard_arrow_up</mat-icon>
</button>
<ul [@bodyExpansion]="_getExpandedState(category.id)" id="panel-{{category.id}}">
<li *ngFor="let component of category.items">
<a [routerLink]="'/' + (params | async)?.section+ '/' + component.id"
routerLinkActive="docs-component-viewer-sidenav-item-selected">
{{component.name}}
</a>
</li>
</ul>
<hr *ngIf="!last" />
</nav>
</div>
</div>
30 changes: 15 additions & 15 deletions src/app/pages/component-sidenav/component-sidenav.html
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<mat-sidenav-container class="docs-component-viewer-sidenav-container">
<!-- If on small screen, menu resides in drawer -->
<mat-sidenav #sidenav class="docs-component-viewer-sidenav"
*ngIf="isScreenSmall()"
[opened]="!isScreenSmall()"
[mode]="isScreenSmall() ? 'over' : 'side'">
<nav *ngFor="let category of docItems.getCategories((params | async)?.section)">
<h3>{{category.name}}</h3>
<ul>
<li *ngFor="let component of category.items">
<a [routerLink]="'/' + (params | async)?.section+ '/' + component.id"
routerLinkActive="docs-component-viewer-sidenav-item-selected">
{{component.name}}
</a>
</li>
</ul>
</nav>
<app-component-nav [params]="params"></app-component-nav>
</mat-sidenav>

<div class="docs-component-sidenav-content">
<component-page-header (toggleSidenav)="sidenav.toggle()"></component-page-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
<div class="docs-component-sidenav-inner-content">
<div class="docs-component-sidenav-body-content">
<!-- If on large screen, menu resides to left of content -->
<app-component-nav
*ngIf="!isScreenSmall()"
[params]="params">
</app-component-nav>
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
</div>
</div>
</mat-sidenav-container>
</mat-sidenav-container>
177 changes: 119 additions & 58 deletions src/app/pages/component-sidenav/component-sidenav.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Loading

0 comments on commit f1ddeae

Please sign in to comment.