A starter app with sidenav, icons, tabs, floating action button, and a list of items.
Forked from Angular Material Basic App.
A Pen by Kyle Ledbetter on CodePen.
A starter app with sidenav, icons, tabs, floating action button, and a list of items.
Forked from Angular Material Basic App.
A Pen by Kyle Ledbetter on CodePen.
<html lang="en" ng-app="StarterApp"> | |
<head> | |
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/angular_material/0.8.3/angular-material.min.css"> | |
</head> | |
<body layout="row" ng-controller="AppCtrl"> | |
<md-sidenav layout="column" class="md-sidenav-left md-whiteframe-z2" md-component-id="left" md-is-locked-open="$mdMedia('gt-md')"> | |
<md-toolbar class="md-tall md-hue-2"> | |
<span flex></span> | |
<div layout="column" class="md-toolbar-tools-bottom inset"> | |
<user-avatar></user-avatar> | |
<span></span> | |
<div>Firstname Lastname</div> | |
<div>[email protected]</div> | |
</div> | |
</md-toolbar> | |
<md-list> | |
<md-item ng-repeat="item in menu"> | |
<a> | |
<md-item-content md-ink-ripple layout="row" layout-align="start center"> | |
<div class="inset"> | |
<ng-md-icon icon="{{item.icon}}"></ng-md-icon> | |
</div> | |
<div class="inset">{{item.title}} | |
</div> | |
</md-item-content> | |
</a> | |
</md-item> | |
<md-divider></md-divider> | |
<md-subheader>Management</md-subheader> | |
<md-item ng-repeat="item in admin"> | |
<a> | |
<md-item-content md-ink-ripple layout="row" layout-align="start center"> | |
<div class="inset"> | |
<ng-md-icon icon="{{item.icon}}"></ng-md-icon> | |
</div> | |
<div class="inset">{{item.title}} | |
</div> | |
</md-item-content> | |
</a> | |
</md-item> | |
</md-list> | |
</md-sidenav> | |
<div layout="column" class="relative" layout-fill role="main"> | |
<md-button class="md-fab md-fab-bottom-right" aria-label="Add" ng-click="showAdd($event)"> | |
<ng-md-icon icon="add"></ng-md-icon> | |
</md-button> | |
<md-toolbar ng-show="!showSearch"> | |
<div class="md-toolbar-tools"> | |
<md-button ng-click="toggleSidenav('left')" hide-gt-md aria-label="Menu"> | |
<ng-md-icon icon="menu"></ng-md-icon> | |
</md-button> | |
<h3> | |
Dashboard | |
</h3> | |
<span flex></span> | |
<md-button aria-label="Search" ng-click="showSearch = !showSearch"> | |
<ng-md-icon icon="search"></ng-md-icon> | |
</md-button> | |
<md-button aria-label="Open Settings" ng-click="showListBottomSheet($event)"> | |
<ng-md-icon icon="more_vert"></ng-md-icon> | |
</md-button> | |
</div> | |
<md-tabs md-stretch-tabs class="md-primary" md-selected="data.selectedIndex"> | |
<md-tab id="tab1" aria-controls="tab1-content"> | |
Latest | |
</md-tab> | |
<md-tab id="tab2" aria-controls="tab2-content"> | |
Favorites | |
</md-tab> | |
</md-tabs> | |
</md-toolbar> | |
<md-toolbar class="md-hue-1" ng-show="showSearch"> | |
<div class="md-toolbar-tools"> | |
<md-button ng-click="showSearch = !showSearch" aria-label="Back"> | |
<ng-md-icon icon="arrow_back"></ng-md-icon> | |
</md-button> | |
<h3 flex="10"> | |
Back | |
</h3> | |
<md-input-container md-theme="input" flex> | |
<label> </label> | |
<input ng-model="search.who" placeholder="enter search"> | |
</md-input-container> | |
<md-button aria-label="Search" ng-click="showSearch = !showSearch"> | |
<ng-md-icon icon="search"></ng-md-icon> | |
</md-button> | |
<md-button aria-label="Open Settings" ng-click="showListBottomSheet($event)"> | |
<ng-md-icon icon="more_vert"></ng-md-icon> | |
</md-button> | |
</div> | |
</md-toolbar> | |
<md-content flex md-scroll-y> | |
<ui-view layout="column" layout-fill layout-padding> | |
<div class="inset" hide-sm></div> | |
<ng-switch on="data.selectedIndex" class="tabpanel-container"> | |
<div role="tabpanel" | |
id="tab1-content" | |
aria-labelledby="tab1" | |
ng-switch-when="0" | |
md-swipe-left="next()" | |
md-swipe-right="previous()" | |
layout="row" layout-align="center center"> | |
<md-card flex-gt-sm="90" flex-gt-md="80"> | |
<md-card-content> | |
<h2>Activity</h2> | |
<md-list> | |
<md-item ng-repeat="item in activity | filter:search"> | |
<md-item-content> | |
<div class="md-tile-left inset" hide-sm> | |
<user-avatar></user-avatar> | |
</div> | |
<div class="md-tile-content"> | |
<h3>{{item.what}}</h3> | |
<h4>{{item.who}}</h4> | |
<p> | |
{{item.notes}} | |
</p> | |
</div> | |
</md-item-content> | |
<md-divider md-inset hide-sm ng-if="!$last"></md-divider> | |
<md-divider hide-gt-sm ng-if="!$last"></md-divider> | |
</md-item> | |
<md-divider></md-divider> | |
<md-item layout class="inset"> | |
<md-button layout layout-align="start center" flex class="md-primary"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></svg> More | |
</md-button> | |
</md-item> | |
</md-list> | |
</md-card-content> | |
</md-card> | |
</div> | |
<div role="tabpanel" | |
id="tab2-content" | |
aria-labelledby="tab2" | |
ng-switch-when="1" | |
md-swipe-left="next()" | |
md-swipe-right="previous()" | |
layout="row" layout-align="center center"> | |
<md-card flex-gt-sm="90" flex-gt-md="80"> | |
<md-card-content> | |
<h2>Favorites</h2> | |
<md-list> | |
<md-item ng-repeat="item in activity | filter:search | orderBy:'-what'"> | |
<md-item-content> | |
<div class="md-tile-left inset" hide-sm> | |
<user-avatar></user-avatar> | |
</div> | |
<div class="md-tile-content"> | |
<h3>{{item.what}}</h3> | |
<h4>{{item.who}}</h4> | |
<p> | |
{{item.notes}} | |
</p> | |
</div> | |
</md-item-content> | |
<md-divider md-inset hide-sm ng-if="!$last"></md-divider> | |
<md-divider hide-gt-sm ng-if="!$last"></md-divider> | |
</md-item> | |
<md-divider></md-divider> | |
<md-item layout class="inset"> | |
<md-button layout layout-align="start center" flex class="md-primary"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></svg> More | |
</md-button> | |
</md-item> | |
</md-list> | |
</md-card-content> | |
</md-card> | |
</div> | |
</ng-switch> | |
</ui-view> | |
</md-content> | |
</div> | |
<!-- Angular Material Dependencies --> | |
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script> | |
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.min.js"></script> | |
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-aria.min.js"></script> | |
<script src="//ajax.googleapis.com/ajax/libs/angular_material/0.8.3/angular-material.min.js"></script> | |
<script src="//cdn.jsdelivr.net/angular-material-icons/0.4.0/angular-material-icons.min.js"></script> | |
</body> | |
</html> |
var app = angular.module('StarterApp', ['ngMaterial', 'ngMdIcons']); | |
app.controller('AppCtrl', ['$scope', '$mdBottomSheet','$mdSidenav', '$mdDialog', function($scope, $mdBottomSheet, $mdSidenav, $mdDialog){ | |
$scope.toggleSidenav = function(menuId) { | |
$mdSidenav(menuId).toggle(); | |
}; | |
$scope.menu = [ | |
{ | |
link : '', | |
title: 'Dashboard', | |
icon: 'dashboard' | |
}, | |
{ | |
link : '', | |
title: 'Friends', | |
icon: 'group' | |
}, | |
{ | |
link : '', | |
title: 'Messages', | |
icon: 'message' | |
} | |
]; | |
$scope.admin = [ | |
{ | |
link : '', | |
title: 'Trash', | |
icon: 'delete' | |
}, | |
{ | |
link : 'showListBottomSheet($event)', | |
title: 'Settings', | |
icon: 'settings' | |
} | |
]; | |
$scope.activity = [ | |
{ | |
what: 'Brunch this weekend?', | |
who: 'Ali Conners', | |
when: '3:08PM', | |
notes: " I'll be in your neighborhood doing errands" | |
}, | |
{ | |
what: 'Summer BBQ', | |
who: 'to Alex, Scott, Jennifer', | |
when: '3:08PM', | |
notes: "Wish I could come out but I'm out of town this weekend" | |
}, | |
{ | |
what: 'Oui Oui', | |
who: 'Sandra Adams', | |
when: '3:08PM', | |
notes: "Do you have Paris recommendations? Have you ever been?" | |
}, | |
{ | |
what: 'Birthday Gift', | |
who: 'Trevor Hansen', | |
when: '3:08PM', | |
notes: "Have any ideas of what we should get Heidi for her birthday?" | |
}, | |
{ | |
what: 'Recipe to try', | |
who: 'Brian Holt', | |
when: '3:08PM', | |
notes: "We should eat this: Grapefruit, Squash, Corn, and Tomatillo tacos" | |
}, | |
]; | |
$scope.alert = ''; | |
$scope.showListBottomSheet = function($event) { | |
$scope.alert = ''; | |
$mdBottomSheet.show({ | |
template: '<md-bottom-sheet class="md-list md-has-header"> <md-subheader>Settings</md-subheader> <md-list> <md-item ng-repeat="item in items"><md-item-content md-ink-ripple flex class="inset"> <a flex aria-label="{{item.name}}" ng-click="listItemClick($index)"> <span class="md-inline-list-icon-label">{{ item.name }}</span> </a></md-item-content> </md-item> </md-list></md-bottom-sheet>', | |
controller: 'ListBottomSheetCtrl', | |
targetEvent: $event | |
}).then(function(clickedItem) { | |
$scope.alert = clickedItem.name + ' clicked!'; | |
}); | |
}; | |
$scope.showAdd = function(ev) { | |
$mdDialog.show({ | |
controller: DialogController, | |
template: '<md-dialog aria-label="Mango (Fruit)"> <md-content class="md-padding"> <form name="userForm"> <div layout layout-sm="column"> <md-input-container flex> <label>First Name</label> <input ng-model="user.firstName" placeholder="Placeholder text"> </md-input-container> <md-input-container flex> <label>Last Name</label> <input ng-model="theMax"> </md-input-container> </div> <md-input-container flex> <label>Address</label> <input ng-model="user.address"> </md-input-container> <div layout layout-sm="column"> <md-input-container flex> <label>City</label> <input ng-model="user.city"> </md-input-container> <md-input-container flex> <label>State</label> <input ng-model="user.state"> </md-input-container> <md-input-container flex> <label>Postal Code</label> <input ng-model="user.postalCode"> </md-input-container> </div> <md-input-container flex> <label>Biography</label> <textarea ng-model="user.biography" columns="1" md-maxlength="150"></textarea> </md-input-container> </form> </md-content> <div class="md-actions" layout="row"> <span flex></span> <md-button ng-click="answer(\'not useful\')"> Cancel </md-button> <md-button ng-click="answer(\'useful\')" class="md-primary"> Save </md-button> </div></md-dialog>', | |
targetEvent: ev, | |
}) | |
.then(function(answer) { | |
$scope.alert = 'You said the information was "' + answer + '".'; | |
}, function() { | |
$scope.alert = 'You cancelled the dialog.'; | |
}); | |
}; | |
}]); | |
app.controller('ListBottomSheetCtrl', function($scope, $mdBottomSheet) { | |
$scope.items = [ | |
{ name: 'Share', icon: 'share' }, | |
{ name: 'Upload', icon: 'upload' }, | |
{ name: 'Copy', icon: 'copy' }, | |
{ name: 'Print this page', icon: 'print' }, | |
]; | |
$scope.listItemClick = function($index) { | |
var clickedItem = $scope.items[$index]; | |
$mdBottomSheet.hide(clickedItem); | |
}; | |
}); | |
function DialogController($scope, $mdDialog) { | |
$scope.hide = function() { | |
$mdDialog.hide(); | |
}; | |
$scope.cancel = function() { | |
$mdDialog.cancel(); | |
}; | |
$scope.answer = function(answer) { | |
$mdDialog.hide(answer); | |
}; | |
}; | |
app.directive('userAvatar', function() { | |
return { | |
replace: true, | |
template: '<svg class="user-avatar" viewBox="0 0 128 128" height="64" width="64" pointer-events="none" display="block" > <path fill="#FF8A80" d="M0 0h128v128H0z"/> <path fill="#FFE0B2" d="M36.3 94.8c6.4 7.3 16.2 12.1 27.3 12.4 10.7-.3 20.3-4.7 26.7-11.6l.2.1c-17-13.3-12.9-23.4-8.5-28.6 1.3-1.2 2.8-2.5 4.4-3.9l13.1-11c1.5-1.2 2.6-3 2.9-5.1.6-4.4-2.5-8.4-6.9-9.1-1.5-.2-3 0-4.3.6-.3-1.3-.4-2.7-1.6-3.5-1.4-.9-2.8-1.7-4.2-2.5-7.1-3.9-14.9-6.6-23-7.9-5.4-.9-11-1.2-16.1.7-3.3 1.2-6.1 3.2-8.7 5.6-1.3 1.2-2.5 2.4-3.7 3.7l-1.8 1.9c-.3.3-.5.6-.8.8-.1.1-.2 0-.4.2.1.2.1.5.1.6-1-.3-2.1-.4-3.2-.2-4.4.6-7.5 4.7-6.9 9.1.3 2.1 1.3 3.8 2.8 5.1l11 9.3c1.8 1.5 3.3 3.8 4.6 5.7 1.5 2.3 2.8 4.9 3.5 7.6 1.7 6.8-.8 13.4-5.4 18.4-.5.6-1.1 1-1.4 1.7-.2.6-.4 1.3-.6 2-.4 1.5-.5 3.1-.3 4.6.4 3.1 1.8 6.1 4.1 8.2 3.3 3 8 4 12.4 4.5 5.2.6 10.5.7 15.7.2 4.5-.4 9.1-1.2 13-3.4 5.6-3.1 9.6-8.9 10.5-15.2M76.4 46c.9 0 1.6.7 1.6 1.6 0 .9-.7 1.6-1.6 1.6-.9 0-1.6-.7-1.6-1.6-.1-.9.7-1.6 1.6-1.6zm-25.7 0c.9 0 1.6.7 1.6 1.6 0 .9-.7 1.6-1.6 1.6-.9 0-1.6-.7-1.6-1.6-.1-.9.7-1.6 1.6-1.6z"/> <path fill="#E0F7FA" d="M105.3 106.1c-.9-1.3-1.3-1.9-1.3-1.9l-.2-.3c-.6-.9-1.2-1.7-1.9-2.4-3.2-3.5-7.3-5.4-11.4-5.7 0 0 .1 0 .1.1l-.2-.1c-6.4 6.9-16 11.3-26.7 11.6-11.2-.3-21.1-5.1-27.5-12.6-.1.2-.2.4-.2.5-3.1.9-6 2.7-8.4 5.4l-.2.2s-.5.6-1.5 1.7c-.9 1.1-2.2 2.6-3.7 4.5-3.1 3.9-7.2 9.5-11.7 16.6-.9 1.4-1.7 2.8-2.6 4.3h109.6c-3.4-7.1-6.5-12.8-8.9-16.9-1.5-2.2-2.6-3.8-3.3-5z"/> <circle fill="#444" cx="76.3" cy="47.5" r="2"/> <circle fill="#444" cx="50.7" cy="47.6" r="2"/> <path fill="#444" d="M48.1 27.4c4.5 5.9 15.5 12.1 42.4 8.4-2.2-6.9-6.8-12.6-12.6-16.4C95.1 20.9 92 10 92 10c-1.4 5.5-11.1 4.4-11.1 4.4H62.1c-1.7-.1-3.4 0-5.2.3-12.8 1.8-22.6 11.1-25.7 22.9 10.6-1.9 15.3-7.6 16.9-10.2z"/> </svg>' | |
}; | |
}); | |
app.config(function($mdThemingProvider) { | |
var customBlueMap = $mdThemingProvider.extendPalette('light-blue', { | |
'contrastDefaultColor': 'light', | |
'contrastDarkColors': ['50'], | |
'50': 'ffffff' | |
}); | |
$mdThemingProvider.definePalette('customBlue', customBlueMap); | |
$mdThemingProvider.theme('default') | |
.primaryPalette('customBlue', { | |
'default': '500', | |
'hue-1': '50' | |
}) | |
.accentPalette('pink'); | |
$mdThemingProvider.theme('input', 'default') | |
.primaryPalette('grey') | |
}); |
$gray: #eee; | |
md-content.md-default-theme { | |
background-color: $gray; | |
} | |
md-card { | |
background-color: #fff; | |
h2:first-of-type { | |
margin-top: 0; | |
} | |
} | |
md-toolbar { | |
.md-button.md-default-theme { | |
border-radius: 99%; // round toolbar buttons | |
} | |
} | |
h2 { | |
font-weight: 400; | |
} | |
.md-toolbar-tools-bottom { | |
font-size: small; | |
& :last-child { | |
opacity: 0.8; | |
} | |
} | |
md-toolbar:not(.md-hue-1), | |
.md-fab { | |
fill: #fff; | |
} | |
md-sidenav { | |
fill: #737373; | |
ng-md-icon { | |
position: relative; | |
top: 5px; // adjust for svg viewbox | |
} | |
} | |
.user-avatar { | |
border-radius: 99%; | |
} |