Skip to content
This repository was archived by the owner on Dec 18, 2024. It is now read-only.

feat(nav): new sidenav #300

Merged
merged 8 commits into from
Oct 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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