MODULE-TYPO

- Sass set-up
- md-list
- md-theming (install)
This commit is contained in:
iRouge
2015-01-16 07:52:29 -05:00
parent ec1b4b9b0c
commit f1d2b8cb75
312 changed files with 26839 additions and 1309 deletions

View File

@@ -6,25 +6,39 @@
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
xmlns:uix="OGo:uix">
<md-content md-scroll-y="md-scroll-y" class="md-padding" flex="flex" id="messagesList">
<md-list data-vs-repeat="56"
<md-content md-scroll-y="md-scroll-y" flex="flex" style="min-width: 300px;" id="messagesList">
<!--dirty fix for vs-repeat-->
<style>
.vs-repeat-repeated-element {
width: 100%;
}
</style>
<md-list data-vs-repeat="72"
data-vs-scroll-parent="#messagesList">
<md-item ng-repeat="currentMessage in mailbox.$messages track by currentMessage.id"
data-ng-class="{unread: !currentMessage.isread}">
<a data-ui-sref="mail.account.mailbox.message({accountId: account.id, mailboxId: (mailbox.path | encodeUri), messageId: currentMessage.uid})"
data-ui-sref-active="_selected">
<div class="name">
{{currentMessage.$shortAddress('from')}}
<span class="right" data-ng-bind-html="currentMessage.relativedate"><!-- date --></span>
</div>
<div class="subject">{{currentMessage.subject}}</div>
<i class="icon-ion-refresh"
data-ng-hide="mailbox.$loadMessage(currentMessage.uid)"><!-- loading --></i>
</a>
<md-item-content>
<div class="md-tile-left">
<!--avatar-->
</div>
<div class="sg-tile-content">
<a data-ui-sref="mail.account.mailbox.message({accountId: account.id, mailboxId: (mailbox.path | encodeUri), messageId: currentMessage.uid})"
data-ui-sref-active="_selected">
<div class="name">
{{currentMessage.$shortAddress('from')}}
<span class="right" data-ng-bind-html="currentMessage.relativedate"><!-- date --></span>
</div>
<div class="subject">{{currentMessage.subject}}</div>
<i class="icon-ion-refresh"
data-ng-hide="mailbox.$loadMessage(currentMessage.uid)"><!-- loading --></i>
</a>
</div>
</md-item-content>
<md-divider md-inset="true" ng-if="!$last"><!--divider--></md-divider>
</md-item>
</md-list>
</md-content>
<md-content class="md-padding" flex="66" data-ui-view="message"><!-- message view --></md-content>
<md-content class="md-padding" flex="flex" data-ui-view="message"><!-- message view --></md-content>
</container>

View File

@@ -268,7 +268,7 @@
</div>-->
<main layout="column" layout-fill="layout-fill">
<md-toolbar layout="row" layout-align="space-between start" class="md-tall md-warn">
<md-toolbar layout="row" layout-align="space-between start" class="md-tall md-grey">
<!--fixme : md-toolbar-tools height is inconsistently defined, in former version it was 64px (basic toolbar height), here it's 100% -->
<div class="md-toolbar-tools">
<span flex="flex">

View File

@@ -25,6 +25,8 @@
<link rel="shortcut icon" var:href="siteFavicon" type="image/x-icon" />
<link type="text/css" rel="stylesheet" rsrc:href="css/icons.css"/>
<link type="text/css" rel="stylesheet" rsrc:href="css/angular-material.css"/>
<link type="text/css" rel="stylesheet" rsrc:href="css/themes/grey-theme.css"/>
<link type="text/css" rel="stylesheet" rsrc:href="css/components.css"/>
<var:if condition="hasPageSpecificCSS"
><link type="text/css" rel="stylesheet" var:href="pageCSSURL"
/></var:if>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -164,6 +164,13 @@
allowedTagsPattern: /([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)/i
});
}])
//todo : define complete custom themes (light and dark) with SOGo green as accent-color
.config(function($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryColor('grey', {
'default': '800'
});
})
.run(function($rootScope) {
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {

View File

@@ -1,4 +1,4 @@
@import "settings";
@import "functions";
//$primary-color: #75B4BF;
//$topbar-link-bg-active: #75B4BF;

View File

@@ -1,4 +1,4 @@
@import "settings";
@import "functions";
$module-color: #D04747; // red
$module-secondary-color: #501B1B; // darker red

View File

@@ -1,4 +1,4 @@
@import "settings";
@import "functions";
@import "foundation";
/* @import "foundation/components/alert-boxes", */
/* "foundation/components/buttons", */

View File

@@ -0,0 +1,44 @@
// SOGo by Inverse
// sogo.nu
// version 3.alpha
//
//
// UTILITIES FUNCTIONS
//
// Strip Unit - From Foundation
// Removes the unit (e.g. px, em, rem) from a value, returning the number only.
//
// @param {number} $num - Number to strip unit from.
// @return The same number, sans unit.
@function strip-unit($num) {
@return $num / ($num * 0 + 1);
}
/// sp|dp to px
// Google's Material design specs are in 'sp' or 'dp' which are not css units
// 'dp' is 'density independant pexels' and 'sp' is 'scale-independent pixels' (same as dp, but will be scaled by the user's font size preference)
// Android gives a 160dpi base value to 'sp' and 'dp', but Google's examples seems to use 'sp' as 'px'
// We define a scaling factor in case we need to adjust
// 'sp' is scale to 1 css-px for a rem-base-value of 16px (default)
// 'dp' is scale to 1 css-px according to scaling factor
//
// sp-to-px converts a 'sp' value to css-pixel value. Units, if specified will be stripped
// dp-to-px converts a 'dp' value to css-pixel value. Units, if specified will be stripped
//
// @param {number} $value - sp or dp value to convert.
//
// @return {number} in px.
//
@function dp-to-px($value) {
$value: strip-unit($value) * strip-unit($sg-dp-scale-factor) * 1px;
@if ($value == 0sp) { $value: 0; } // Turn 0rem into 0
@return $value;
}
@function sp-to-px($value) {
$value: strip-unit($value) * $sg-sp-scale-factor * 1px;
@if ($value == 0sp) { $value: 0; } // Turn 0sp into 0
@return $value;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,58 @@
/**
*
* Main Stylesheet SOGo
* Based on Angular Material Design
* IMPORTANT : This scss file might interfere with actual Angular-Material grunt-build
* and will generate a (too)) long css file because of the overrides
*
**/
// Compass import - comment-out if needed
//@import 'vendors/compass';
// Browser reset - most effective for applications. Generated by Compass in a non-regular way
@import 'reset.css';
//@import 'components/normalize';
// Fonts
@import '../css/ubuntu.css';
// MODULES - Shouldn't immediately generate any css
@import 'functions';
// Angular-Material core style files (filenames are not reflecting content)
@import '../angular-material/src/core/style/color-palette.scss';
@import '../angular-material/src/core/style/variables.scss';
@import '../angular-material/src/core/style/mixins.scss';
@import '../angular-material/src/core/style/structure.scss';
@import '../angular-material/src/core/style/layout.scss';
/* Local overrides from angular-material src */
@import 'vendors/angular-material/core/style/color-palette';
@import 'vendors/angular-material/core/style/variables';
@import 'vendors/angular-material/core/style/mixins';
@import 'vendors/angular-material/core/style/structure';
@import 'vendors/angular-material/core/style/layout';
// Icons -
// Angular-Material Color Palettes (used by $mdThemingProvider [theming.js]) - generated at (grunt ?) build
// @import '../angular-material/src/core/style/color-palette.scss';
// COMPONENTS
// Angular-material src components
/* Angular-material components local overrides */
@import 'vendors/angular-material/components/list/list.scss';
@import 'vendors/angular-material/components/divider/divider.scss';
// Pages-specific styles
// Make sure this is last to override anything else :)

View File

@@ -0,0 +1,55 @@
/**
*
* Articles list
*
**/
.articles-list {
padding-left: 0;
}
.articles-list__item {
padding-bottom: $lineHeight * 2;
&:last-child {
padding-bottom: $lineHeight * 2 + 1;
}
padding-left: 0;
&::before {
content: "";
display: block;
width: 40%;
height: 1px;
box-shadow: inset 0 1px 0 0 $colorGrayKeyline;
margin-right: 0;
margin-left: 30%;
}
h3 {
a:hover {
text-decoration: none;
}
}
p {
margin-top: $lineHeight;
margin-bottom: $lineHeight;
}
&:first-child {
padding-top: 0;
@include medium {
padding-top: $lineHeight - 2;
}
&::before {
display: none;
}
}
}

View File

@@ -0,0 +1,31 @@
/**
*
* Breadcrumb
*
**/
.breadcrumbs {
display: none;
@include medium {
display: block;
}
position: relative;
z-index: 1;
}
.breadcrumbs p {
@include type--small;
padding-top: $lineHeight;
}
.breadcrumbs__link {
@include type--small;
color: black;
font-weight: 400;
padding-top: 0;
@include medium {
padding-top: 0;
}
}

View File

@@ -0,0 +1,56 @@
/**
*
* Button
*
**/
.button {
display: inline-block;
padding: (($lineHeight / 2) - 1) 32px;
margin-bottom: $lineHeight / 2;
margin-top: $lineHeight / 2;
min-height: $lineHeight;
text-align: center;
font-family: $fontHighlight;
font-weight: 600;
text-decoration: none;
outline: 0;
transition: none;
&:hover {
background: #4d4d4d;
color: #ffffff;
border: 1px solid #4d4d4d;
text-decoration: none;
}
}
// Mixin to create buttons
@mixin style-button($color, $textColor, $isInverted: false) {
background: $color;
color: $textColor;
border: 1px solid darken($color, 10%);
@if $isInverted { border-color: transparent;}
}
.button--primary {
@extend .button;
@include style-button(#4285f4, #ffffff);
}
.button--secondary {
@extend .button;
@include style-button(#ffffff, $colorBlue);
}
.button--secondary-variation {
@extend .button;
@include style-button(#ffffff, $colorBlue, true);
}

View File

@@ -0,0 +1,42 @@
/**
*
* Column list
*
**/
.columns-list-wrapper {
@include wide {
margin-right: $mediumColWidth;
}
}
.list--columns {
border-bottom: 1px solid #ccc;
padding-bottom: $lineHeight - 1;
margin-bottom: 1px;
@include medium {
column-count: 2;
column-rule: 0 none transparent;
column-gap: 0;
}
& li,
& .columns-list-item {
@include type--small;
padding: 0;
}
& a {
display: block;
position: relative;
padding-left: 39px;
&::before {
line-height: 26px;
}
}
}

View File

@@ -0,0 +1,144 @@
/**
*
* Grid
*
**/
@include medium-only {
// Generating grid classes for medium view
@for $i from 1 through $mediumColCount {
.g-medium--#{$i} {
@include rule--col(medium);
width: ($mediumColWidth*$i) + ($mediumGutterWidth*($i + -1));
@if $i == $mediumColCount { margin-right: 0; }
}
@if $i < $mediumColCount {
.g-medium--push-#{$i} {
margin-left: ($mediumColWidth*$i) + ($mediumGutterWidth*$i);
}
.g-medium--pull-#{$i} {
margin-right: ($mediumColWidth*$i) + ($mediumGutterWidth*$i);
}
}
}
.g-medium--full {
@include rule--col(medium);
margin-right: 0;
width: 100%;
}
.g--third {
@include rule--col(medium);
width: $mediumColWidth;
}
.g--half,
.g-medium--half {
@include rule--col(medium);
width: 50% - $mediumGutterWidth/2;
}
.g-medium--last { margin-right: 0; }
.g-medium--last + .g-medium--half { clear: left; }
.g--pull-half { margin-right: 50% + $mediumGutterWidth/2; }
}
@include wide {
// Generating grid classes for wide view
@for $i from 1 through $wideColCount {
.g-wide--#{$i} {
@include rule--col(wide);
width: ($wideColWidth*$i) + ($wideGutterWidth*($i + -1));
@if $i == $wideColCount { margin-right: 0; }
}
@if $i < $wideColCount {
.g-wide--push-#{$i} {
margin-left: ($wideColWidth*$i) + ($wideGutterWidth*$i);
}
.g-wide--pull-#{$i} {
margin-right: ($wideColWidth*$i) + ($wideGutterWidth*$i);
}
}
}
.g-wide--last { margin-right: 0; }
.g-wide--full {
@include rule--col(wide);
margin-right: 0;
width: 100%;
}
.g--third {
@include rule--col(wide);
width: 30.8%;
}
.g--half,
.g-wide--half {
@include rule--col(wide);
width: 50% - $wideGutterWidth/2;
}
.g--pull-half { margin-right: 50% + $wideGutterWidth/2; }
}
// This is a global 'last' class
// to be used with global grid classes, such as 'half' or 'third'
// Example usage:
// <div class="third"></div>
// <div class="third"></div>
// <div class="third last"></div>
.g--last { margin-right: 0; }
// This is a global 'centered' class
.g--centered {
float: none; // reset float to none so we can center it
margin-left: auto;
margin-right: auto;
}
// This is a grid overlay
// Its purpose is to show users our grid system
// It becomes visible when a class 'debug' is added to the body
.grid-overlay {
display: none;
pointer-events: none;
// Only show when parents (body) has debug class
.debug & {
@include container(true);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
display: block;
[class*="g-"] {
height: 100%;
background-color: rgba(lighten(#000, 35%), .2);
}
@include medium-only {
.g-wide--last {
display: none;
}
}
@include small-only {
display: none;
}
}
}

View File

@@ -0,0 +1,78 @@
/**
*
* Guides List
*
**/
.guides-list {
overflow: hidden;
@include medium {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
padding-top: $lineHeight*2;
}
}
.guides-list__item {
padding: 0;
background: #ffffff;
margin-top: $lineHeight;
margin-bottom: 0;
@include medium {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
h3 {
margin: 0 32px;
}
p {
margin: $lineHeight 32px 0;
}
.primary-content {
@include medium {
flex: 1;
}
}
.secondary-content {
position: relative;
// background: #f5f5f5;
margin-top: ($lineHeight*2) - 1;
border-top: 1px solid $colorGrayKeyline;
@include medium {
width: 100%; // needed due to parent being flex
}
.icon-circle {
position: absolute;
top: -$lineHeight - 2;
left: 50%;
margin-left: -21px;
border: 2px solid #ffffff;
& i {
font-size: 23px;
}
}
}
ol {
margin: $lineHeight 0 0;
padding: $lineHeight*2 0 $lineHeight*2;
margin-top: 0;
}
&::before {
display: none;
}
}

View File

@@ -0,0 +1,110 @@
/**
*
* Icon Circle
*
**/
.icon-circle,
.icon-circle--large {
height: 0;
width: 0;
background: $colorGray;
display: block;
position: relative;
border-radius: 100%;
font-size: 0;
padding: 22px; // Breaks baseline grid
margin: 4px auto; // Adds margin top/bottom to fix baseline grid ;)
i,
span {
position: absolute;
line-height: 0px;
top: 50%;
width: 100%;
left: 0;
text-align: center;
color: #ffffff;
font-size: $fontLarge;
}
span {
font-family: $fontHighlight;
font-size: $fontLarge;
font-weight: 700;
@include medium {
font-size: $fontXLarge;
}
}
}
.icon-circle--large {
margin-top: 0;
margin-bottom: 0;
padding: $lineHeight;
position: relative;
i {
font-size: $fontLarge;
@include medium {
font-size: $fontXLarge;
}
}
@include medium {
padding: ($lineHeight + $lineHeight/2) - 2;
border: 2px solid #ffffff;
a & {
padding: ($lineHeight + $lineHeight/2) - 1;
box-shadow: inset 0px 0px 0px 1px rgba(#ffffff, .42);
border: 1px solid;
// demo transition
transition: all 100ms linear;
transform: translateZ(0); // kick in hardware acceleration
}
.no-touch a:hover & {
box-shadow: inset 0px 0px 0px 1px #ffffff;
transform: scale(1.1);
}
}
}
.icon-circle--nav {
height: 0;
width: 0;
background: $colorGray;
display: block;
position: relative;
border-radius: 100%;
font-size: 0;
padding: $lineHeight/2;
margin: 0 auto;
@include medium {
padding: 22px; // Breaks baseline grid
margin-top: 4px; // Adds margin top/bottom to fix baseline grid ;)
margin-bottom: 4px; // Adds margin top/bottom to fix baseline grid ;)
}
i {
position: absolute;
line-height: 1px;
top: 50%;
width: 100%;
left: 0;
text-align: center;
color: #ffffff;
font-size: $fontBase;
@include medium {
font-size: $fontLarge;
}
}
}

View File

@@ -0,0 +1,147 @@
@font-face {
font-family: icons;
src: url(../images/icons/icons.eot);
src: url(../images/icons/icons.eot?#iefix) format('embedded-opentype'),
url(../images/icons/icons.woff2) format('woff2'),
url(../images/icons/icons.woff) format('woff'),
url(../images/icons/icons.ttf) format('truetype'),
url(../images/icons/icons.svg?#icons) format('svg');
font-weight: normal;
font-style: normal;
}
.icon {
font-family: 'icons';
display: inline-block;
vertical-align: top;
line-height: 1;
font-weight: normal;
font-style: normal;
speak: none;
text-decoration: inherit;
text-transform: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// Icons
$icon-bullet: '\e001';
.icon-bullet::before {
content:"\e001";
}
$icon-chevron-down: '\e002';
.icon-chevron-down::before {
content: '\e002';
}
$icon-chevron-large: '\e003';
.icon-chevron-large::before {
content: '\e003';
}
$icon-chevron-left: '\e004';
.icon-chevron-left::before {
content: '\e004';
}
$icon-chevron-right: '\e005';
.icon-chevron-right::before {
content: '\e005';
}
$icon-chevron-up: '\e006';
.icon-chevron-up::before {
content: '\e006';
}
$icon-close: '\e007';
.icon-close::before {
content: '\e007';
}
$icon-cog: '\e008';
.icon-cog::before {
content: '\e008';
}
$icon-diamond: '\e009';
.icon-diamond::before {
content: '\e009';
}
$icon-exclamation: '\e00a';
.icon-exclamation::before {
content: '\e00a';
}
$icon-google-dev: '\e00b';
.icon-google-dev::before {
content: '\e00b';
}
$icon-hash: '\e00c';
.icon-hash::before {
content: '\e00c';
}
$icon-introduction-to-media: '\e00d';
.icon-introduction-to-media::before {
content: '\e00d';
}
$icon-lessons: '\e00e';
.icon-lessons::before {
content: '\e00e';
}
$icon-menu: '\e00f';
.icon-menu::before {
content: '\e00f';
}
$icon-minus: '\e010';
.icon-minus::before {
content: '\e010';
}
$icon-multi-device-layouts: '\e011';
.icon-multi-device-layouts::before {
content: '\e011';
}
$icon-performance: '\e012';
.icon-performance::before {
content: '\e012';
}
$icon-plus: '\e013';
.icon-plus::before {
content: '\e013';
}
$icon-question: '\e014';
.icon-question::before {
content: '\e014';
}
$icon-slash: '\e015';
.icon-slash::before {
content: '\e015';
}
$icon-star: '\e016';
.icon-star::before {
content: '\e016';
}
$icon-tick: '\e017';
.icon-tick::before {
content: '\e017';
}
$icon-user-input: '\e018';
.icon-user-input::before {
content: '\e018';
}

View File

@@ -0,0 +1,21 @@
/**
*
* Link
*
**/
a {
color: $colorBlue;
}
a:hover {
text-decoration: none;
}
.cta--primary {
@include style-cta($colorBlue, $icon-chevron-right);
}
.cta--secondary {
@include style-cta($colorBlue);
}

View File

@@ -0,0 +1,336 @@
/**
*
* List
*
**/
ul,
ol {
list-style: none;
margin: 0;
@include small-only {
padding-left: 0;
}
}
ul li {
position: relative;
padding-left: 16px;
@include bullet-type("", icon-bullet);
&::before {
font-size: 4px;
}
}
ol {
counter-reset: list;
> li {
@include numbered-list;
position: relative;
padding-left: 32px;
// This selected every adjacent <li>
// from the 10th and overrides the
// content property of each
&:nth-child(10n) ~ li::before,
&:nth-child(10n)::before {
content: counter(list);
}
}
}
ul ol,
ol ul {
padding-top: 0;
}
/*========== LIST LINKS ==========*/
ul.list-links {
li::before {
display: none;
}
a {
@include bullet-type("", icon-bullet);
&::before {
font-size: 4px;
}
font-weight: 400;
}
&.list-links--primary {
a {
@include bullet-type("", icon-chevron-right);
font-weight: 400;
font-family: $fontHighlight;
line-height: 1; // fixes baseline grid alignment
text-decoration: none;
}
}
}
ol.list-links {
li {
&::before {
display: none;
}
a {
display: inline-block;
@include numbered-list;
font-weight: 300;
}
&:nth-child(10n) ~ li a::before,
&:nth-child(10n) a::before {
content: counter(list);
}
}
&.list-links--secondary {
a::before {
display: none;
}
}
}
.list-links--secondary {
@include type--base;
padding-left: 0;
li {
padding-left: 0;
}
}
/*========== ANCHOR LIST ==========*/
.list-anchor {
padding-left: 0;
li {
@include type--base;
padding-top: 0;
padding-left: 0;
&::before {
display: none
}
}
a {
@include bullet-type("", icon-bullet);
line-height: 1; // fixes baseline grid alignment
display: inline-block;
padding-left: 16px;
&::before {
font-size: 4px;
}
}
}
/*========== SMALL LIST ==========*/
.list-small {
li {
@include medium {
@include type--small;
padding-top: 0;
}
}
}
/*========== CENTERED LIST ==========*/
.list-centered {
text-align: center;
padding-left: 0;
}
/*========== FEATURED LIST ==========*/
.featured-list {
padding-top: $lineHeight * 3;
padding-bottom: $lineHeight * 3;
}
.featured-list__item {
background: #ffffff;
padding-left: 0;
padding-top: $lineHeight;
padding-bottom: $lineHeight;
@include medium {
min-height: $lineHeight * 13;
padding: $lineHeight * 2 32px;
}
margin-top: $lineHeight;
&:first-child {
margin-top: 0;
}
p {
margin-bottom: $lineHeight;
}
}
.featured-list__img-wrapper {
display: none;
position: relative;
padding-top: $lineHeight;
margin: 0 -5%;
@include medium {
display: block;
padding-top: 0;
margin: 0;
}
}
.featured-list__img {
@include medium {
padding-top: 60.8%;
padding-bottom: 0;
height: 0;
overflow: hidden;
position: absolute;
width: 100%;
}
img {
display: block;
margin: 0 auto;
max-width: 100%;
@include medium {
margin: 0;
position: absolute;
top: 0;
height: 100%;
width: 100%;
left: 0;
}
}
}
/*========== RELATED GUIDES LIST ==========*/
.related-guides-list {
font-family: $fontHighlight;
padding-top: 0;
padding-left: 0;
@include medium {
padding-top: $lineHeight
}
@include wide {
padding-top: 0
}
p {
padding-top: 0;
}
.tag {
padding-top: 0;
}
li {
padding-top: $lineHeight;
padding-bottom: $lineHeight - 1;
border-bottom: 1px solid $colorGrayKeyline;
&:last-child {
border-color: transparent;
}
@include medium {
padding-top: 0;
padding-bottom: 0;
border-color: transparent;
}
}
}
/*========== LIST RESET ==========*/
.list--reset {
padding-left: 0;
li {
padding-left: 0;
}
&.list-links a::before,
& li::before {
display: none !important; // Fine to use !important when we are forcing an override
}
}
/*========== LESSONS ==========*/
.list-lessons {
padding-left: 0;
& a {
color: #ffffff;
}
& .current {
&,
a {
text-decoration: none;
cursor: default;
}
& .icon {
font-size: $fontSmall;
display: inline-block;
background: rgba(#000000, .2);
border-radius: 100%;
width: 26px;
line-height: 26px;
text-align: center;
margin-left: 7px;
}
}
}
/*========== GUIDES INTO - used on homepage ==========*/
.list-guides-intro {
margin-bottom: $lineHeight*2;
@include small-only {
padding-top: $lineHeight*2;
}
li {
border-bottom: 1px solid $colorGrayKeyline;
padding-bottom: ($lineHeight*2) - 1;
margin-bottom: ($lineHeight*2);
@include medium {
border-color: transparent;
padding-bottom: 0;
}
&:last-child {
border-bottom: transparent;
margin-bottom: 0;
}
}
}

View File

@@ -0,0 +1,19 @@
/**
*
* Media - imgs/videos
*
**/
img,
video,
object {
max-width: 100%;
}
img {
.content & {
margin-top: $lineHeight;
margin-bottom: $lineHeight;
}
}

View File

@@ -0,0 +1,16 @@
/**
*
* subsection__title
*
**/
.subsection-title {
color: $colorGrayDark;
margin-top: $lineHeight * 2;
}
.subsection-number {
@include type--base;
padding-top: 0;
display: block;
}

View File

@@ -0,0 +1,158 @@
/**
*
* Table
*
**/
table {
margin-top: $lineHeight;
width: 100%;
thead {
background: $colorBlue;
color: #ffffff;
}
th {
text-align: center;
display: none;
font-family: $fontHighlight;
@include type--medium;
}
tr {
@include medium {
border-bottom: 1px solid #ffffff;
}
}
tbody {
background: $colorGrayBackground;
}
td {
display: block;
padding-top: $lineHeight/2;
padding-bottom: $lineHeight/2;
// This is to re-plicate the table-headers for mobile
&::before {
content: attr(data-th) " :";
display: inline-block;
color: #ffffff;
background: $colorBlue;
border-right: 2px solid #ffffff;
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100px;
max-height: 100%;
font-family: $fontHighlight;
font-size: 16px;
font-weight: 400;
padding-left: $lineHeight/2;
padding-top: $lineHeight/2;
@include medium {
display: none;
}
}
}
th,
td {
position: relative;
padding-left: 140px;
@include medium {
display: table-cell;
}
}
th {
@include medium {
padding: $lineHeight;
padding-top: 13px;
padding-bottom: $lineHeight/2 - 1;
}
}
td {
@include medium {
padding: $lineHeight;
padding-bottom: $lineHeight - 1;
}
}
}
td:last-child::after {
content: "";
display: block;
background: #ffffff;
height: 1px;
left: 0;
position: absolute;
bottom: 0;
width: 100%;
@include medium {
display: none;
}
}
.table-2 {
col {
width: $mediumContainer / 2;
@include wide {
width: $wideContainer / 2;
}
}
th,
td {
@include medium {
&:first-child {
border-right: 2px solid #ffffff;
}
}
}
}
.table-3 {
col {
width: $mediumContainer / 3;
@include wide {
width: $wideContainer / 3;
}
}
th,
td {
@include medium {
&:nth-child(2) {
border-left: 2px solid #ffffff;
border-right: 2px solid #ffffff;
}
}
}
}
.table-4 {
col {
width: $mediumContainer / 4;
@include wide {
width: $wideContainer / 4;
}
}
th,
td {
@include medium {
&:nth-child(2),
&:nth-child(3) {
border-left: 2px solid #ffffff;
border-right: 2px solid #ffffff;
}
}
}
}

View File

@@ -0,0 +1,52 @@
/**
*
* Typography
*
**/
// Just normalizing text
// Recommend using padding instead of margin
h1, h2, h3, h4, h5, p {
margin: 0;
}
// Definitions
.small,
small {
@include type--small;
}
.base,
p,
ul,
ol {
@include type--base;
}
.medium,
h4 {
@include type--medium;
}
.large,
h3 {
@include type--large;
}
.xlarge,
h2 {
@include type--xlarge;
}
.xxlarge,
h1 {
@include type--xxlarge;
}
.huge {
@include type--huge;
}
li > p {
padding-top: 0;
}

View File

@@ -0,0 +1,88 @@
/**
*
* Article nav
*
**/
.article-nav {
overflow: hidden;
position: relative;
&::before {
content: '';
border-left: 2px solid $colorGrayKeyline;
height: 100%;
position: absolute;
top: 0;
left: 50%;
}
}
.article-nav-link {
padding: $lineHeight 32px;
float: left;
width: 50%;
position: relative;
&::before{
position: absolute;
top: 21px;
font-family: $fontHighlight;
font-size: $fontMedium;
font-weight: 400;
@include medium {
top: 25px;
font-size: $fontLarge;
display: block;
padding: 13px 10px;
color: #ffffff;
background: $colorBlue;
}
}
}
.article-nav p {
padding: 0;
margin: 0;
}
.article-nav-link--prev {
text-align: right;
// border-right-width: 1px;
&::before {
font-family: $fontIcon;
@extend .icon-chevron-left::before;
left: 32px;
}
p {
@include medium {
padding-left: 52px;
}
}
}
.article-nav-link--next {
// border-left-width: 1px;
&::before {
font-family: $fontIcon;
@extend .icon-chevron-right::before;
right: 32px;
}
p {
@include medium {
padding-right: 52px;
}
}
}
.article-nav-count {
@include type--large;
font-weight: 700;
@include medium {font-weight: 400;}
}

View File

@@ -0,0 +1,25 @@
/**
*
* Articles section
*
**/
.articles-section {
background: $colorGrayBackground;
text-align: center;
padding: $lineHeight 0 $lineHeight*4;
}
.articles-count {
color: $colorBlue;
font-family: $fontHighlight;
font-weight: 400;
}
.article-section__icon {
top: -($lineHeight);
@include medium {
top: -($lineHeight + $lineHeight/2);
}
}

View File

@@ -0,0 +1,56 @@
/**
*
* Text module
*
**/
.did-you-know {
ol {
@include medium {
padding-top: 0 !important;
}
}
.cta--primary {
margin-top: $lineHeight;
font-weight: 500;
}
&>.g--half {
position: relative;
padding-left: 0;
@include medium {padding-left: 32px}
}
}
.did-you-know__symbol {
padding-bottom: $lineHeight*12;
@include medium {padding-bottom: $lineHeight}
&::after {
content: $icon-question;
color: $colorBlue;
font-family: $fontIcon;
font-size: 300px;
top: 150px;
left: 30%;
position: relative;
display: block;
width: 0;
@include medium {
position: absolute;
font-size: 400px;
top: 200px;
left: 110%;
}
@include wide {
position: absolute;
font-size: 400px;
top: 200px;
left: 124%;
}
}
}

View File

@@ -0,0 +1,78 @@
/**
*
* Editorial Header
*
**/
.editorial-header {
overflow: hidden;
.breadcrumbs {
color: $colorBlue;
a {
color: $colorBlue;
}
}
.container {
@include medium {
position: relative;
// Pseudo elements to add the background characters
&::before {
content: $icon-chevron-large;
font-family: $fontIcon;
font-size: 1000px;
line-height: 0;
display: block;
position: absolute;
top: 0;
right: 100%;
color: $colorGrayBackground;
margin: 168px -35px 0 0;
}
}
}
}
.editorial-header__excerpt {
@include type--medium(true);
font-family: $fontHighlight;
}
.editorial-header .tag{
padding-top: $lineHeight*2;
}
.editorial-header__subtitle {
@include type--xxlarge;
padding-top: 0;
@include medium {
padding-top: 0;
padding-bottom: $lineHeight;
}
color: $colorBlue;
}
.editorial-header__toc {
margin-top: $lineHeight;
ol {
padding-top: 0;
@include medium {
padding-top: 0;
}
}
}
.editorial-header__toc-title {
font-family: $fontHighlight;
border-bottom: 1px solid $colorGrayKeyline;
margin-bottom: 13px;
padding-bottom: 13px !important;
color: $colorBlue;
}

View File

@@ -0,0 +1,9 @@
/**
*
* Editorial Header
*
**/
.featured-section {
background: $colorGrayBackground;
}

View File

@@ -0,0 +1,61 @@
/**
*
* Editorial Header
*
**/
.featured-spotlight {
background: $colorGrayDark;
color: #ffffff;
overflow: hidden;
padding-bottom: $lineHeight * 3 - 1;
margin-top: $lineHeight * 2;
p {
padding-bottom: $lineHeight;
}
.cta--primary {
color: #ffffff;
&:hover {
color: #ffffff;
}
}
}
.featured-spotlight__container {
position: relative;
}
.featured-spotlight__img {
@include small-only {
padding-top: 58.4%;
padding-bottom: 0;
height: 0;
overflow: hidden;
position: relative;
width: 100%;
}
img {
margin: 0 auto;
display: block;
width: 100%;
position: absolute;
left: 0;
top: 0;
margin: 0;
@include medium {
width: auto;
max-width: none;
left: 100% + $mediumGutterWidth * 2;
}
@include wide {
left: 100% + $wideGutterWidth * 2;
}
}
}

View File

@@ -0,0 +1,5 @@
.guides-section {
background: $colorGrayBackground;
text-align: center;
padding: $lineHeight 0 $lineHeight * 4;
}

View File

@@ -0,0 +1,269 @@
/**
*
* Highlight
*
**/
.highlight-module {
overflow: hidden;
margin-top: $lineHeight * 2;
margin-bottom: $lineHeight;
position: relative;
&::after {
background: $colorGrayBackground;
content: '';
height: 100%;
position: absolute;
top: 0;
bottom: 0;
z-index: 0;
width: 100%;
right: 0;
left: 0;
}
ul,
ol {
padding-left: 0;
}
}
.highlight-module__container {
@include container;
padding-bottom: $lineHeight * 3;
z-index: 1;
@include highlight-symbol();
@include medium {
padding-bottom: $lineHeight * 2;
}
@include wide {
min-height: $lineHeight * 8;
}
}
.highlight-module__title {
@include type--huge;
padding-top: $lineHeight;
@include wide {
@include type--xxlarge;
}
}
.highlight-module__cta {
display: block;
}
/*========== LEARNING ==========*/
.highlight-module--learning {
color: #ffffff;
&::after {
background-color: $colorLearning;
}
a {
color: #ffffff;
text-decoration: underline;
}
}
/*========== REMEMBER ==========*/
.highlight-module--remember {
color: #ffffff;
&::after {
background-color: $colorRemember;
}
a {
color: #ffffff;
text-decoration: underline;
}
}
/*========== CODE ==========*/
.highlight-module--code {
overflow: visible;
margin-bottom: $lineHeight * 2;
pre {
margin: 0;
padding-top: $lineHeight;
font-size: $fontBase - 2;
line-height: $lineHeight;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
span {
margin: 0;
padding: 0;
display: inline-block;
}
}
code {
margin: 0;
padding: 0;
word-spacing: -2px;
display: block;
}
.highlight-module__container {
padding-bottom: 0;
}
.highlight-module__cta {
position: absolute;
bottom: -$lineHeight;
}
}
/*========== LEFT ==========*/
.highlight-module--left {
&::after {
@include wide {
width: 80%;
right: 20%;
}
}
}
/*========== RIGHT ==========*/
.highlight-module--right {
&::after {
@include wide {
width: 80%;
left: 20%;
}
}
&.highlight-module--code {
&::after {
@include wide {
width: 100%;
left: 0;
}
}
}
}
/*========== INLINE ==========*/
.highlight-module--inline {
color: $colorText;
overflow: visible;
margin: $lineHeight 0 0;
& .highlight-module__container {
padding-bottom: 0;
&::before {
display: none;
}
}
& .highlight-module__content {
border-color: $colorGrayKeyline;
border-style: solid;
border-width: 1px;
border-left-width: 0;
border-right-width: 0;
margin-bottom: -2px; // Offsetting 2px to considerate border top/bottom - baseline rules.
padding: 0 0 $lineHeight;
}
& .highlight-module__title {
@include type--large;
}
&.highlight-module--remember {
& .highlight-module__title,
& li::before {
color: $colorRemember;
}
}
&.highlight-module--learning {
& .highlight-module__title,
& li::before {
color: $colorLearning;
}
}
&::after {
display: none !important;
}
}
/*========== COLORS ==========*/
div.highlight > pre > code, code .highlight { background: transparent; }
div.highlight > pre > code .c, code .highlight .c { color: #999988; font-style: italic } /* Comment */
div.highlight > pre > code .err, code .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
div.highlight > pre > code .k, code .highlight .k { } /* Keyword */
div.highlight > pre > code .o, code .highlight .o { } /* Operator */
div.highlight > pre > code .cm, code .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
div.highlight > pre > code .cp, code .highlight .cp { color: $colorGray; } /* Comment.Preproc */
div.highlight > pre > code .c1, code .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
div.highlight > pre > code .cs, code .highlight .cs { color: $colorGray; font-style: italic } /* Comment.Special */
div.highlight > pre > code .gs, code .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
div.highlight > pre > code .gd .x, code .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
div.highlight > pre > code .ge, code .highlight .ge { font-style: italic } /* Generic.Emph */
div.highlight > pre > code .gr, code .highlight .gr { color: #aa0000 } /* Generic.Error */
div.highlight > pre > code .gh, code .highlight .gh { color: $colorGray } /* Generic.Heading */
div.highlight > pre > code .gi, code .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
div.highlight > pre > code .gi .x, code .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
div.highlight > pre > code .go, code .highlight .go { color: #888888 } /* Generic.Output */
div.highlight > pre > code .gp, code .highlight .gp { color: #555555 } /* Generic.Prompt */
div.highlight > pre > code .gs, code .highlight .gs { } /* Generic.Strong */
div.highlight > pre > code .gu, code .highlight .gu { color: #aaaaaa } /* Generic.Subheading */
div.highlight > pre > code .gt, code .highlight .gt { color: #aa0000 } /* Generic.Traceback */
div.highlight > pre > code .kc, code .highlight .kc { } /* Keyword.Constant */
div.highlight > pre > code .kd, code .highlight .kd { } /* Keyword.Declaration */
div.highlight > pre > code .kp, code .highlight .kp { } /* Keyword.Pseudo */
div.highlight > pre > code .kr, code .highlight .kr { } /* Keyword.Reserved */
div.highlight > pre > code .kt, code .highlight .kt { color: #445588; } /* Keyword.Type */
div.highlight > pre > code .m, code .highlight .m { color: #009999 } /* Literal.Number */
div.highlight > pre > code .s, code .highlight .s { color: $colorLearning } /* Literal.String */
div.highlight > pre > code .na, code .highlight .na { color: #008080 } /* Name.Attribute */
div.highlight > pre > code .nb, code .highlight .nb { color: #0086B3 } /* Name.Builtin */
div.highlight > pre > code .nc, code .highlight .nc { color: #445588; } /* Name.Class */
div.highlight > pre > code .no, code .highlight .no { color: #008080 } /* Name.Constant */
div.highlight > pre > code .ni, code .highlight .ni { color: #800080 } /* Name.Entity */
div.highlight > pre > code .ne, code .highlight .ne { color: #990000; } /* Name.Exception */
div.highlight > pre > code .nf, code .highlight .nf { color: #990000; } /* Name.Function */
div.highlight > pre > code .nn, code .highlight .nn { color: #555555 } /* Name.Namespace */
div.highlight > pre > code .nt, code .highlight .nt { color: $colorRemember } /* Name.Tag */
div.highlight > pre > code .nv, code .highlight .nv { color: #008080 } /* Name.Variable */
div.highlight > pre > code .ow, code .highlight .ow { } /* Operator.Word */
div.highlight > pre > code .w, code .highlight .w { color: #bbbbbb } /* Text.Whitespace */
div.highlight > pre > code .mf, code .highlight .mf { color: #009999 } /* Literal.Number.Float */
div.highlight > pre > code .mh, code .highlight .mh { color: #009999 } /* Literal.Number.Hex */
div.highlight > pre > code .mi, code .highlight .mi { color: #009999 } /* Literal.Number.Integer */
div.highlight > pre > code .mo, code .highlight .mo { color: #009999 } /* Literal.Number.Oct */
div.highlight > pre > code .sb, code .highlight .sb { color: $colorLearning } /* Literal.String.Backtick */
div.highlight > pre > code .sc, code .highlight .sc { color: $colorLearning } /* Literal.String.Char */
div.highlight > pre > code .sd, code .highlight .sd { color: $colorLearning } /* Literal.String.Doc */
div.highlight > pre > code .s2, code .highlight .s2 { color: $colorLearning } /* Literal.String.Double */
div.highlight > pre > code .se, code .highlight .se { color: $colorLearning } /* Literal.String.Escape */
div.highlight > pre > code .sh, code .highlight .sh { color: $colorLearning } /* Literal.String.Heredoc */
div.highlight > pre > code .si, code .highlight .si { color: $colorLearning } /* Literal.String.Interpol */
div.highlight > pre > code .sx, code .highlight .sx { color: $colorLearning } /* Literal.String.Other */
div.highlight > pre > code .sr, code .highlight .sr { color: #009926 } /* Literal.String.Regex */
div.highlight > pre > code .s1, code .highlight .s1 { color: $colorLearning } /* Literal.String.Single */
div.highlight > pre > code .ss, code .highlight .ss { color: #990073 } /* Literal.String.Symbol */
div.highlight > pre > code .bp, code .highlight .bp { color: $colorGray } /* Name.Builtin.Pseudo */
div.highlight > pre > code .vc, code .highlight .vc { color: #008080 } /* Name.Variable.Class */
div.highlight > pre > code .vg, code .highlight .vg { color: #008080 } /* Name.Variable.Global */
div.highlight > pre > code .vi, code .highlight .vi { color: #008080 } /* Name.Variable.Instance */
div.highlight > pre > code .il, code .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */

View File

@@ -0,0 +1,15 @@
/**
*
* In this guide
*
**/
.in-this-guide {
margin-top: - $lineHeight * 3;
}
.in-this-guide__title {
@include type--medium(true);
font-family: $fontHighlight;
margin-bottom: $lineHeight;
}

View File

@@ -0,0 +1,79 @@
/**
*
* Next Lessons
*
**/
.next-lessons {
background: $colorGrayDark;
padding: $lineHeight $lineHeight $lineHeight * 2;
margin-top: $lineHeight;
color: #ffffff;
position: relative;
h3 {
i {
@include medium {
display: none;
}
}
}
&::before,
&::after {
color: rgba(255, 255, 255, 0.5);
position: absolute;
display: none;
@include medium {
display: inline-block;
}
}
&::before {
@include medium {
content: attr(data-current-lesson);
font-family: $fontHighlight;
font-size: $fontBase;
font-weight: 400;
line-height: 1;
background: $colorGrayDark;
display: inline-block;
padding: 5px 7px;
right: 127px;
top: 143px;
z-index: 1;
color: rgba(255, 255, 255, 0.5);
}
@include wide {
font-size: $fontMedium;
padding-left: 15px;
padding-right: 15px;
top: 126px;
right: 230px;
}
}
&::after {
@include medium {
content: $icon-lessons;
font-family: $fontIcon;
font-size: 150px;
right: 40px;
top: 185px;
}
@include wide {
font-size: 210px;
right: 120px;
}
}
}

View File

@@ -0,0 +1,32 @@
/**
*
* Page header
*
**/
.page-header {
text-align: center;
.breadcrumbs {
text-align: left;
color: $colorBlue;
a {
color: $colorBlue;
}
}
h3 {
color: $colorGrayDark;
padding-top: $lineHeight * 2;
}
}
.page-header__excerpt {
position: relative;
padding-top: 0;
&:last-child {
padding-bottom: $lineHeight * 3;
}
}

View File

@@ -0,0 +1,44 @@
/**
*
* Quote
*
**/
.quote__content {
position: relative;
font-family: $fontHighlight;
@include type--medium;
padding-top: $lineHeight * 4;
padding-left: $lineHeight;
@include medium {
padding-top: $lineHeight * 2;
padding-left: 0;
}
p {
border-top: 1px solid $colorGrayKeyline;
text-align: right;
font-weight: 500;
margin-top: $lineHeight/2 - 1;
padding-top: $lineHeight/2;
}
&::before {
content: open-quote;
display: block;
position: absolute;
font-family: $fontHighlight;
font-weight: 700;
color: $colorGrayBackground;
top: 90px;
left: $lineHeight;
font-size: 260px;
@include medium {
top: 225px;
left: -210px;
font-size: 540px;
}
}
}

View File

@@ -0,0 +1,41 @@
/**
*
* Related items
*
**/
.related-guides {
margin-top: $lineHeight*3;
padding-bottom: ($lineHeight*2) - 2;
border-top: 2px solid $colorGrayKeyline;
padding-top: ($lineHeight*2) - 2;
}
.related-guides__list {
.list-links {
padding-top: 0;
}
a {
display: block;
}
}
.related-guides__title {
@include type--xlarge;
padding-top: 0;
@include medium {
padding-top: 0;
}
}
.related-guides__main-link {
text-transform: uppercase;
&::before {
content: '#';
display: inline-block;
padding-right: 2px;
}
}

View File

@@ -0,0 +1,19 @@
/**
*
* Related items
*
**/
.related-items {
background-color: $colorGrayDark;
color: #ffffff;
padding-bottom: $lineHeight * 2;
margin-top: $lineHeight * 2;
.list-links {
a {
color: #ffffff;
}
}
}

View File

@@ -0,0 +1,29 @@
/**
*
* Editorial Header
*
**/
.summary-header {
background-color: $colorBlue;
padding-bottom: $lineHeight * 3;
color: #ffffff;
margin-bottom: $lineHeight;
box-shadow: inset 0 2px 0 0 #fff;
.breadcrumbs__link {
color: #ffffff;
}
}
.summary-header__anchor-list {
margin-top: $lineHeight * 2;
}
.summary-header__anchors-item {
& a {
color: #ffffff;
}
}

View File

@@ -0,0 +1,34 @@
/**
*
* Table of contents
*
**/
.toc__title {
@include type--medium;
font-family: $fontHighlight;
padding-bottom: $lineHeight/2;
margin-bottom: ($lineHeight/2) - 1;
border-bottom: 1px solid $colorGrayKeyline;
@include medium {
padding-bottom: $lineHeight/2;
margin-bottom: $lineHeight/2;
}
}
.toc__list {
padding-top: 0;
border-bottom: 1px solid $colorGrayKeyline;
padding-bottom: ($lineHeight/2) - 1;
margin-bottom: $lineHeight/2;
a {
display: block;
}
}
.toc__sublist {
padding-top: 0;
}

View File

@@ -0,0 +1,23 @@
/**
*
* Resources page
*
**/
.page--resources {
& .article-section__icon,
& .articles-count,
& .guides-list__item .secondary-content {
display: none;
}
& .primary-content {
padding-top: $lineHeight;
padding-bottom: $lineHeight*2;
p {
margin-top: 0;
}
}
}

View File

@@ -0,0 +1,82 @@
/**
*
* Styleguide
*
**/
.page--styleguide {
.styleguide__module-title {
margin-bottom: $lineHeight;
}
section {
margin-bottom: $lineHeight*2;
border-bottom: 1px solid #ccc;
padding-bottom: $lineHeight*3 - 1;
}
.styleguide__color-list {
text-align: center;
li {
border-bottom: $lineHeight*2 solid;
margin-bottom: $lineHeight;
position: relative;
}
}
.styleguide__breadcrumb .breadcrumbs {
display: block;
}
.styleguide__lists {
ul,
ol {
margin-bottom: $lineHeight;
}
}
.styleguide__inverted-block {
background: #e8e8e8;
padding: 0 13px;
}
.styleguide__theme-block {
background: $colorLayouts;
padding: 0 13px;
}
}
.demo {
margin-bottom: $lineHeight;
margin-top: $lineHeight;
}
.demo {
[class*="g-"] {
background-color: $colorGrayLight;
position: relative;
margin-bottom: $lineHeight;
min-height: $lineHeight*6;
&::before,
&::after {
@include type--small;
display: block;
margin: 0 10px;
}
&::before {
content: 'HTML classes: ';
font-weight: 700;
}
&::after {
content: attr(class);
word-spacing: 15px;
}
}
}

View File

@@ -0,0 +1,335 @@
/**
*
* Material design color palettes NOT TO BE USED WITH ANGULAR-MATERIAL
* @see http://www.google.com/design/spec/style/color.html
*
**/
/* ========== Blacks ========== */
$colorBlack: #000;
$colorGrayDark: rgba($colorBlack, .87);
$colorGray: rgba($colorBlack, .54);
$colorGrayLight: rgba($colorBlack, .26);
$colorGrayLighter: rgba($colorBlack, .12);
/* ========== Color Palettes ========== */
$paletteRed: #fde0dc #f9bdbb #f69988 #f36c60 #e84e40 #e51c23 #dd191d
#d01716 #c41411 #b0120a #ff7997 #ff5177 #ff2d6f #e00032;
$palettePink: #fce4ec #f8bbd0 #f48fb1 #f06292 #ec407a #e91e63 #d81b60
#c2185b #ad1457 #880e4f #ff80ab #ff4081 #f50057 #c51162;
$palettePurple: #f3e5f5 #e1bee7 #ce93d8 #ba68c8 #ab47bc #9c27b0 #8e24aa
#7b1fa2 #6a1b9a #4a148c #ea80fc #e040fb #d500f9 #aa00ff;
$paletteDeepPurple: #673ab7 #ede7f6 #d1c4e9 #b39ddb #9575cd #7e57c2 #673ab7
#5e35b1 #512da8 #4527a0 #311b92 #b388ff #7c4dff #651fff
#6200ea;
$paletteIndigo: #e8eaf6 #c5cae9 #9fa8da #7986cb #5c6bc0 #3f51b5 #3949ab
#303f9f #283593 #1a237e #8c9eff #536dfe #3d5afe #304ffe;
$paletteBlue: #e7e9fd #d0d9ff #afbfff #91a7ff #738ffe #5677fc #4e6cef
#455ede #3b50ce #2a36b1 #a6baff #6889ff #4d73ff #4d69ff;
$paletteLightBlue: #e1f5fe #b3e5fc #81d4fa #4fc3f7 #29b6f6 #03a9f4 #039be5
#0288d1 #0277bd #01579b #80d8ff #40c4ff #00b0ff #0091ea;
$paletteCyan: #e0f7fa #b2ebf2 #80deea #4dd0e1 #26c6da #00bcd4 #00acc1
#0097a7 #00838f #006064 #84ffff #18ffff #00e5ff #00b8d4;
$paletteTeal: #e0f2f1 #b2dfdb #80cbc4 #4db6ac #26a69a #009688 #00897b
#00796b #00695c #004d40 #a7ffeb #64ffda #1de9b6 #00bfa5;
$paletteGreen: #d0f8ce #a3e9a4 #72d572 #42bd41 #2baf2b #259b24 #0a8f08
#0a7e07 #056f00 #0d5302 #a2f78d #5af158 #14e715 #12c700;
$paletteLightGreen: #f1f8e9 #dcedc8 #c5e1a5 #aed581 #9ccc65 #8bc34a #7cb342
#689f38 #558b2f #33691e #ccff90 #b2ff59 #76ff03 #64dd17;
$paletteLime: #f9fbe7 #f0f4c3 #e6ee9c #dce775 #d4e157 #cddc39 #c0ca33
#afb42b #9e9d24 #827717 #f4ff81 #eeff41 #c6ff00 #aeea00;
$paletteYellow: #fffde7 #fff9c4 #fff59d #fff176 #ffee58 #ffeb3b #fdd835
#fbc02d #f9a825 #f57f17 #ffff8d #ffff00 #ffea00 #ffd600;
$paletteAmber: #fff8e1 #ffecb3 #ffe082 #ffd54f #ffca28 #ffc107 #ffb300
#ffa000 #ff8f00 #ff6f00 #ffe57f #ffd740 #ffc400 #ffab00;
$paletteOrange: #fff3e0 #ffe0b2 #ffcc80 #ffb74d #ffa726 #ff9800 #fb8c00
#f57c00 #ef6c00 #e65100 #ffd180 #ffab40 #ff9100 #ff6d00;
$paletteDeepOrange: #fbe9e7 #ffccbc #ffab91 #ff8a65 #ff7043 #ff5722 #f4511e
#e64a19 #d84315 #bf360c #ff9e80 #ff6e40 #ff3d00 #dd2c00;
$paletteBrown: #efebe9 #d7ccc8 #bcaaa4 #a1887f #8d6e63
#795548 #6d4c41 #5d4037 #4e342e #3e2723;
$paletteBlueGrey: #eceff1 #cfd8dc #b0bec5 #90a4ae #78909c
#607d8b #546e7a #455a64 #37474f #263238;
/* ========== Color definitions ========== */
$colorRed50: nth($paletteRed, 1);
$colorRed100: nth($paletteRed, 2);
$colorRed200: nth($paletteRed, 3);
$colorRed300: nth($paletteRed, 4);
$colorRed400: nth($paletteRed, 5);
$colorRed500: nth($paletteRed, 6);
$colorRed600: nth($paletteRed, 7);
$colorRed700: nth($paletteRed, 8);
$colorRed800: nth($paletteRed, 9);
$colorRed900: nth($paletteRed, 10);
$colorRedA100: nth($paletteRed, 11);
$colorRedA200: nth($paletteRed, 12);
$colorRedA400: nth($paletteRed, 13);
$colorRedA700: nth($paletteRed, 14);
$colorPink50: nth($palettePink, 1);
$colorPink100: nth($palettePink, 2);
$colorPink200: nth($palettePink, 3);
$colorPink300: nth($palettePink, 4);
$colorPink400: nth($palettePink, 5);
$colorPink500: nth($palettePink, 6);
$colorPink600: nth($palettePink, 7);
$colorPink700: nth($palettePink, 8);
$colorPink800: nth($palettePink, 9);
$colorPink900: nth($palettePink, 10);
$colorPinkA100: nth($palettePink, 11);
$colorPinkA200: nth($palettePink, 12);
$colorPinkA400: nth($palettePink, 13);
$colorPinkA700: nth($palettePink, 14);
$colorPurple50: nth($palettePurple, 1);
$colorPurple100: nth($palettePurple, 2);
$colorPurple200: nth($palettePurple, 3);
$colorPurple300: nth($palettePurple, 4);
$colorPurple400: nth($palettePurple, 5);
$colorPurple500: nth($palettePurple, 6);
$colorPurple600: nth($palettePurple, 7);
$colorPurple700: nth($palettePurple, 8);
$colorPurple800: nth($palettePurple, 9);
$colorPurple900: nth($palettePurple, 10);
$colorPurpleA100: nth($palettePurple, 11);
$colorPurpleA200: nth($palettePurple, 12);
$colorPurpleA400: nth($palettePurple, 13);
$colorPurpleA700: nth($palettePurple, 14);
$colorDeepPurple50: nth($paletteDeepPurple, 1);
$colorDeepPurple100: nth($paletteDeepPurple, 2);
$colorDeepPurple200: nth($paletteDeepPurple, 3);
$colorDeepPurple300: nth($paletteDeepPurple, 4);
$colorDeepPurple400: nth($paletteDeepPurple, 5);
$colorDeepPurple500: nth($paletteDeepPurple, 6);
$colorDeepPurple600: nth($paletteDeepPurple, 7);
$colorDeepPurple700: nth($paletteDeepPurple, 8);
$colorDeepPurple800: nth($paletteDeepPurple, 9);
$colorDeepPurple900: nth($paletteDeepPurple, 10);
$colorDeepPurpleA100: nth($paletteDeepPurple, 11);
$colorDeepPurpleA200: nth($paletteDeepPurple, 12);
$colorDeepPurpleA400: nth($paletteDeepPurple, 13);
$colorDeepPurpleA700: nth($paletteDeepPurple, 14);
$colorIndigo50: nth($paletteIndigo, 1);
$colorIndigo100: nth($paletteIndigo, 2);
$colorIndigo200: nth($paletteIndigo, 3);
$colorIndigo300: nth($paletteIndigo, 4);
$colorIndigo400: nth($paletteIndigo, 5);
$colorIndigo500: nth($paletteIndigo, 6);
$colorIndigo600: nth($paletteIndigo, 7);
$colorIndigo700: nth($paletteIndigo, 8);
$colorIndigo800: nth($paletteIndigo, 9);
$colorIndigo900: nth($paletteIndigo, 10);
$colorIndigoA100: nth($paletteIndigo, 11);
$colorIndigoA200: nth($paletteIndigo, 12);
$colorIndigoA400: nth($paletteIndigo, 13);
$colorIndigoA700: nth($paletteIndigo, 14);
$colorBlue50: nth($paletteBlue, 1);
$colorBlue100: nth($paletteBlue, 2);
$colorBlue200: nth($paletteBlue, 3);
$colorBlue300: nth($paletteBlue, 4);
$colorBlue400: nth($paletteBlue, 5);
$colorBlue500: nth($paletteBlue, 6);
$colorBlue600: nth($paletteBlue, 7);
$colorBlue700: nth($paletteBlue, 8);
$colorBlue800: nth($paletteBlue, 9);
$colorBlue900: nth($paletteBlue, 10);
$colorBlueA100: nth($paletteBlue, 11);
$colorBlueA200: nth($paletteBlue, 12);
$colorBlueA400: nth($paletteBlue, 13);
$colorBlueA700: nth($paletteBlue, 14);
$colorLightBlue50: nth($paletteLightBlue, 1);
$colorLightBlue100: nth($paletteLightBlue, 2);
$colorLightBlue200: nth($paletteLightBlue, 3);
$colorLightBlue300: nth($paletteLightBlue, 4);
$colorLightBlue400: nth($paletteLightBlue, 5);
$colorLightBlue500: nth($paletteLightBlue, 6);
$colorLightBlue600: nth($paletteLightBlue, 7);
$colorLightBlue700: nth($paletteLightBlue, 8);
$colorLightBlue800: nth($paletteLightBlue, 9);
$colorLightBlue900: nth($paletteLightBlue, 10);
$colorLightBlueA100: nth($paletteLightBlue, 11);
$colorLightBlueA200: nth($paletteLightBlue, 12);
$colorLightBlueA400: nth($paletteLightBlue, 13);
$colorLightBlueA700: nth($paletteLightBlue, 14);
$colorCyan50: nth($paletteCyan, 1);
$colorCyan100: nth($paletteCyan, 2);
$colorCyan200: nth($paletteCyan, 3);
$colorCyan300: nth($paletteCyan, 4);
$colorCyan400: nth($paletteCyan, 5);
$colorCyan500: nth($paletteCyan, 6);
$colorCyan600: nth($paletteCyan, 7);
$colorCyan700: nth($paletteCyan, 8);
$colorCyan800: nth($paletteCyan, 9);
$colorCyan900: nth($paletteCyan, 10);
$colorCyanA100: nth($paletteCyan, 11);
$colorCyanA200: nth($paletteCyan, 12);
$colorCyanA400: nth($paletteCyan, 13);
$colorCyanA700: nth($paletteCyan, 14);
$colorTeal50: nth($paletteTeal, 1);
$colorTeal100: nth($paletteTeal, 2);
$colorTeal200: nth($paletteTeal, 3);
$colorTeal300: nth($paletteTeal, 4);
$colorTeal400: nth($paletteTeal, 5);
$colorTeal500: nth($paletteTeal, 6);
$colorTeal600: nth($paletteTeal, 7);
$colorTeal700: nth($paletteTeal, 8);
$colorTeal800: nth($paletteTeal, 9);
$colorTeal900: nth($paletteTeal, 10);
$colorTealA100: nth($paletteTeal, 11);
$colorTealA200: nth($paletteTeal, 12);
$colorTealA400: nth($paletteTeal, 13);
$colorTealA700: nth($paletteTeal, 14);
$colorGreen50: nth($paletteGreen, 1);
$colorGreen100: nth($paletteGreen, 2);
$colorGreen200: nth($paletteGreen, 3);
$colorGreen300: nth($paletteGreen, 4);
$colorGreen400: nth($paletteGreen, 5);
$colorGreen500: nth($paletteGreen, 6);
$colorGreen600: nth($paletteGreen, 7);
$colorGreen700: nth($paletteGreen, 8);
$colorGreen800: nth($paletteGreen, 9);
$colorGreen900: nth($paletteGreen, 10);
$colorGreenA100: nth($paletteGreen, 11);
$colorGreenA200: nth($paletteGreen, 12);
$colorGreenA400: nth($paletteGreen, 13);
$colorGreenA700: nth($paletteGreen, 14);
$colorLightGreen50: nth($paletteLightGreen, 1);
$colorLightGreen100: nth($paletteLightGreen, 2);
$colorLightGreen200: nth($paletteLightGreen, 3);
$colorLightGreen300: nth($paletteLightGreen, 4);
$colorLightGreen400: nth($paletteLightGreen, 5);
$colorLightGreen500: nth($paletteLightGreen, 6);
$colorLightGreen600: nth($paletteLightGreen, 7);
$colorLightGreen700: nth($paletteLightGreen, 8);
$colorLightGreen800: nth($paletteLightGreen, 9);
$colorLightGreen900: nth($paletteLightGreen, 10);
$colorLightGreenA100: nth($paletteLightGreen, 11);
$colorLightGreenA200: nth($paletteLightGreen, 12);
$colorLightGreenA400: nth($paletteLightGreen, 13);
$colorLightGreenA700: nth($paletteLightGreen, 14);
$colorLime50: nth($paletteLime, 1);
$colorLime100: nth($paletteLime, 2);
$colorLime200: nth($paletteLime, 3);
$colorLime300: nth($paletteLime, 4);
$colorLime400: nth($paletteLime, 5);
$colorLime500: nth($paletteLime, 6);
$colorLime600: nth($paletteLime, 7);
$colorLime700: nth($paletteLime, 8);
$colorLime800: nth($paletteLime, 9);
$colorLime900: nth($paletteLime, 10);
$colorLimeA100: nth($paletteLime, 11);
$colorLimeA200: nth($paletteLime, 12);
$colorLimeA400: nth($paletteLime, 13);
$colorLimeA700: nth($paletteLime, 14);
$colorYellow50: nth($paletteYellow, 1);
$colorYellow100: nth($paletteYellow, 2);
$colorYellow200: nth($paletteYellow, 3);
$colorYellow300: nth($paletteYellow, 4);
$colorYellow400: nth($paletteYellow, 5);
$colorYellow500: nth($paletteYellow, 6);
$colorYellow600: nth($paletteYellow, 7);
$colorYellow700: nth($paletteYellow, 8);
$colorYellow800: nth($paletteYellow, 9);
$colorYellow900: nth($paletteYellow, 10);
$colorYellowA100: nth($paletteYellow, 11);
$colorYellowA200: nth($paletteYellow, 12);
$colorYellowA400: nth($paletteYellow, 13);
$colorYellowA700: nth($paletteYellow, 14);
$colorAmber50: nth($paletteAmber, 1);
$colorAmber100: nth($paletteAmber, 2);
$colorAmber200: nth($paletteAmber, 3);
$colorAmber300: nth($paletteAmber, 4);
$colorAmber400: nth($paletteAmber, 5);
$colorAmber500: nth($paletteAmber, 6);
$colorAmber600: nth($paletteAmber, 7);
$colorAmber700: nth($paletteAmber, 8);
$colorAmber800: nth($paletteAmber, 9);
$colorAmber900: nth($paletteAmber, 10);
$colorAmberA100: nth($paletteAmber, 11);
$colorAmberA200: nth($paletteAmber, 12);
$colorAmberA400: nth($paletteAmber, 13);
$colorAmberA700: nth($paletteAmber, 14);
$colorOrange50: nth($paletteOrange, 1);
$colorOrange100: nth($paletteOrange, 2);
$colorOrange200: nth($paletteOrange, 3);
$colorOrange300: nth($paletteOrange, 4);
$colorOrange400: nth($paletteOrange, 5);
$colorOrange500: nth($paletteOrange, 6);
$colorOrange600: nth($paletteOrange, 7);
$colorOrange700: nth($paletteOrange, 8);
$colorOrange800: nth($paletteOrange, 9);
$colorOrange900: nth($paletteOrange, 10);
$colorOrangeA100: nth($paletteOrange, 11);
$colorOrangeA200: nth($paletteOrange, 12);
$colorOrangeA400: nth($paletteOrange, 13);
$colorOrangeA700: nth($paletteOrange, 14);
$colorDeepOrange50: nth($paletteDeepOrange, 1);
$colorDeepOrange100: nth($paletteDeepOrange, 2);
$colorDeepOrange200: nth($paletteDeepOrange, 3);
$colorDeepOrange300: nth($paletteDeepOrange, 4);
$colorDeepOrange400: nth($paletteDeepOrange, 5);
$colorDeepOrange500: nth($paletteDeepOrange, 6);
$colorDeepOrange600: nth($paletteDeepOrange, 7);
$colorDeepOrange700: nth($paletteDeepOrange, 8);
$colorDeepOrange800: nth($paletteDeepOrange, 9);
$colorDeepOrange900: nth($paletteDeepOrange, 10);
$colorDeepOrangeA100: nth($paletteDeepOrange, 11);
$colorDeepOrangeA200: nth($paletteDeepOrange, 12);
$colorDeepOrangeA400: nth($paletteDeepOrange, 13);
$colorDeepOrangeA700: nth($paletteDeepOrange, 14);
$colorBrown50: nth($paletteBrown, 1);
$colorBrown100: nth($paletteBrown, 2);
$colorBrown200: nth($paletteBrown, 3);
$colorBrown300: nth($paletteBrown, 4);
$colorBrown400: nth($paletteBrown, 5);
$colorBrown500: nth($paletteBrown, 6);
$colorBrown600: nth($paletteBrown, 7);
$colorBrown700: nth($paletteBrown, 8);
$colorBrown800: nth($paletteBrown, 9);
$colorBrown900: nth($paletteBrown, 10);
$colorBlueGrey50: nth($paletteBlueGrey, 1);
$colorBlueGrey100: nth($paletteBlueGrey, 2);
$colorBlueGrey200: nth($paletteBlueGrey, 3);
$colorBlueGrey300: nth($paletteBlueGrey, 4);
$colorBlueGrey400: nth($paletteBlueGrey, 5);
$colorBlueGrey500: nth($paletteBlueGrey, 6);
$colorBlueGrey600: nth($paletteBlueGrey, 7);
$colorBlueGrey700: nth($paletteBlueGrey, 8);
$colorBlueGrey800: nth($paletteBlueGrey, 9);
$colorBlueGrey900: nth($paletteBlueGrey, 10);

View File

@@ -0,0 +1,417 @@
/**
*
* Utils
*
**/
/*========== VARIABLES ==========*/
// Defining breakpoints
$medium: 620px !default;
$wide: 800px !default;
$huge: 1600px !default;
$mediumContainer: 688px !default;
$wideContainer: 864px !default;
// Defining grid sizes
$mediumColCount: 3 !default;
$mediumColWidth: 30.3% !default;
$mediumGutterWidth: 4.5% !default;
$wideColCount: 4 !default;
$wideColWidth: 22.2% !default;
$wideGutterWidth: 3.7% !default;
// Defining colors
$colorBlue: #3372df !default;
$colorBlueSecondary: lighten($colorBlue, 30%) !default;
$colorGreen: #0f9d58 !default;
$colorGreenSecondary: lighten($colorGreen, 30%) !default;
$colorRed: #cb4437 !default;
$colorRedSecondary: lighten($colorRed, 30%) !default;
$colorYellow: #f4b400 !default;
$colorYellowSecondary: lighten($colorYellow, 20%) !default;
$colorRemember: #09829a !default;
$colorLearning: #da2e75 !default;
$colorGrayBackground: #f0f0f0 !default;
$colorGrayKeyline: #e0e0e0 !default;
$colorGray: #737373 !default;
$colorGrayLight: #eeeeee !default;
$colorGrayDark: #404040 !default;
$colorText: $colorGrayDark !default;
$colorHighlight: $colorBlue !default;
$colorWarning: $colorYellowSecondary !default;
$colorMuted: $colorGray !default;
$colorDanger: $colorRed !default;
$colorLayouts: #297ea9 !default;
$colorLayoutsSecondary: lighten($colorLayouts, 30%) !default;
$colorUser: #2c8566 !default;
$colorUserSecondary: lighten($colorUser, 30%) !default;
$colorMedia: #cf423a !default;
$colorMediaSecondary: lighten($colorMedia, 30%) !default;
$colorPerformance: #7b5294 !default;
$colorPerformanceSecondary: lighten($colorPerformance, 30%) !default;
// Defining font family
$fontDefault: 'Ubuntu', Helvetica, Arial, sans-serif !default;
$fontHighlight: 'Ubuntu', Helvetica, sans-serif !default;
$fontIcon: 'icons' !default;
// Defining font sizes
$fontSmall: 13px !default;
$fontBase: 16px !default;
$fontMedium: 20px !default;
$fontLarge: 26px !default;
$fontXLarge: 42px !default;
$fontXXLarge: 68px !default;
$fontHuge: 110px !default;
// Defining baseline line height
$lineHeight: 26px !default;
// Defining animation easings
$animationEasing: cubic-bezier(0.455, 0.030, 0.515, 0.955) !default;
// Defining sidebar stuff
$sidebarWidth: 280px !default;
/*========== FUNCTIONS ==========*/
@function leading($size, $context: $lineHeight) {
@return $context / $size + em;
}
/*========== MIXINS ==========*/
@mixin media-query($media-query) {
@if $media-query == small {
@media only screen and (max-width: $medium - 1) { @content; }
}
@if $media-query == medium {
@media only screen and (min-width: $medium) { @content; }
}
@if $media-query == medium-only {
@media only screen and (min-width: $medium) and (max-width: $wide - 1) { @content; }
}
@if $media-query == wide {
@media only screen and (min-width: $wide) { @content; }
}
@if $media-query == huge {
@media only screen and (min-width: $huge) { @content; }
}
}
// Just some helpers...
@mixin small-only { @include media-query(small) { @content }; }
@mixin medium { @include media-query(medium) { @content }; }
@mixin medium-only { @include media-query(medium-only) { @content }; }
@mixin wide { @include media-query(wide) { @content }; }
@mixin huge { @include media-query(huge) { @content }; }
// Mixin to constrain elements
@mixin container($isRelative: false) {
box-sizing: content-box;
@if $isRelative {
position: relative;
}
padding-left: 5%;
padding-right: 5%;
margin-left: auto;
margin-right: auto;
@include medium {
padding-left: 4.8%;
padding-right: 4.8%;
max-width: $mediumContainer;
}
@include wide {
padding-left: 4.4%;
padding-right: 4.4%;
max-width: $wideContainer;
}
}
// Mixin to show a baseline grid
// only visible when body has 'debug' class
@mixin baseline-grid() {
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
z-index: 9;
display: none;
background-image: linear-gradient(to bottom, rgba(0,0,0,0.15) 95%,rgba(0,0,0,0.15) 100%);
background-size: 100% 26px;
}
&.debug::after {
display: block;
pointer-events: none;
}
}
// Mixins simply to store CSS rules
@mixin rule--small {
font-size: $fontSmall;
line-height: 2.0000em; /* 26px */
padding-top: 2.0000em;
padding-bottom: 0;
}
@mixin rule--base {
font-size: $fontBase;
line-height: 1.6250em; /* 26px */
padding-top: 1.6250em;
padding-bottom: 0;
}
@mixin rule--medium {
font-size: $fontMedium;
font-weight: 300;
line-height: 1.3000em; /* 26px */
padding-top: 1.3000em;
padding-bottom: 0;
}
@mixin rule--large {
font-family: $fontHighlight;
font-size: $fontLarge;
font-weight: 300;
line-height: 1.0000em; /* 26px */
padding-top: 1.0000em;
padding-bottom: 0;
}
@mixin rule--xlarge {
font-family: $fontHighlight;
font-size: $fontXLarge;
font-weight: 300;
line-height: 1.2381em; /* 52px */
padding-top: 0.6190em;
padding-bottom: 0;
}
@mixin rule--xxlarge {
font-family: $fontHighlight;
font-size: $fontXXLarge;
font-weight: 300;
line-height: 1.1471em; /* 78px */
padding-top: 0.3824em;
padding-bottom: 0;
}
@mixin rule--huge {
font-family: $fontHighlight;
font-size: $fontHuge;
font-weight: 300;
line-height: 1.19em; /* 130px */
padding-top: 0.2364em;
padding-bottom: 0;
}
// Mixins to determine which rule to use at which breakpoint
@mixin type--small($isFromMixin: false) {
@include rule--small;
}
@mixin type--base($isFromMixin: false) {
@include rule--base;
}
@mixin type--medium($isFromMixin: false) {
@if $isFromMixin == false {
@include type--base(true);
@include wide {
@include rule--medium;
}
}
@else {
@include rule--medium;
}
}
@mixin type--large($isFromMixin: false) {
@if $isFromMixin == false {
@include type--medium(true);
@include wide {
@include rule--large;
}
}
@else {
@include rule--large;
}
}
@mixin type--xlarge($isFromMixin: false) {
@if $isFromMixin == false {
@include type--large(true);
@include wide {
@include rule--xlarge;
}
}
@else {
@include rule--xlarge;
}
}
@mixin type--xxlarge($isFromMixin: false) {
@if $isFromMixin == false {
@include type--xlarge(true);
@include wide {
@include rule--xxlarge;
}
}
@else {
@include rule--xxlarge;
}
}
@mixin type--huge($isFromMixin: false) {
@if $isFromMixin == false {
@include type--xxlarge(true);
@include wide {
@include rule--huge;
}
}
@else {
@include rule--huge;
}
}
// LISTS
@mixin bullet-type($bullet, $icon: false) {
&::before {
@if $icon {
font-family: $fontIcon;
@extend .#{$icon}::before;
font-size: $fontSmall;
}
@else {
content: $bullet;
font-family: $fontHighlight;
}
display: block;
font-weight: 400;
position: absolute;
top: 0;
left: 0;
line-height: $lineHeight;
}
}
@mixin numbered-list() {
&::before {
counter-increment: list;
content: '0' counter(list);
color: inherit;
font-weight: 400;
display: inline-block;
position: absolute;
left: 0;
}
}
// Mixin to create links
@mixin style-cta($textColor, $linkIcon: false) {
font-family: $fontHighlight;
color: $textColor;
font-weight: 400;
display: inline-block;
line-height: 1;
&:hover {
color: $colorGrayDark;
}
@if $linkIcon {
text-decoration: none;
&::before {
display: inline-block;
padding-right: 10px;
font-family: $fontIcon;
line-height: ($lineHeight) - 1; // remove 1px from line-height to fix baseline alignment
font-size: $fontSmall;
content: $linkIcon;
}
}
}
// Mixin to create highlight modules
@mixin highlight-symbol($verticalOffset: 0, $horizontalOffset: 45px, $fontSize: 130px) {
position: relative;
&::before {
display: none;
@include medium {
display: block;
position: absolute;
top: 106px;
right: $horizontalOffset;
font-family: $fontIcon;
font-size: $fontSize;
line-height: 1px;
text-align: center;
height: 100%;
width: $mediumColWidth;
color: #ffffff;
}
.highlight-module--left & {
right: auto;
left: $horizontalOffset;
}
@include wide {
top: 134px;
width: $wideColWidth;
font-size: $fontSize + 50;
.highlight-module--large & {
font-size: $fontSize + 300;
}
}
}
}
// Grid CSS rules
@mixin rule--col($mediaQuery) {
@if $mediaQuery == medium {
float: left;
margin-right: $mediumGutterWidth;
}
@if $mediaQuery == wide {
float: left;
margin-right: $wideGutterWidth;
}
}

View File

@@ -0,0 +1,68 @@
/* Welcome to Compass.
* In this file you should write your main styles. (or centralize your imports)
* Import this file using the following HTML or equivalent:
* <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css" /> */
/* line 5, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font: inherit;
font-size: 100%;
vertical-align: baseline;
}
/* line 22, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html {
line-height: 1;
}
/* line 24, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none;
}
/* line 26, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: collapse;
border-spacing: 0;
}
/* line 28, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle;
}
/* line 30, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: none;
}
/* line 103, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none;
}
/* line 32, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
a img {
border: none;
}
/* line 116, ../../.rvm/gems/ruby-2.1.5/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
display: block;
}

View File

@@ -0,0 +1,3 @@
@import "compass/utilities";
@import "compass/typography";
@import "compass/css3";

View File

@@ -0,0 +1,4 @@
md-backdrop.md-opaque.md-THEME_NAME-theme {
background-color: '{{foreground-4-0.5}}';
position: absolute
}

View File

@@ -0,0 +1,31 @@
(function() {
'use strict';
/*
* @ngdoc module
* @name material.components.backdrop
* @description Backdrop
*/
/**
* @ngdoc directive
* @name mdBackdrop
* @module material.components.backdrop
*
* @restrict E
*
* @description
* `<md-backdrop>` is a backdrop element used by other coponents, such as dialog and bottom sheet.
* Apply class `opaque` to make the backdrop use the theme backdrop color.
*
*/
angular.module('material.components.backdrop', [
'material.core'
])
.directive('mdBackdrop', BackdropDirective);
function BackdropDirective($mdTheming) {
return $mdTheming;
}
})();

View File

@@ -0,0 +1,36 @@
md-backdrop {
z-index: $z-index-backdrop;
&.md-dialog-backdrop {
z-index: $z-index-dialog - 1;
}
&.md-bottom-sheet-backdrop {
z-index: $z-index-bottom-sheet - 1;
}
&.md-sidenav-backdrop {
z-index: $z-index-sidenav - 1;
}
background-color: rgba(0,0,0,0);
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
&.ng-enter {
animation: $swift-ease-out-timing-function mdBackdropFadeIn 0.5s both;
}
&.ng-leave {
animation: $swift-ease-in-timing-function mdBackdropFadeOut 0.2s both;
}
}
@keyframes mdBackdropFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes mdBackdropFadeOut {
from { opacity: 1; }
to { opacity: 0; }
}

View File

@@ -0,0 +1,19 @@
md-bottom-sheet.md-THEME_NAME-theme {
background-color: '{{background-50}}';
border-top-color: '{{background-300}}';
&.md-list {
md-item {
color: '{{foreground-1}}';
}
}
.md-subheader {
background-color: '{{background-50}}';
}
.md-subheader {
color: '{{foreground-1}}';
}
}

View File

@@ -0,0 +1,285 @@
(function() {
'use strict';
/**
* @ngdoc module
* @name material.components.bottomSheet
* @description
* BottomSheet
*/
angular.module('material.components.bottomSheet', [
'material.core',
'material.components.backdrop'
])
.directive('mdBottomSheet', MdBottomSheetDirective)
.provider('$mdBottomSheet', MdBottomSheetProvider);
function MdBottomSheetDirective() {
return {
restrict: 'E'
};
}
/**
* @ngdoc service
* @name $mdBottomSheet
* @module material.components.bottomSheet
*
* @description
* `$mdBottomSheet` opens a bottom sheet over the app and provides a simple promise API.
*
* ### Restrictions
*
* - The bottom sheet's template must have an outer `<md-bottom-sheet>` element.
* - Add the `md-grid` class to the bottom sheet for a grid layout.
* - Add the `md-list` class to the bottom sheet for a list layout.
*
* @usage
* <hljs lang="html">
* <div ng-controller="MyController">
* <md-button ng-click="openBottomSheet()">
* Open a Bottom Sheet!
* </md-button>
* </div>
* </hljs>
* <hljs lang="js">
* var app = angular.module('app', ['ngMaterial']);
* app.controller('MyController', function($scope, $mdBottomSheet) {
* $scope.openBottomSheet = function() {
* $mdBottomSheet.show({
* template: '<md-bottom-sheet>Hello!</md-bottom-sheet>'
* });
* };
* });
* </hljs>
*/
/**
* @ngdoc method
* @name $mdBottomSheet#show
*
* @description
* Show a bottom sheet with the specified options.
*
* @param {object} options An options object, with the following properties:
*
* - `templateUrl` - `{string=}`: The url of an html template file that will
* be used as the content of the bottom sheet. Restrictions: the template must
* have an outer `md-bottom-sheet` element.
* - `template` - `{string=}`: Same as templateUrl, except this is an actual
* template string.
* - `controller` - `{string=}`: The controller to associate with this bottom sheet.
* - `locals` - `{string=}`: An object containing key/value pairs. The keys will
* be used as names of values to inject into the controller. For example,
* `locals: {three: 3}` would inject `three` into the controller with the value
* of 3.
* - `targetEvent` - `{DOMClickEvent=}`: A click's event object. When passed in as an option,
* the location of the click will be used as the starting point for the opening animation
* of the the dialog.
* - `resolve` - `{object=}`: Similar to locals, except it takes promises as values
* and the bottom sheet will not open until the promises resolve.
* - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.
* - `parent` - `{element=}`: The element to append the bottom sheet to. Defaults to appending
* to the root element of the application.
*
* @returns {promise} A promise that can be resolved with `$mdBottomSheet.hide()` or
* rejected with `$mdBottomSheet.cancel()`.
*/
/**
* @ngdoc method
* @name $mdBottomSheet#hide
*
* @description
* Hide the existing bottom sheet and resolve the promise returned from
* `$mdBottomSheet.show()`.
*
* @param {*=} response An argument for the resolved promise.
*
*/
/**
* @ngdoc method
* @name $mdBottomSheet#cancel
*
* @description
* Hide the existing bottom sheet and reject the promise returned from
* `$mdBottomSheet.show()`.
*
* @param {*=} response An argument for the rejected promise.
*
*/
function MdBottomSheetProvider($$interimElementProvider) {
return $$interimElementProvider('$mdBottomSheet')
.setDefaults({
options: bottomSheetDefaults
});
/* @ngInject */
function bottomSheetDefaults($animate, $mdConstant, $timeout, $$rAF, $compile, $mdTheming, $mdBottomSheet, $rootElement) {
var backdrop;
return {
themable: true,
targetEvent: null,
onShow: onShow,
onRemove: onRemove,
escapeToClose: true
};
function onShow(scope, element, options) {
// Add a backdrop that will close on click
backdrop = $compile('<md-backdrop class="md-opaque md-bottom-sheet-backdrop">')(scope);
backdrop.on('click touchstart', function() {
$timeout($mdBottomSheet.cancel);
});
$mdTheming.inherit(backdrop, options.parent);
$animate.enter(backdrop, options.parent, null);
var bottomSheet = new BottomSheet(element);
options.bottomSheet = bottomSheet;
// Give up focus on calling item
options.targetEvent && angular.element(options.targetEvent.target).blur();
$mdTheming.inherit(bottomSheet.element, options.parent);
return $animate.enter(bottomSheet.element, options.parent)
.then(function() {
var focusable = angular.element(
element[0].querySelector('button') ||
element[0].querySelector('a') ||
element[0].querySelector('[ng-click]')
);
focusable.focus();
if (options.escapeToClose) {
options.rootElementKeyupCallback = function(e) {
if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
$timeout($mdBottomSheet.cancel);
}
};
$rootElement.on('keyup', options.rootElementKeyupCallback);
}
});
}
function onRemove(scope, element, options) {
var bottomSheet = options.bottomSheet;
$animate.leave(backdrop);
return $animate.leave(bottomSheet.element).then(function() {
bottomSheet.cleanup();
// Restore focus
options.targetEvent && angular.element(options.targetEvent.target).focus();
});
}
/**
* BottomSheet class to apply bottom-sheet behavior to an element
*/
function BottomSheet(element) {
var MAX_OFFSET = 80; // amount past the bottom of the element that we can drag down, this is same as in _bottomSheet.scss
var WIGGLE_AMOUNT = 20; // point where it starts to get "harder" to drag
var CLOSING_VELOCITY = 10; // how fast we need to flick down to close the sheet
var startY, lastY, velocity, transitionDelay, startTarget;
// coercion incase $mdCompiler returns multiple elements
element = element.eq(0);
element.on('touchstart', onTouchStart)
.on('touchmove', onTouchMove)
.on('touchend', onTouchEnd);
return {
element: element,
cleanup: function cleanup() {
element.off('touchstart', onTouchStart)
.off('touchmove', onTouchMove)
.off('touchend', onTouchEnd);
}
};
function onTouchStart(e) {
e.preventDefault();
startTarget = e.target;
startY = getY(e);
// Disable transitions on transform so that it feels fast
transitionDelay = element.css($mdConstant.CSS.TRANSITION_DURATION);
element.css($mdConstant.CSS.TRANSITION_DURATION, '0s');
}
function onTouchEnd(e) {
// Re-enable the transitions on transforms
element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDelay);
var currentY = getY(e);
// If we didn't scroll much, and we didn't change targets, assume its a click
if ( Math.abs(currentY - startY) < 5 && e.target == startTarget) {
angular.element(e.target).triggerHandler('click');
} else {
// If they went fast enough, trigger a close.
if (velocity > CLOSING_VELOCITY) {
$timeout($mdBottomSheet.cancel);
// Otherwise, untransform so that we go back to our normal position
} else {
setTransformY(undefined);
}
}
}
function onTouchMove(e) {
var currentY = getY(e);
var delta = currentY - startY;
velocity = currentY - lastY;
lastY = currentY;
// Do some conversion on delta to get a friction-like effect
delta = adjustedDelta(delta);
setTransformY(delta + MAX_OFFSET);
}
/**
* Helper function to find the Y aspect of various touch events.
**/
function getY(e) {
var touch = e.touches && e.touches.length ? e.touches[0] : e.changedTouches[0];
return touch.clientY;
}
/**
* Transform the element along the y-axis
**/
function setTransformY(amt) {
if (amt === null || amt === undefined) {
element.css($mdConstant.CSS.TRANSFORM, '');
} else {
element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0, ' + amt + 'px, 0)');
}
}
// Returns a new value for delta that will never exceed MAX_OFFSET_AMOUNT
// Will get harder to exceed it as you get closer to it
function adjustedDelta(delta) {
if ( delta < 0 && delta < -MAX_OFFSET + WIGGLE_AMOUNT) {
delta = -delta;
var base = MAX_OFFSET - WIGGLE_AMOUNT;
delta = Math.max(-MAX_OFFSET, -Math.min(MAX_OFFSET - 5, base + ( WIGGLE_AMOUNT * (delta - base)) / MAX_OFFSET) - delta / 50);
}
return delta;
}
}
}
}
})();

View File

@@ -0,0 +1,175 @@
$bottom-sheet-horizontal-padding: 2 * $baseline-grid !default;
$bottom-sheet-vertical-padding: 1 * $baseline-grid !default;
$bottom-sheet-icon-after-margin: 4 * $baseline-grid !default;
$bottom-sheet-list-item-height: 6 * $baseline-grid !default;
$bottom-sheet-hidden-bottom-padding: 80px !default;
$bottom-sheet-header-height: 7 * $baseline-grid !default;
$bottom-sheet-grid-font-weight: 300 !default;
md-bottom-sheet {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: $bottom-sheet-vertical-padding $bottom-sheet-horizontal-padding $bottom-sheet-vertical-padding + $bottom-sheet-hidden-bottom-padding $bottom-sheet-horizontal-padding;
z-index: $z-index-bottom-sheet;
border-top: 1px solid;
transform: translate3d(0, $bottom-sheet-hidden-bottom-padding, 0);
transition: $swift-ease-out;
transition-property: transform;
&.md-has-header {
padding-top: 0;
}
&.ng-enter {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
&.ng-enter-active {
opacity: 1;
display: block;
transform: translate3d(0, $bottom-sheet-hidden-bottom-padding, 0) !important;
}
&.ng-leave-active {
transform: translate3d(0, 100%, 0) !important;
transition: $swift-ease-in;
}
.md-subheader {
background-color: transparent;
font-family: $font-family;
line-height: $bottom-sheet-header-height;
padding: 0;
white-space: nowrap;
}
md-inline-icon {
display: inline-block;
height: 24px;
width: 24px;
fill: #444;
}
md-item {
display: flex;
outline: none;
&:hover {
cursor: pointer;
}
}
&.md-list {
md-item {
align-items: center;
height: $bottom-sheet-list-item-height;
div.md-icon-container {
display: inline-block;
height: 3 * $baseline-grid;
margin-right: $bottom-sheet-icon-after-margin;
}
}
}
&.md-grid {
padding-left: 3 * $baseline-grid;
padding-right: 3 * $baseline-grid;
padding-top: 0;
md-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
transition: all 0.5s;
align-items: center;
}
md-item {
flex-direction: column;
align-items: center;
transition: all 0.5s;
height: 12 * $baseline-grid;
margin-top: $baseline-grid;
margin-bottom: $baseline-grid;
/* Mixin for how many grid items to show per row */
@mixin grid-items-per-row($num, $alignEdges: false) {
$width: 100% / $num;
flex: 1 1 $width;
max-width: $width;
@if $alignEdges {
&:nth-of-type(#{$num}n + 1) {
align-items: flex-start;
}
&:nth-of-type(#{$num}n) {
align-items: flex-end;
}
}
}
@media screen and (max-width: $layout-breakpoint-sm) {
@include grid-items-per-row(3, true);
}
@media screen and (min-width: $layout-breakpoint-sm) and (max-width: $layout-breakpoint-md) {
@include grid-items-per-row(4);
}
@media screen and (min-width: $layout-breakpoint-md) and (max-width: $layout-breakpoint-lg) {
@include grid-items-per-row(6);
}
@media screen and (min-width: $layout-breakpoint-lg) {
@include grid-items-per-row(7);
}
.md-item-content {
display: flex;
flex-direction: column;
align-items: center;
width: 6 * $baseline-grid;
padding-bottom: 2 * $baseline-grid;
}
.md-grid-item-content {
display: flex;
flex-direction: column;
align-items: center;
width: 10 * $baseline-grid;
}
.md-icon-container {
display: inline-block;
box-sizing: border-box;
height: 6 * $baseline-grid;
width: 6 * $baseline-grid;
margin: 0 0;
}
p.md-grid-text {
font-weight: $bottom-sheet-grid-font-weight;
line-height: 2 * $baseline-grid;
font-size: 2 * $baseline-grid - 3;
margin: 0;
white-space: nowrap;
width: 8 * $baseline-grid;
text-align: center;
padding-top: 1 * $baseline-grid;
}
}
}
}

View File

@@ -0,0 +1,44 @@
describe('$mdBottomSheet service', function() {
beforeEach(module('material.components.bottomSheet', 'ngAnimateMock'));
describe('#build()', function() {
it('should escapeToClose == true', inject(function($mdBottomSheet, $rootScope, $rootElement, $timeout, $animate, $mdConstant) {
var parent = angular.element('<div>');
$mdBottomSheet.show({
template: '<md-bottom-sheet>',
parent: parent,
escapeToClose: true
});
$rootScope.$apply();
$animate.triggerCallbacks();
expect(parent.find('md-bottom-sheet').length).toBe(1);
$rootElement.triggerHandler({type: 'keyup',
keyCode: $mdConstant.KEY_CODE.ESCAPE
});
$timeout.flush();
expect(parent.find('md-bottom-sheet').length).toBe(0);
}));
it('should escapeToClose == false', inject(function($mdBottomSheet, $rootScope, $rootElement, $timeout, $animate, $mdConstant) {
var parent = angular.element('<div>');
$mdBottomSheet.show({
template: '<md-bottom-sheet>',
parent: parent,
escapeToClose: false
});
$rootScope.$apply();
$animate.triggerCallbacks();
expect(parent.find('md-bottom-sheet').length).toBe(1);
$rootElement.triggerHandler({ type: 'keyup', keyCode: $mdConstant.KEY_CODE.ESCAPE });
expect(parent.find('md-bottom-sheet').length).toBe(1);
}));
});
});

View File

@@ -0,0 +1,14 @@
<md-bottom-sheet class="md-grid">
<md-list>
<md-item ng-repeat="item in items">
<md-button class="md-grid-item-content" aria-label="{{item.name}}" ng-click="listItemClick($index)">
<div class="md-icon-container">
<md-inline-grid-icon icon="{{item.icon}}"></md-inline-grid-icon>
</div>
<p class="md-grid-text"> {{ item.name }} </p>
</md-button>
</md-item>
</md-list>
</md-bottom-sheet>

View File

@@ -0,0 +1,12 @@
<md-bottom-sheet class="md-list md-has-header">
<md-subheader>Comment Actions</md-subheader>
<md-list>
<md-item ng-repeat="item in items">
<md-button aria-label="{{item.name}}" ng-click="listItemClick($index)">
<!-- Using custom inline icon until md-icon is ready. DONT USE ME! -->
<md-inline-list-icon icon="{{item.icon}}"></md-inline-list-icon>
<span class="md-inline-list-icon-label">{{ item.name }}</span>
</md-button>
</md-item>
</md-list>
</md-bottom-sheet>

View File

@@ -0,0 +1,19 @@
<div ng-controller="BottomSheetExample">
<p style="padding-left: 20px;">
Bottom sheet can be dismissed with the service or a swipe down.
</p>
<div class="bottom-sheet-demo inset" layout="column" layout-sm="row" layout-align="center">
<md-button class="md-primary" ng-click="showListBottomSheet($event)">
Show as List
</md-button>
<div style="width:50px;"></div>
<md-button class="md-primary" ng-click="showGridBottomSheet($event)">
Show as Grid
</md-button>
</div>
<br/>
<b layout="row" layout-align="center center" layout-margin>
{{alert}}
</b>
</div>

View File

@@ -0,0 +1,58 @@
angular.module('bottomSheetDemo1', ['ngMaterial'])
.controller('BottomSheetExample', function($scope, $timeout, $mdBottomSheet) {
$scope.alert = '';
$scope.showListBottomSheet = function($event) {
$scope.alert = '';
$mdBottomSheet.show({
templateUrl: 'bottom-sheet-list-template.html',
controller: 'ListBottomSheetCtrl',
targetEvent: $event
}).then(function(clickedItem) {
$scope.alert = clickedItem.name + ' clicked!';
});
};
$scope.showGridBottomSheet = function($event) {
$scope.alert = '';
$mdBottomSheet.show({
templateUrl: 'bottom-sheet-grid-template.html',
controller: 'GridBottomSheetCtrl',
targetEvent: $event
}).then(function(clickedItem) {
$scope.alert = clickedItem.name + ' clicked!';
});
};
})
.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);
};
})
.controller('GridBottomSheetCtrl', function($scope, $mdBottomSheet) {
$scope.items = [
{ name: 'Hangout', icon: 'hangout' },
{ name: 'Mail', icon: 'mail' },
{ name: 'Message', icon: 'message' },
{ name: 'Copy', icon: 'copy' },
{ name: 'Facebook', icon: 'facebook' },
{ name: 'Twitter', icon: 'twitter' },
];
$scope.listItemClick = function($index) {
var clickedItem = $scope.items[$index];
$mdBottomSheet.hide(clickedItem);
};
});

View File

@@ -0,0 +1,64 @@
/* Temporary fix until md-icon is working, DO NOT USE! */
md-inline-list-icon {
display: inline-block;
height: 24px;
width: 24px;
}
.md-inline-list-icon-label {
padding-left: 20px;
display: inline-block;
margin-top: -5px;
height: 24px;
vertical-align: middle;
}
md-inline-list-icon[icon=share] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMjRweCINCgkgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItNjE4IiB5PSItMTA4MCIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbCI+DQo8L2c+DQo8ZyBpZD0iSWNvbiI+DQoJPGc+DQoJCTxwYXRoIGZpbGw9IiM3ZDdkN2QiIGQ9Ik0yMSwxMWwtNy03djRDNyw5LDQsMTQsMywxOWMyLjUtMy41LDYtNS4xLDExLTUuMVYxOEwyMSwxMXoiLz4NCgkJPHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ii8+DQoJPC9nPg0KPC9nPg0KPGcgaWQ9IkdyaWQiIGRpc3BsYXk9Im5vbmUiPg0KCTxnIGRpc3BsYXk9ImlubGluZSI+DQoJPC9nPg0KPC9nPg0KPC9zdmc+');
}
md-inline-list-icon[icon=upload] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMjRweCINCgkgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItNjE4IiB5PSItMjIzMiIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbCI+DQo8L2c+DQo8ZyBpZD0iSWNvbiI+DQoJPGc+DQoJCTxyZWN0IGZpbGw9Im5vbmUiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIvPg0KCQk8cGF0aCBmaWxsPSIjN2Q3ZDdkIiBkPSJNMTkuNCwxMGMtMC43LTMuNC0zLjctNi03LjQtNkM5LjEsNCw2LjYsNS42LDUuNCw4QzIuMyw4LjQsMCwxMC45LDAsMTRjMCwzLjMsMi43LDYsNiw2aDEzYzIuOCwwLDUtMi4yLDUtNQ0KCQkJQzI0LDEyLjQsMjEuOSwxMC4yLDE5LjQsMTB6IE0xNCwxM3Y0aC00di00SDdsNS01bDUsNUgxNHoiLz4NCgk8L2c+DQo8L2c+DQo8ZyBpZD0iR3JpZCIgZGlzcGxheT0ibm9uZSI+DQoJPGcgZGlzcGxheT0iaW5saW5lIj4NCgk8L2c+DQo8L2c+DQo8L3N2Zz4=');
}
md-inline-list-icon[icon=copy] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMjRweCINCgkgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItNjE4IiB5PSItMTcyMCIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbHMiPg0KPC9nPg0KPGcgaWQ9Ikljb24iPg0KCTxnPg0KCQk8cmVjdCBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz4NCgkJPHBhdGggZmlsbD0iIzdkN2Q3ZCIgZD0iTTE2LDFINEMyLjksMSwyLDEuOSwyLDN2MTRoMlYzaDEyVjF6IE0xOSw1SDhDNi45LDUsNiw1LjksNiw3djE0YzAsMS4xLDAuOSwyLDIsMmgxMWMxLjEsMCwyLTAuOSwyLTJWNw0KCQkJQzIxLDUuOSwyMC4xLDUsMTksNXogTTE5LDIxSDhWN2gxMVYyMXoiLz4NCgk8L2c+DQo8L2c+DQo8ZyBpZD0iR3JpZCIgZGlzcGxheT0ibm9uZSI+DQoJPGcgZGlzcGxheT0iaW5saW5lIj4NCgk8L2c+DQo8L2c+DQo8L3N2Zz4=');
}
md-inline-list-icon[icon=print] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMjRweCINCgkgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItNjE4IiB5PSItMTQ2NCIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbCI+DQo8L2c+DQo8ZyBpZD0iSWNvbiI+DQoJPGc+DQoJCTxnPg0KCQkJPHBhdGggZD0iTTE5LDhINWMtMS43LDAtMywxLjMtMywzdjZoNHY0aDEydi00aDR2LTZDMjIsOS4zLDIwLjcsOCwxOSw4eiBNMTYsMTlIOHYtNWg4VjE5eiBNMTksMTJjLTAuNiwwLTEtMC40LTEtMXMwLjQtMSwxLTENCgkJCQljMC42LDAsMSwwLjQsMSwxUzE5LjYsMTIsMTksMTJ6IE0xOCwzSDZ2NGgxMlYzeiIgZmlsbD0iIzdkN2Q3ZCIvPg0KCQk8L2c+DQoJCTxyZWN0IGZpbGw9Im5vbmUiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJHcmlkIiBkaXNwbGF5PSJub25lIj4NCgk8ZyBkaXNwbGF5PSJpbmxpbmUiPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg==');
}
.md-icon-container md-inline-grid-icon {
display: inline-block;
height: 48px;
width: 48px;
}
md-inline-grid-icon[icon=hangout] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDhweCINCgkgaGVpZ2h0PSI0OHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ4IDQ4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItODM4IiB5PSItMjIzMiIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbHMiPg0KPC9nPg0KPGcgaWQ9Ikljb24iPg0KCTxnPg0KCQk8cGF0aCBmaWxsPSIjMTU5RjVDIiBkPSJNMjMsNEMxMy42LDQsNiwxMS42LDYsMjFzNy42LDE3LDE3LDE3aDF2N2M5LjctNC43LDE2LTE1LDE2LTI0QzQwLDExLjYsMzIuNCw0LDIzLDR6IE0yMiwyMmwtMiw0aC0zbDItNGgtM3YtNmg2VjIyeg0KCQkJIE0zMCwyMmwtMiw0aC0zbDItNGgtM3YtNmg2VjIyeiIvPg0KCQk8cmVjdCB4PSIwIiBmaWxsPSJub25lIiB3aWR0aD0iNDgiIGhlaWdodD0iNDgiLz4NCgk8L2c+DQo8L2c+DQo8ZyBpZD0iR3JpZCIgZGlzcGxheT0ibm9uZSI+DQoJPGcgZGlzcGxheT0iaW5saW5lIj4NCgkJPGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDBFNUZGIiBzdHJva2Utd2lkdGg9IjAuMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iNDIiIHkxPSItMjIzMiIgeDI9IjQyIiB5Mj0iMTMyMCIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K');
}
md-inline-grid-icon[icon=mail] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDhweCINCgkgaGVpZ2h0PSI0OHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ4IDQ4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItODM4IiB5PSItMjg3MiIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbHMiPg0KPC9nPg0KPGcgaWQ9Ikljb24iPg0KCTxnPg0KCQk8cGF0aCBmaWxsPSIjN2Q3ZDdkIiBkPSJNNDAsOEg4Yy0yLjIsMC00LDEuOC00LDRsMCwyNGMwLDIuMiwxLjgsNCw0LDRoMzJjMi4yLDAsNC0xLjgsNC00VjEyQzQ0LDkuOCw0Mi4yLDgsNDAsOHogTTQwLDE2TDI0LDI2TDgsMTZ2LTRsMTYsMTANCgkJCWwxNi0xMFYxNnoiLz4NCgkJPHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ii8+DQoJPC9nPg0KPC9nPg0KPGcgaWQ9IkdyaWQiIGRpc3BsYXk9Im5vbmUiPg0KCTxnIGRpc3BsYXk9ImlubGluZSI+DQoJCTxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwRTVGRiIgc3Ryb2tlLXdpZHRoPSIwLjEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjQyIiB5MT0iLTI4NzIiIHgyPSI0MiIgeTI9IjY4MCIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K');
}
md-inline-grid-icon[icon=message] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDhweCINCgkgaGVpZ2h0PSI0OHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ4IDQ4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItODM4IiB5PSItMjc0NCIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbHMiPg0KPC9nPg0KPGcgaWQ9Ikljb24iPg0KCTxnPg0KCQk8cGF0aCBmaWxsPSIjN2Q3ZDdkIiBkPSJNNDAsNEg4QzUuOCw0LDQsNS44LDQsOGwwLDM2bDgtOGgyOGMyLjIsMCw0LTEuOCw0LTRWOEM0NCw1LjgsNDIuMiw0LDQwLDR6IE0zNiwyOEgxMnYtNGgyNFYyOHogTTM2LDIySDEydi00aDI0VjIyeg0KCQkJIE0zNiwxNkgxMnYtNGgyNFYxNnoiLz4NCgkJPHJlY3QgeD0iMCIgZmlsbD0ibm9uZSIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ii8+DQoJPC9nPg0KPC9nPg0KPGcgaWQ9IkdyaWQiIGRpc3BsYXk9Im5vbmUiPg0KCTxnIGRpc3BsYXk9ImlubGluZSI+DQoJCTxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwRTVGRiIgc3Ryb2tlLXdpZHRoPSIwLjEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjQyIiB5MT0iLTI3NDQiIHgyPSI0MiIgeTI9IjgwOCIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K');
}
md-inline-grid-icon[icon=copy] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDhweCINCgkgaGVpZ2h0PSI0OHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ4IDQ4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItODM4IiB5PSItMTcyMCIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbHMiPg0KPC9nPg0KPGcgaWQ9Ikljb24iPg0KCTxnPg0KCQk8cmVjdCBmaWxsPSJub25lIiB3aWR0aD0iNDgiIGhlaWdodD0iNDgiLz4NCgkJPHBhdGggZmlsbD0iIzdkN2Q3ZCIgZD0iTTMyLDJIOEM1LjgsMiw0LDMuOCw0LDZ2MjhoNFY2aDI0VjJ6IE0zOCwxMEgxNmMtMi4yLDAtNCwxLjgtNCw0djI4YzAsMi4yLDEuOCw0LDQsNGgyMmMyLjIsMCw0LTEuOCw0LTRWMTQNCgkJCUM0MiwxMS44LDQwLjIsMTAsMzgsMTB6IE0zOCw0MkgxNlYxNGgyMlY0MnoiLz4NCgk8L2c+DQo8L2c+DQo8ZyBpZD0iR3JpZCIgZGlzcGxheT0ibm9uZSI+DQoJPGcgZGlzcGxheT0iaW5saW5lIj4NCgkJPGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDBFNUZGIiBzdHJva2Utd2lkdGg9IjAuMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iNDIiIHkxPSItMTcyMCIgeDI9IjQyIiB5Mj0iMTgzMiIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K');
}
md-inline-grid-icon[icon=facebook] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDhweCINCgkgaGVpZ2h0PSI0OHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ4IDQ4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItODM4IiB5PSItMzI1NiIgZmlsbD0ibm9uZSIgd2lkdGg9IjE0MDAiIGhlaWdodD0iMzYwMCIvPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJMYWJlbCI+DQo8L2c+DQo8ZyBpZD0iSWNvbiI+DQoJPGc+DQoJCTxnPg0KCQkJPHBhdGggZmlsbD0iIzdkN2Q3ZCIgZD0iTTQwLDRIOEM1LjgsNCw0LDUuOCw0LDhsMCwzMmMwLDIuMiwxLjgsNCw0LDRoMzJjMi4yLDAsNC0xLjgsNC00VjhDNDQsNS44LDQyLjIsNCw0MCw0eiBNMzgsOHY2aC00Yy0xLjEsMC0yLDAuOS0yLDJ2NA0KCQkJCWg2djZoLTZ2MTRoLTZWMjZoLTR2LTZoNHYtNWMwLTMuOSwzLjEtNyw3LTdIMzh6Ii8+DQoJCTwvZz4NCgkJPGc+DQoJCQk8cmVjdCBmaWxsPSJub25lIiB3aWR0aD0iNDgiIGhlaWdodD0iNDgiLz4NCgkJPC9nPg0KCTwvZz4NCjwvZz4NCjxnIGlkPSJHcmlkIiBkaXNwbGF5PSJub25lIj4NCgk8ZyBkaXNwbGF5PSJpbmxpbmUiPg0KCQk8bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiMwMEU1RkYiIHN0cm9rZS13aWR0aD0iMC4xIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHgxPSI0MiIgeTE9Ii0zMjU2IiB4Mj0iNDIiIHkyPSIyOTYiLz4NCgk8L2c+DQo8L2c+DQo8L3N2Zz4NCg==');
}
md-inline-grid-icon[icon=twitter] {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDhweCINCgkgaGVpZ2h0PSI0OHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ4IDQ4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJIZWFkZXIiPg0KCTxnPg0KCQk8cmVjdCB4PSItODM4IiB5PSItOTUyIiBmaWxsPSJub25lIiB3aWR0aD0iMTQwMCIgaGVpZ2h0PSIzNjAwIi8+DQoJPC9nPg0KPC9nPg0KPGcgaWQ9IkxhYmVsIj4NCjwvZz4NCjxnIGlkPSJJY29uIj4NCgk8Zz4NCgkJPGc+DQoJCQk8cGF0aCBmaWxsPSIjN2Q3ZDdkIiBkPSJNNDAsNEg4QzUuOCw0LDQsNS44LDQsOGwwLDMyYzAsMi4yLDEuOCw0LDQsNGgzMmMyLjIsMCw0LTEuOCw0LTRWOEM0NCw1LjgsNDIuMiw0LDQwLDR6IE0zNS40LDE4LjcNCgkJCQljLTAuMSw5LjItNiwxNS42LTE0LjgsMTZjLTMuNiwwLjItNi4zLTEtOC42LTIuNWMyLjcsMC40LDYtMC42LDcuOC0yLjJjLTIuNi0wLjMtNC4yLTEuNi00LjktMy44YzAuOCwwLjEsMS42LDAuMSwyLjMtMC4xDQoJCQkJYy0yLjQtMC44LTQuMS0yLjMtNC4yLTUuM2MwLjcsMC4zLDEuNCwwLjYsMi4zLDAuNmMtMS44LTEtMy4xLTQuNy0xLjYtNy4yYzIuNiwyLjksNS44LDUuMywxMSw1LjZjLTEuMy01LjYsNi4xLTguNiw5LjItNC45DQoJCQkJYzEuMy0wLjMsMi40LTAuOCwzLjQtMS4zYy0wLjQsMS4zLTEuMiwyLjItMi4yLDIuOWMxLjEtMC4xLDIuMS0wLjQsMi45LTAuOEMzNy41LDE2LjksMzYuNCwxNy45LDM1LjQsMTguN3oiLz4NCgkJPC9nPg0KCQk8Zz4NCgkJCTxyZWN0IGZpbGw9Im5vbmUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIvPg0KCQk8L2c+DQoJPC9nPg0KPC9nPg0KPGcgaWQ9IkdyaWQiIGRpc3BsYXk9Im5vbmUiPg0KCTxnIGRpc3BsYXk9ImlubGluZSI+DQoJCTxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwRTVGRiIgc3Ryb2tlLXdpZHRoPSIwLjEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjQyIiB5MT0iLTk1MiIgeDI9IjQyIiB5Mj0iMjYwMCIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K');
}

View File

@@ -0,0 +1,84 @@
$button-border-radius: 3px !default;
$button-fab-border-radius: 50% !default;
.md-button.md-THEME_NAME-theme {
border-radius: $button-border-radius;
&:not([disabled]) {
&:hover,
&:focus {
background-color: '{{background-500-0.2}}';
}
}
&.md-primary {
color: '{{primary-color}}';
&.md-raised,
&.md-fab {
color: '{{primary-contrast}}';
background-color: '{{primary-color}}';
&:not([disabled]) {
&:hover,
&:focus {
background-color: '{{primary-600}}';
}
}
}
}
&.md-fab {
border-radius: $button-fab-border-radius;
}
&.md-raised,
&.md-fab {
color: '{{background-contrast}}';
background-color: '{{background-500-0.185}}';
&:not([disabled]) {
&:hover,
&:focus {
background-color: '{{background-500-0.3}}';
}
}
}
&.md-warn {
color: '{{warn-color}}';
&.md-raised,
&.md-fab {
color: '{{warn-contrast}}';
background-color: '{{warn-color}}';
&:not([disabled]) {
&:hover,
&:focus {
background-color: '{{warn-700}}';
}
}
}
}
&.md-accent {
color: '{{accent-color}}';
&.md-raised,
&.md-fab {
color: '{{accent-contrast}}';
background-color: '{{accent-color}}';
&:not([disabled]) {
&:hover,
&:focus {
background-color: '{{accent-700}}';
}
}
}
}
&[disabled],
&.md-raised[disabled],
&.md-fab[disabled] {
color: '{{foreground-3}}';
background-color: transparent;
cursor: not-allowed;
}
}

View File

@@ -0,0 +1,87 @@
(function() {
'use strict';
/**
* @ngdoc module
* @name material.components.button
* @description
*
* Button
*/
angular.module('material.components.button', [
'material.core'
])
.directive('mdButton', MdButtonDirective);
/**
* @ngdoc directive
* @name mdButton
* @module material.components.button
*
* @restrict E
*
* @description
* `<md-button>` is a button directive with optional ink ripples (default enabled).
*
* If you supply a `href` or `ng-href` attribute, it will become an `<a>` element. Otherwise, it will
* become a `<button>` element.
*
* @param {boolean=} md-no-ink If present, disable ripple ink effects.
* @param {expression=} ng-disabled En/Disable based on the expression
* @param {string=} aria-label Adds alternative text to button for accessibility, useful for icon buttons.
* If no default text is found, a warning will be logged.
*
* @usage
* <hljs lang="html">
* <md-button>
* Button
* </md-button>
* <md-button href="http://google.com" class="md-button-colored">
* I'm a link
* </md-button>
* <md-button ng-disabled="true" class="md-colored">
* I'm a disabled button
* </md-button>
* </hljs>
*/
function MdButtonDirective($mdInkRipple, $mdTheming, $mdAria) {
return {
restrict: 'E',
replace: true,
transclude: true,
template: getTemplate,
link: postLink
};
function isAnchor(attr) {
return angular.isDefined(attr.href) || angular.isDefined(attr.ngHref);
}
function getTemplate(element, attr) {
return isAnchor(attr) ?
'<a class="md-button" ng-transclude></a>' :
'<button class="md-button" ng-transclude></button>';
}
function postLink(scope, element, attr) {
var node = element[0];
$mdTheming(element);
$mdInkRipple.attachButtonBehavior(scope, element);
var elementHasText = node.textContent.trim();
if (!elementHasText) {
$mdAria.expect(element, 'aria-label');
}
// For anchor elements, we have to set tabindex manually when the
// element is disabled
if (isAnchor(attr) && angular.isDefined(attr.ngDisabled) ) {
scope.$watch(attr.ngDisabled, function(isDisabled) {
element.attr('tabindex', isDisabled ? -1 : 0);
});
}
}
}
})();

View File

@@ -0,0 +1,173 @@
$button-line-height: 25px !default;
$button-padding: 2px 6px 3px !default;
// Fab buttons
$button-fab-width: 56px !default;
$button-fab-height: 56px !default;
$button-fab-padding: 16px !default;
$button-fab-toast-offset: $button-fab-height * 0.75;
/**
* Position a FAB button.
*/
@mixin fab-position($spot, $top: auto, $right: auto, $bottom: auto, $left: auto) {
&.md-fab-#{$spot} {
top: $top;
right: $right;
bottom: $bottom;
left: $left;
position: absolute;
}
}
.md-button {
user-select: none;
position: relative; //for child absolute-positioned <canvas>
outline: none;
border: 0;
padding: 6px;
margin: 0;
background: transparent;
white-space: nowrap;
text-align: center;
// Always uppercase buttons
text-transform: uppercase;
font-weight: 500;
font-style: inherit;
font-variant: inherit;
font-size: inherit;
font-family: inherit;
line-height: inherit;
text-decoration: none;
cursor: pointer;
overflow: hidden; // for ink containment
transition: box-shadow $swift-ease-out-duration $swift-ease-out-timing-function,
background-color $swift-ease-out-duration $swift-ease-out-timing-function,
transform $swift-ease-out-duration $swift-ease-out-timing-function;
&.ng-hide {
transition: none;
}
;
&.md-cornered {
border-radius: 0;
}
&.md-icon {
padding: 0;
background: none;
}
&.md-raised {
transform: translate3d(0, 0, 0);
&:not([disabled]) {
@extend .md-shadow-bottom-z-1;
}
}
&.md-fab {
@include fab-position(bottom-right, auto, ($button-fab-width - $button-fab-padding)/2, ($button-fab-height - $button-fab-padding)/2, auto);
@include fab-position(bottom-left, auto, auto, ($button-fab-height - $button-fab-padding)/2, ($button-fab-width - $button-fab-padding)/2);
@include fab-position(top-right, ($button-fab-height - $button-fab-padding)/2, ($button-fab-width - $button-fab-padding)/2, auto, auto);
@include fab-position(top-left, ($button-fab-height - $button-fab-padding)/2, auto, auto, ($button-fab-width - $button-fab-padding)/2);
z-index: $z-index-fab;
width: $button-fab-width;
height: $button-fab-height;
border-radius: 50%;
@extend .md-shadow-bottom-z-1;
border-radius: 50%;
overflow: hidden;
transform: translate3d(0,0,0);
transition: 0.2s linear;
transition-property: transform, box-shadow;
md-icon {
line-height: $button-fab-height;
margin-top: 0;
}
}
&:not([disabled]) {
&.md-raised,
&.md-fab {
&:focus,
&:hover {
transform: translate3d(0, -1px, 0);
@extend .md-shadow-bottom-z-2;
}
}
}
}
.md-toast-open-top {
.md-button.md-fab-top-left,
.md-button.md-fab-top-right {
transform: translate3d(0, $button-fab-toast-offset, 0);
&:not([disabled]) {
&:focus,
&:hover {
transform: translate3d(0, $button-fab-toast-offset - 1, 0);
}
}
}
}
.md-toast-open-bottom {
.md-button.md-fab-bottom-left,
.md-button.md-fab-bottom-right {
transform: translate3d(0, -$button-fab-toast-offset, 0);
&:not([disabled]) {
&:focus,
&:hover {
transform: translate3d(0, -$button-fab-toast-offset - 1, 0);
}
}
}
}
.md-button-group {
display: flex;
flex: 1;
width: 100%;
}
.md-button-group > .md-button {
flex: 1;
display: block;
overflow: hidden;
width: 0;
border-width: 1px 0px 1px 1px;
border-radius: 0;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
&:first-child {
border-radius: 2px 0px 0px 2px;
}
&:last-child {
border-right-width: 1px;
border-radius: 0px 2px 2px 0px;
}
}

View File

@@ -0,0 +1,91 @@
describe('md-button', function() {
beforeEach(TestUtil.mockRaf);
beforeEach(module('material.components.button'));
it('should convert attributes on an md-button to attributes on the generated button', inject(function($compile, $rootScope) {
var button = $compile('<md-button hide hide-sm></md-button>')($rootScope);
$rootScope.$apply();
expect(button[0].hasAttribute('hide')).toBe(true);
expect(button[0].hasAttribute('hide-sm')).toBe(true);
}));
it('should only have one ripple container when a custom ripple color is set', inject(function ($compile, $rootScope, $timeout) {
var button = $compile('<md-button md-ink-ripple="#f00">button</md-button>')($rootScope);
var scope = button.eq(0).scope();
scope._onInput({ isFirst: true, eventType: Hammer.INPUT_START, center: { x: 0, y: 0 } });
expect(button[0].getElementsByClassName('md-ripple-container').length).toBe(1);
}));
it('should expect an aria-label if element has no text', inject(function($compile, $rootScope, $log) {
spyOn($log, 'warn');
var button = $compile('<md-button><md-icon></md-icon></md-button>')($rootScope);
$rootScope.$apply();
expect($log.warn).toHaveBeenCalled();
$log.warn.reset();
button = $compile('<md-button aria-label="something"><md-icon></md-icon></md-button>')($rootScope);
$rootScope.$apply();
expect($log.warn).not.toHaveBeenCalled();
}));
describe('with href or ng-href', function() {
it('should be anchor if href attr', inject(function($compile, $rootScope) {
var button = $compile('<md-button href="/link">')($rootScope.$new());
$rootScope.$apply();
expect(button[0].tagName.toLowerCase()).toEqual('a');
}));
it('should be anchor if ng-href attr', inject(function($compile, $rootScope) {
var button = $compile('<md-button ng-href="/link">')($rootScope.$new());
$rootScope.$apply();
expect(button[0].tagName.toLowerCase()).toEqual('a');
}));
it('should be button otherwise', inject(function($compile, $rootScope) {
var button = $compile('<md-button>')($rootScope.$new());
$rootScope.$apply();
expect(button[0].tagName.toLowerCase()).toEqual('button');
}));
});
describe('with ng-disabled', function() {
it('should not set `tabindex` when used without anchor attributes', inject(function ($compile, $rootScope, $timeout) {
var scope = angular.extend( $rootScope.$new(), { isDisabled : true } );
var button = $compile('<md-button ng-disabled="isDisabled">button</md-button>')(scope);
$rootScope.$apply();
expect(button[0].hasAttribute('tabindex')).toBe(false);
}));
it('should set `tabindex == -1` when used with href', inject(function ($compile, $rootScope, $timeout) {
var scope = angular.extend( $rootScope.$new(), { isDisabled : true } );
var button = $compile('<md-button ng-disabled="isDisabled" href="#nowhere">button</md-button>')(scope);
$rootScope.$apply();
expect(button.attr('tabindex')).toBe("-1");
$rootScope.$apply(function(){
scope.isDisabled = false;
});
expect(button.attr('tabindex')).toBe("0");
}));
it('should set `tabindex == -1` when used with ng-href', inject(function ($compile, $rootScope, $timeout) {
var scope = angular.extend( $rootScope.$new(), { isDisabled : true, url : "http://material.angularjs.org" });
var button = $compile('<md-button ng-disabled="isDisabled" ng-href="url">button</md-button>')(scope);
$rootScope.$apply();
expect(button.attr('tabindex')).toBe("-1");
}));
})
});

View File

@@ -0,0 +1,53 @@
<div ng-controller="AppCtrl">
<md-content >
<section layout="row" layout-sm="column" layout-align="center center">
<md-button>{{title1}}</md-button>
<md-button md-no-ink class="md-primary">Primary (md-noink)</md-button>
<md-button ng-disabled="true" class="md-primary">Disabled</md-button>
<md-button class="md-warn">{{title4}}</md-button>
</section>
<section layout="row" layout-sm="column" layout-align="center center">
<md-button class="md-raised">Button</md-button>
<md-button class="md-raised md-primary">Primary</md-button>
<md-button ng-disabled="true" class="md-raised md-primary">Disabled</md-button>
<md-button class="md-raised md-warn">Warn</md-button>
<div class="label">raised</div>
</section>
<section layout="row" layout-sm="column" layout-align="center center">
<md-button class="md-fab" aria-label="Time">
<md-icon icon="/img/icons/ic_access_time_24px.svg" style="width: 24px; height: 24px;"></md-icon>
</md-button>
<md-button class="md-fab" aria-label="New document">
<md-icon icon="/img/icons/ic_insert_drive_file_24px.svg" style="width: 24px; height: 24px;"></md-icon>
</md-button>
<md-button class="md-fab" ng-disabled="true" aria-label="Comment">
<md-icon icon="/img/icons/ic_comment_24px.svg" style="width: 24px; height: 24px;"></md-icon>
</md-button>
<md-button class="md-fab md-primary" md-theme="cyan" aria-label="Profile">
<md-icon icon="/img/icons/ic_people_24px.svg" style="width: 24px; height: 24px;"></md-icon>
</md-button>
<div class="label">FAB</div>
</section>
<section layout="row" layout-sm="column" layout-align="center center">
<md-button ng-href="{{googleUrl}}" target="_blank">Go to Google</md-button>
<md-button>RSVP</md-button>
</section>
<section layout="row" layout-sm="column" layout-align="center center">
<md-button class="md-primary md-hue-1">Primary Hue 1</md-button>
<md-button class="md-warn md-raised md-hue-2">Warn Hue 2</md-button>
<md-button class="md-accent">Accent</md-button>
<md-button class="md-accent md-raised md-hue-3">Accent Hue 3</md-button>
<div class="label">Themed</div>
</section>
</md-content>
</div>

View File

@@ -0,0 +1,11 @@
angular.module('buttonsDemo1', ['ngMaterial'])
.controller('AppCtrl', function($scope) {
$scope.title1 = 'Button';
$scope.title4 = 'Warn';
$scope.isDisabled = true;
$scope.googleUrl = 'http://google.com';
});

View File

@@ -0,0 +1,30 @@
/** From vulcanized demo **/
section {
background: #f7f7f7;
border-radius: 3px;
text-align: center;
margin: 1em;
position: relative !important;
padding-bottom: 10px;
}
md-content {
margin-right: 7px;
}
section .md-button:not(.md-fab) {
min-width: 10em;
}
section .md-button {
display: block;
margin: 1em;
line-height: 25px;
}
.label {
position: absolute;
bottom: 5px;
left: 7px;
color: #ccc;
font-size: 14px;
}

View File

@@ -0,0 +1,9 @@
$card-border-radius: 2px !default;
md-card.md-THEME_NAME-theme {
border-radius: $card-border-radius;
.md-card-image {
border-radius: $card-border-radius $card-border-radius 0 0;
}
}

View File

@@ -0,0 +1,51 @@
(function() {
'use strict';
/**
* @ngdoc module
* @name material.components.card
*
* @description
* Card components.
*/
angular.module('material.components.card', [
'material.core'
])
.directive('mdCard', mdCardDirective);
/**
* @ngdoc directive
* @name mdCard
* @module material.components.card
*
* @restrict E
*
* @description
* The `<md-card>` directive is a container element used within `<md-content>` containers.
*
* Cards have constant width and variable heights; where the maximum height is limited to what can
* fit within a single view on a platform, but it can temporarily expand as needed
*
* @usage
* <hljs lang="html">
* <md-card>
* <img src="img/washedout.png" class="md-card-image">
* <h2>Paracosm</h2>
* <p>
* The titles of Washed Out's breakthrough song and the first single from Paracosm share the * two most important words in Ernest Greene's musical language: feel it. It's a simple request, as well...
* </p>
* </md-card>
* </hljs>
*
*/
function mdCardDirective($mdTheming) {
return {
restrict: 'E',
link: function($scope, $element, $attr) {
$mdTheming($element);
}
};
}
})();

View File

@@ -0,0 +1,20 @@
$card-margin: 8px !default;
$card-box-shadow: $whiteframe-shadow-z1 !default;
md-card {
box-sizing: border-box;
display: flex;
flex-direction: column;
box-shadow: $card-box-shadow;
> img {
order: 0;
width: 100%;
}
md-card-content {
order: 1;
margin: $card-margin;
}
}

View File

@@ -0,0 +1,16 @@
describe('mdCard directive', function() {
beforeEach(module('material.components.card'));
it('should have the default theme class when the md-theme attribute is not defined', inject(function($compile, $rootScope) {
var card = $compile('<md-card></md-card>')($rootScope.$new());
$rootScope.$apply();
expect(card.hasClass('md-default-theme')).toBe(true);
}));
it('should have the correct theme class when the md-theme attribute is defined', inject(function($compile, $rootScope) {
var card = $compile('<md-card md-theme="green"></md-card>')($rootScope.$new());
$rootScope.$apply();
expect(card.hasClass('md-green-theme')).toBe(true);
}));
});

View File

@@ -0,0 +1,41 @@
<div ng-controller="AppCtrl">
<md-content>
<md-card>
<img src="img/washedout.png" alt="Washed Out">
<md-card-content>
<h2>Paracosm</h2>
<p>
The titles of Washed Out's breakthrough song and the first single from Paracosm share the
two most important words in Ernest Greene's musical language: feel it. It's a simple request, as well...
</p>
</md-card-content>
</md-card>
<md-card>
<img src="img/washedout.png" alt="Washed Out">
<md-card-content>
<h2>Paracosm</h2>
<p>
The titles of Washed Out's breakthrough song and the first single from Paracosm share the
two most important words in Ernest Greene's musical language: feel it. It's a simple request, as well...
</p>
</md-card-content>
</md-card>
<md-card>
<img src="img/washedout.png" alt="Washed Out">
<md-card-content>
<h2>Paracosm</h2>
<p>
The titles of Washed Out's breakthrough song and the first single from Paracosm share the
two most important words in Ernest Greene's musical language: feel it. It's a simple request, as well...
</p>
</md-card-content>
</md-card>
</md-content>
</div>

View File

@@ -0,0 +1,6 @@
angular.module('cardDemo1', ['ngMaterial'])
.controller('AppCtrl', function($scope) {
});

View File

@@ -0,0 +1,4 @@
md-card {
min-height: 150px;
}

View File

@@ -0,0 +1,73 @@
md-checkbox.md-THEME_NAME-theme {
.md-ripple {
color: '{{accent-600}}';
}
&.md-checked .md-ripple {
color: '{{background-600}}';
}
.md-icon {
border-color: '{{foreground-2}}';
}
&.md-checked .md-icon {
background-color: '{{accent-color-0.87}}';
}
&.md-checked .md-icon:after {
border-color: '{{background-200}}';
}
&:not([disabled]) {
&.md-primary {
.md-ripple {
color: '{{primary-600}}';
}
&.md-checked .md-ripple {
color: '{{background-600}}';
}
.md-icon {
border-color: '{{foreground-2}}';
}
&.md-checked .md-icon {
background-color: '{{primary-color-0.87}}';
}
&.md-checked .md-icon:after {
border-color: '{{background-200}}';
}
}
&.md-warn {
.md-ripple {
color: '{{warn-600}}';
}
&.md-checked .md-ripple {
color: '{{background-600}}';
}
.md-icon {
border-color: '{{foreground-2}}';
}
&.md-checked .md-icon {
background-color: '{{warn-color-0.87}}';
}
&.md-checked .md-icon:after {
border-color: '{{background-200}}';
}
}
}
&[disabled] {
.md-icon {
border-color: '{{foreground-3}}';
}
&.md-checked .md-icon {
background-color: '{{foreground-3}}';
}
}
}

View File

@@ -0,0 +1,126 @@
(function() {
'use strict';
/**
* @ngdoc module
* @name material.components.checkbox
* @description Checkbox module!
*/
angular.module('material.components.checkbox', [
'material.core'
])
.directive('mdCheckbox', MdCheckboxDirective);
/**
* @ngdoc directive
* @name mdCheckbox
* @module material.components.checkbox
* @restrict E
*
* @description
* The checkbox directive is used like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
*
* @param {string} ng-model Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {expression=} ng-true-value The value to which the expression should be set when selected.
* @param {expression=} ng-false-value The value to which the expression should be set when not selected.
* @param {string=} ng-change Angular expression to be executed when input changes due to user interaction with the input element.
* @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects
* @param {string=} aria-label Adds label to checkbox for accessibility.
* Defaults to checkbox's text. If no default text is found, a warning will be logged.
*
* @usage
* <hljs lang="html">
* <md-checkbox ng-model="isChecked" aria-label="Finished?">
* Finished ?
* </md-checkbox>
*
* <md-checkbox md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
* No Ink Effects
* </md-checkbox>
*
* <md-checkbox ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
* Disabled
* </md-checkbox>
*
* </hljs>
*
*/
function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant, $mdTheming, $mdUtil) {
inputDirective = inputDirective[0];
var CHECKED_CSS = 'md-checked';
return {
restrict: 'E',
transclude: true,
require: '?ngModel',
template:
'<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
'<div class="md-icon"></div>' +
'</div>' +
'<div ng-transclude class="md-label"></div>',
compile: compile
};
// **********************************************************
// Private Methods
// **********************************************************
function compile (tElement, tAttrs) {
tAttrs.type = 'checkbox';
tAttrs.tabIndex = 0;
tElement.attr('role', tAttrs.type);
return function postLink(scope, element, attr, ngModelCtrl) {
ngModelCtrl = ngModelCtrl || $mdUtil.fakeNgModel();
var checked = false;
$mdTheming(element);
$mdAria.expectWithText(tElement, 'aria-label');
// Reuse the original input[type=checkbox] directive from Angular core.
// This is a bit hacky as we need our own event listener and own render
// function.
inputDirective.link.pre(scope, {
on: angular.noop,
0: {}
}, attr, [ngModelCtrl]);
// Used by switch. in Switch, we don't want click listeners; we have more granular
// touchup/touchdown listening.
if (!attr.mdNoClick) {
element.on('click', listener);
}
element.on('keypress', keypressHandler);
ngModelCtrl.$render = render;
function keypressHandler(ev) {
if(ev.which === $mdConstant.KEY_CODE.SPACE) {
ev.preventDefault();
listener(ev);
}
}
function listener(ev) {
if (element[0].hasAttribute('disabled')) return;
scope.$apply(function() {
checked = !checked;
ngModelCtrl.$setViewValue(checked, ev && ev.type);
ngModelCtrl.$render();
});
}
function render() {
checked = ngModelCtrl.$viewValue;
if(checked) {
element.addClass(CHECKED_CSS);
} else {
element.removeClass(CHECKED_CSS);
}
}
};
}
}
})();

View File

@@ -0,0 +1,91 @@
$checkbox-width: 18px !default;
$checkbox-height: $checkbox-width !default;
md-checkbox {
display: block;
margin: 15px;
white-space: nowrap;
cursor: pointer;
outline: none;
user-select: none;
.md-container {
position: relative;
top: 4px;
display: inline-block;
width: $checkbox-width;
height: $checkbox-height;
&:after {
content: '';
position: absolute;
top: -10px;
right: -10px;
bottom: -10px;
left: -10px;
}
.md-ripple-container {
position: absolute;
display: block;
width: auto;
height: auto;
left: -15px;
top: -15px;
right: -15px;
bottom: -15px;
}
}
// unchecked
.md-icon {
transition: 240ms;
position: absolute;
top: 0;
left: 0;
width: $checkbox-width;
height: $checkbox-height;
border: 2px solid;
border-radius: 2px;
}
&.md-checked .md-icon {
border: none;
}
// disabled
&[disabled] {
cursor: no-drop;
}
// focus
&:focus .md-label:not(:empty) {
border-color: black;
}
&.md-checked .md-icon:after {
transform: rotate(45deg);
position: absolute;
left: 6px;
top: 2px;
display: table;
width: 6px;
height: 12px;
border: 2px solid;
border-top: 0;
border-left: 0;
content: ' ';
}
.md-label {
border: 1px dotted transparent;
position: relative;
display: inline-block;
margin-left: 10px;
vertical-align: middle;
white-space: normal;
pointer-events: none;
user-select: text;
}
}

View File

@@ -0,0 +1,172 @@
describe('mdCheckbox', function() {
var CHECKED_CSS = 'md-checked';
beforeEach(module('material.components.checkbox'));
beforeEach(module('ngAria'));
beforeEach(TestUtil.mockRaf);
it('should warn developers they need a label', inject(function($compile, $rootScope, $log){
spyOn($log, "warn");
var element = $compile('<div>' +
'<md-checkbox ng-model="blue">' +
'</md-checkbox>' +
'</div>')($rootScope);
expect($log.warn).toHaveBeenCalled();
}));
it('should copy text content to aria-label', inject(function($compile, $rootScope){
var element = $compile('<div>' +
'<md-checkbox ng-model="blue">' +
'Some text' +
'</md-checkbox>' +
'</div>')($rootScope);
var cbElements = element.find('md-checkbox');
expect(cbElements.eq(0).attr('aria-label')).toBe('Some text');
}));
it('should set checked css class and aria-checked attributes', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
'<md-checkbox ng-model="blue">' +
'</md-checkbox>' +
'<md-checkbox ng-model="green">' +
'</md-checkbox>' +
'</div>')($rootScope);
$rootScope.$apply(function(){
$rootScope.blue = false;
$rootScope.green = true;
});
var cbElements = element.find('md-checkbox');
expect(cbElements.eq(0).hasClass(CHECKED_CSS)).toEqual(false);
expect(cbElements.eq(1).hasClass(CHECKED_CSS)).toEqual(true);
expect(cbElements.eq(0).attr('aria-checked')).toEqual('false');
expect(cbElements.eq(1).attr('aria-checked')).toEqual('true');
expect(cbElements.eq(0).attr('role')).toEqual('checkbox');
}));
it('should be disabled with disabled attr', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
'<md-checkbox ng-disabled="isDisabled" ng-model="blue">' +
'</md-checkbox>' +
'</div>')($rootScope);
var checkbox = element.find('md-checkbox');
$rootScope.$apply('isDisabled = true');
$rootScope.$apply('blue = false');
checkbox.triggerHandler('click');
expect($rootScope.blue).toBe(false);
$rootScope.$apply('isDisabled = false');
checkbox.triggerHandler('click');
expect($rootScope.blue).toBe(true);
}));
describe('ng core checkbox tests', function() {
var inputElm;
var scope;
var $compile;
beforeEach(inject(function(_$compile_, _$rootScope_) {
scope = _$rootScope_;
$compile = _$compile_;
}));
function compileInput(html) {
inputElm = $compile(html)(scope);
}
function isChecked(cbEl) {
return cbEl.hasClass(CHECKED_CSS);
}
it('should format booleans', function() {
compileInput('<md-checkbox ng-model="name" />');
scope.$apply("name = false");
expect(isChecked(inputElm)).toBe(false);
scope.$apply("name = true");
expect(isChecked(inputElm)).toBe(true);
});
it('should support type="checkbox" with non-standard capitalization', function() {
compileInput('<md-checkbox ng-model="checkbox" />');
inputElm.triggerHandler('click');
expect(scope.checkbox).toBe(true);
inputElm.triggerHandler('click');
expect(scope.checkbox).toBe(false);
});
it('should allow custom enumeration', function() {
compileInput('<md-checkbox ng-model="name" ng-true-value="\'y\'" ' +
'ng-false-value="\'n\'">');
scope.$apply("name = 'y'");
expect(isChecked(inputElm)).toBe(true);
scope.$apply("name = 'n'");
expect(isChecked(inputElm)).toBe(false);
scope.$apply("name = 'something else'");
expect(isChecked(inputElm)).toBe(false);
inputElm.triggerHandler('click');
expect(scope.name).toEqual('y');
inputElm.triggerHandler('click');
expect(scope.name).toEqual('n');
});
it('should throw if ngTrueValue is present and not a constant expression', function() {
expect(function() {
compileInput('<md-checkbox ng-model="value" ng-true-value="yes" />');
}).toThrow();
});
it('should throw if ngFalseValue is present and not a constant expression', function() {
expect(function() {
compileInput('<md-checkbox ng-model="value" ng-false-value="no" />');
}).toThrow();
});
it('should not throw if ngTrueValue or ngFalseValue are not present', function() {
expect(function() {
compileInput('<md-checkbox ng-model="value" />');
}).not.toThrow();
});
it('should be required if false', function() {
compileInput('<md-checkbox ng:model="value" required />');
inputElm.triggerHandler('click');
expect(isChecked(inputElm)).toBe(true);
expect(inputElm.hasClass('ng-valid')).toBe(true);
inputElm.triggerHandler('click');
expect(isChecked(inputElm)).toBe(false);
expect(inputElm.hasClass('ng-invalid')).toBe(true);
});
});
});

View File

@@ -0,0 +1,23 @@
<div ng-controller="AppCtrl">
<md-checkbox ng-model="data.cb1" aria-label="Checkbox 1">
Checkbox 1: {{ data.cb1 }}
</md-checkbox>
<md-checkbox ng-model="data.cb2" aria-label="Checkbox 2" ng-true-value="'yup'" ng-false-value="'nope'" class="md-warn">
Checkbox 2 (md-warn): {{ data.cb2 }}
</md-checkbox>
<md-checkbox ng-disabled="true" aria-label="Disabled checkbox" ng-model="data.cb3">
Checkbox: Disabled
</md-checkbox>
<md-checkbox ng-disabled="true" aria-label="Disabled checked checkbox" ng-model="data.cb4" ng-init="data.cb4=true">
Checkbox: Disabled, Checked
</md-checkbox>
<md-checkbox md-no-ink aria-label="Checkbox No Ink" ng-model="data.cb5" class="md-primary">
Checkbox (md-primary): No Ink
</md-checkbox>
</div>

View File

@@ -0,0 +1,13 @@
angular.module('checkboxDemo1', ['ngMaterial'])
.controller('AppCtrl', function($scope) {
$scope.data = {};
$scope.data.cb1 = true;
$scope.data.cb2 = false;
$scope.data.cb3 = false;
$scope.data.cb4 = false;
$scope.data.cb5 = false;
});

View File

@@ -0,0 +1,4 @@
body {
padding: 20px;
}

View File

@@ -0,0 +1,5 @@
$content-background-color: $background-color-base !default;
md-content.md-THEME_NAME-theme {
background-color: '{{background-hue-3}}';
}

View File

@@ -0,0 +1,53 @@
(function() {
'use strict';
/**
* @ngdoc module
* @name material.components.content
*
* @description
* Scrollable content
*/
angular.module('material.components.content', [
'material.core'
])
.directive('mdContent', mdContentDirective);
/**
* @ngdoc directive
* @name mdContent
* @module material.components.content
*
* @restrict E
*
* @description
* The `<md-content>` directive is a container element useful for scrollable content
*
* ### Restrictions
*
* - Add the `md-padding` class to make the content padded.
*
* @usage
* <hljs lang="html">
* <md-content class="md-padding">
* Lorem ipsum dolor sit amet, ne quod novum mei.
* </md-content>
* </hljs>
*
*/
function mdContentDirective($mdTheming) {
return {
restrict: 'E',
controller: ['$scope', '$element', ContentController],
link: function($scope, $element, $attr) {
$mdTheming($element);
$scope.$broadcast('$mdContentLoaded', $element);
}
};
function ContentController($scope, $element) {
this.$scope = $scope;
this.$element = $element;
}
}
})();

View File

@@ -0,0 +1,28 @@
md-content {
display: block;
position: relative;
overflow: auto;
-webkit-overflow-scrolling: touch;
&[md-scroll-y] {
overflow-y: auto;
overflow-x: hidden;
}
&[md-scroll-x] {
overflow-x: auto;
overflow-y: hidden;
}
&[md-scroll-xy] {
}
&.md-padding {
padding: 8px;
}
}
@media (min-width: $layout-breakpoint-sm) {
md-content.md-padding {
padding: 16px;
}
}

View File

@@ -0,0 +1,54 @@
<div ng-controller="AppCtrl" layout="column" style="padding-bottom: 15px;">
<md-toolbar class="md-accent">
<div class="md-toolbar-tools">
<span class="md-flex">Toolbar: md-accent</span>
</div>
</md-toolbar>
<md-content class="md-padding" style="height: 600px;">
Lorem ipsum dolor sit amet, ne quod novum mei. Sea omnium invenire mediocrem at, in lobortis conclusionemque nam. Ne deleniti appetere reprimique pro, inani labitur disputationi te sed. At vix sale omnesque, id pro labitur reformidans accommodare, cum labores honestatis eu. Nec quem lucilius in, eam praesent reformidans no. Sed laudem aliquam ne.
<p>
Facete delenit argumentum cum at. Pro rebum nostrum contentiones ad. Mel exerci tritani maiorum at, mea te audire phaedrum, mel et nibh aliquam. Malis causae equidem vel eu. Noster melius vis ea, duis alterum oporteat ea sea. Per cu vide munere fierent.
</p>
<p>
Ad sea dolor accusata consequuntur. Sit facete convenire reprehendunt et. Usu cu nonumy dissentiet, mei choro omnes fuisset ad. Te qui docendi accusam efficiantur, doming noster prodesset eam ei. In vel posse movet, ut convenire referrentur eum, ceteros singulis intellegam eu sit.
</p>
<p>
Sit saepe quaestio reprimique id, duo no congue nominati, cum id nobis facilisi. No est laoreet dissentias, idque consectetuer eam id. Clita possim assueverit cu his, solum virtute recteque et cum. Vel cu luptatum signiferumque, mel eu brute nostro senserit. Blandit euripidis consequat ex mei, atqui torquatos id cum, meliore luptatum ut usu. Cu zril perpetua gubergren pri. Accusamus rationibus instructior ei pro, eu nullam principes qui, reque justo omnes et quo.
</p>
<p>
Sint unum eam id. At sit fastidii theophrastus, mutat senserit repudiare et has. Atqui appareat repudiare ad nam, et ius alii incorrupte. Alii nullam libris his ei, meis aeterno at eum. Ne aeque tincidunt duo. In audire malorum mel, tamquam efficiantur has te.
</p>
<p>
Qui utamur tacimates quaestio ad, quod graece omnium ius ut. Pri ut vero debitis interpretaris, qui cu mentitum adipiscing disputationi. Voluptatum mediocritatem quo ut. Fabulas dolorem ei has, quem molestie persequeris et sit.
</p>
<p>
Est in vivendum comprehensam conclusionemque, alia cetero iriure no usu, te cibo deterruisset pro. Ludus epicurei quo id, ex cum iudicabit intellegebat. Ex modo deseruisse quo, mel noster menandri sententiae ea, duo et tritani malorum recteque. Nullam suscipit partiendo nec id, indoctum vulputate per ex. Et has enim habemus tibique. Cu latine electram cum, ridens propriae intellegat eu mea.
</p>
<p>
Duo at aliquid mnesarchum, nec ne impetus hendrerit. Ius id aeterno debitis atomorum, et sed feugait voluptua, brute tibique no vix. Eos modo esse ex, ei omittam imperdiet pro. Vel assum albucius incorrupte no. Vim viris prompta repudiare ne, vel ut viderer scripserit, dicant appetere argumentum mel ea. Eripuit feugait tincidunt pri ne, cu facilisi molestiae usu.
</p>
<p>
Qui utamur tacimates quaestio ad, quod graece omnium ius ut. Pri ut vero debitis interpretaris, qui cu mentitum adipiscing disputationi. Voluptatum mediocritatem quo ut. Fabulas dolorem ei has, quem molestie persequeris et sit.
</p>
<p>
Est in vivendum comprehensam conclusionemque, alia cetero iriure no usu, te cibo deterruisset pro. Ludus epicurei quo id, ex cum iudicabit intellegebat. Ex modo deseruisse quo, mel noster menandri sententiae ea, duo et tritani malorum recteque. Nullam suscipit partiendo nec id, indoctum vulputate per ex. Et has enim habemus tibique. Cu latine electram cum, ridens propriae intellegat eu mea.
</p>
<p>
Duo at aliquid mnesarchum, nec ne impetus hendrerit. Ius id aeterno debitis atomorum, et sed feugait voluptua, brute tibique no vix. Eos modo esse ex, ei omittam imperdiet pro. Vel assum albucius incorrupte no. Vim viris prompta repudiare ne, vel ut viderer scripserit, dicant appetere argumentum mel ea. Eripuit feugait tincidunt pri ne, cu facilisi molestiae usu.
</p>
</md-content>
</div>

View File

@@ -0,0 +1,6 @@
angular.module('contentDemo1', ['ngMaterial'])
.controller('AppCtrl', function($scope) {
})

View File

@@ -0,0 +1,32 @@
<md-dialog aria-label="Mango (Fruit)">
<md-content>
<md-subheader class="md-sticky-no-effect">Mango (Fruit)</md-subheader>
<p>
The mango is a juicy stone fruit belonging to the genus Mangifera, consisting of numerous tropical fruiting trees, cultivated mostly for edible fruit. The majority of these species are found in nature as wild mangoes. They all belong to the flowering plant family Anacardiaceae. The mango is native to South and Southeast Asia, from where it has been distributed worldwide to become one of the most cultivated fruits in the tropics.
</p>
<img style="margin: auto; max-width: 100%;" src="img/mangues.jpg">
<p>
The highest concentration of Mangifera genus is in the western part of Malesia (Sumatra, Java and Borneo) and in Burma and India. While other Mangifera species (e.g. horse mango, M. foetida) are also grown on a more localized basis, Mangifera indica—the "common mango" or "Indian mango"—is the only mango tree commonly cultivated in many tropical and subtropical regions.
</p>
<p>
It originated in Indian subcontinent (present day India and Pakistan) and Burma. It is the national fruit of India, Pakistan, and the Philippines, and the national tree of Bangladesh. In several cultures, its fruit and leaves are ritually used as floral decorations at weddings, public celebrations, and religious ceremonies.
</p>
</md-content>
<div class="md-actions" layout="row">
<md-button href="http://en.wikipedia.org/wiki/Mango" target="_blank" hide show-md>
More on Wikipedia
</md-button>
<span flex></span>
<md-button ng-click="answer('not useful')">
Not Useful
</md-button>
<md-button ng-click="answer('useful')" class="md-primary">
Useful
</md-button>
</div>
</md-dialog>

View File

@@ -0,0 +1,24 @@
<div ng-controller="AppCtrl" class="full" layout="column" layout-margin>
<p class="inset">
Open a dialog over the app's content. Press escape or click outside to close the dialog.
</p>
<div layout="column" layout-align="center" >
<md-button class="md-primary" ng-click="showAlert($event)">
Alert Dialog
</md-button>
<div class="gap"></div>
<md-button class="md-primary" ng-click="showConfirm($event)">
Confirm Dialog
</md-button>
<div class="gap"></div>
<md-button class="md-primary" ng-click="showAdvanced($event)">
Custom Dialog
</md-button>
</div>
<br/>
<b layout="row" layout-align="center center" layout-margin>
{{alert}}
</b>
</div>

View File

@@ -0,0 +1,59 @@
angular.module('dialogDemo1', ['ngMaterial'])
.controller('AppCtrl', function($scope, $mdDialog) {
$scope.alert = '';
$scope.showAlert = function(ev) {
$mdDialog.show(
$mdDialog.alert()
.title('This is an alert title')
.content('You can specify some description text in here.')
.ariaLabel('Password notification')
.ok('Got it!')
.targetEvent(ev)
);
};
$scope.showConfirm = function(ev) {
var confirm = $mdDialog.confirm()
.title('Would you like to delete your debt?')
.content('All of the banks have agreed to forgive you your debts.')
.ariaLabel('Lucky day')
.ok('Please do it!')
.cancel('Sounds like a scam')
.targetEvent(ev);
$mdDialog.show(confirm).then(function() {
$scope.alert = 'You decided to get rid of your debt.';
}, function() {
$scope.alert = 'You decided to keep your debt.';
});
};
$scope.showAdvanced = function(ev) {
$mdDialog.show({
controller: DialogController,
templateUrl: 'dialog1.tmpl.html',
targetEvent: ev,
})
.then(function(answer) {
$scope.alert = 'You said the information was "' + answer + '".';
}, function() {
$scope.alert = 'You cancelled the dialog.';
});
};
});
function DialogController($scope, $mdDialog) {
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
}

View File

@@ -0,0 +1,34 @@
.full {
width: 100%;
height: 100%;
}
.gap {
width:50px;
}
.md-subheader {
background-color: #dcedc8;
margin: 0px;
}
h2.md-subheader {
margin: 0px;
margin-left: -24px;
margin-right: -24px;
margin-top: -24px;
}
h2.md-subheader.md-sticky-clone {
margin-right:0px;
margin-top:0px;
box-shadow: 0px 2px 4px 0 rgba(0,0,0,0.16);
}
h2 .md-subheader-content {
padding-left: 10px;
}

View File

@@ -0,0 +1,11 @@
$dialog-border-radius: 4px !default;
md-dialog.md-THEME_NAME-theme {
border-radius: $dialog-border-radius;
background-color: '{{background-hue-3}}';
&.md-content-overflow .md-actions {
border-top-color: '{{foreground-4}}';
}
}

View File

@@ -0,0 +1,485 @@
(function() {
'use strict';
/**
* @ngdoc module
* @name material.components.dialog
*/
angular.module('material.components.dialog', [
'material.core',
'material.components.backdrop'
])
.directive('mdDialog', MdDialogDirective)
.provider('$mdDialog', MdDialogProvider);
function MdDialogDirective($$rAF, $mdTheming) {
return {
restrict: 'E',
link: function(scope, element, attr) {
$mdTheming(element);
$$rAF(function() {
var content = element[0].querySelector('md-content');
if (content && content.scrollHeight > content.clientHeight) {
element.addClass('md-content-overflow');
}
});
}
};
}
/**
* @ngdoc service
* @name $mdDialog
* @module material.components.dialog
*
* @description
* `$mdDialog` opens a dialog over the app and provides a simple promise API.
*
* ### Restrictions
*
* - The dialog is always given an isolate scope.
* - The dialog's template must have an outer `<md-dialog>` element.
* Inside, use an `<md-content>` element for the dialog's content, and use
* an element with class `md-actions` for the dialog's actions.
*
* @usage
* ##### HTML
*
* <hljs lang="html">
* <div ng-app="demoApp" ng-controller="EmployeeController">
* <md-button ng-click="showAlert()" class="md-raised md-warn">
* Employee Alert!
* </md-button>
* <md-button ng-click="closeAlert()" ng-disabled="!hasAlert()" class="md-raised">
* Close Alert
* </md-button>
* <md-button ng-click="showGreeting($event)" class="md-raised md-primary" >
* Greet Employee
* </md-button>
* </div>
* </hljs>
*
* ##### JavaScript
*
* <hljs lang="js">
* (function(angular, undefined){
* "use strict";
*
* angular
* .module('demoApp', ['ngMaterial'])
* .controller('EmployeeController', EmployeeEditor)
* .controller('GreetingController', GreetingController);
*
* // Fictitious Employee Editor to show how to use simple and complex dialogs.
*
* function EmployeeEditor($scope, $mdDialog) {
* var alert;
*
* $scope.showAlert = showAlert;
* $scope.closeAlert = closeAlert;
* $scope.showGreeting = showCustomGreeting;
*
* $scope.hasAlert = function() { return !!alert };
* $scope.userName = $scope.userName || 'Bobby';
*
* // Dialog #1 - Show simple alert dialog and cache
* // reference to dialog instance
*
* function showAlert() {
* alert = $mdDialog.alert()
* .title('Attention, ' + $scope.userName)
* .content('This is an example of how easy dialogs can be!')
* .ok('Close');
*
* $mdDialog
* .show( alert )
* .finally(function() {
* alert = undefined;
* });
* }
*
* // Close the specified dialog instance and resolve with 'finished' flag
* // Normally this is not needed, just use '$mdDialog.hide()' to close
* // the most recent dialog popup.
*
* function closeAlert() {
* $mdDialog.hide( alert, "finished" );
* alert = undefined;
* }
*
* // Dialog #2 - Demonstrate more complex dialogs construction and popup.
*
* function showCustomGreeting($event) {
* $mdDialog.show({
* targetEvent: $event,
* template:
* '<md-dialog>' +
*
* ' <md-content>Hello {{ employee }}!</md-content>' +
*
* ' <div class="md-actions">' +
* ' <md-button ng-click="closeDialog()">' +
* ' Close Greeting' +
*
* ' </md-button>' +
* ' </div>' +
* '</md-dialog>',
* controller: 'GreetingController',
* onComplete: afterShowAnimation,
* locals: { employee: $scope.userName }
* });
*
* // When the 'enter' animation finishes...
*
* function afterShowAnimation(scope, element, options) {
* // post-show code here: DOM element focus, etc.
* }
* }
* }
*
* // Greeting controller used with the more complex 'showCustomGreeting()' custom dialog
*
* function GreetingController($scope, $mdDialog, employee) {
* // Assigned from construction <code>locals</code> options...
* $scope.employee = employee;
*
* $scope.closeDialog = function() {
* // Easily hides most recent dialog shown...
* // no specific instance reference is needed.
* $mdDialog.hide();
* };
* }
*
* })(angular);
* </hljs>
*/
/**
* @ngdoc method
* @name $mdDialog#alert
*
* @description
* Builds a preconfigured dialog with the specified message.
*
* @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
*
* - $mdDialogPreset#title(string) - sets title to string
* - $mdDialogPreset#content(string) - sets content / message to string
* - $mdDialogPreset#ok(string) - sets okay button text to string
*
*/
/**
* @ngdoc method
* @name $mdDialog#confirm
*
* @description
* Builds a preconfigured dialog with the specified message. You can call show and the promise returned
* will be resolved only if the user clicks the confirm action on the dialog.
*
* @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
*
* Additionally, it supports the following methods:
*
* - $mdDialogPreset#title(string) - sets title to string
* - $mdDialogPreset#content(string) - sets content / message to string
* - $mdDialogPreset#ok(string) - sets okay button text to string
* - $mdDialogPreset#cancel(string) - sets cancel button text to string
*
*/
/**
* @ngdoc method
* @name $mdDialog#show
*
* @description
* Show a dialog with the specified options.
*
* @param {object} optionsOrPreset Either provide an `$mdDialogPreset` returned from `alert()`,
* `confirm()` or an options object with the following properties:
* - `templateUrl` - `{string=}`: The url of a template that will be used as the content
* of the dialog.
* - `template` - `{string=}`: Same as templateUrl, except this is an actual template string.
* - `targetEvent` - `{DOMClickEvent=}`: A click's event object. When passed in as an option,
* the location of the click will be used as the starting point for the opening animation
* of the the dialog.
* - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the dialog is open.
* Default true.
* - `hasBackdrop` - `{boolean=}`: Whether there should be an opaque backdrop behind the dialog.
* Default true.
* - `clickOutsideToClose` - `{boolean=}`: Whether the user can click outside the dialog to
* close it. Default true.
* - `escapeToClose` - `{boolean=}`: Whether the user can press escape to close the dialog.
* Default true.
* - `controller` - `{string=}`: The controller to associate with the dialog. The controller
* will be injected with the local `$hideDialog`, which is a function used to hide the dialog.
* - `locals` - `{object=}`: An object containing key/value pairs. The keys will be used as names
* of values to inject into the controller. For example, `locals: {three: 3}` would inject
* `three` into the controller, with the value 3. If `bindToController` is true, they will be
* copied to the controller instead.
* - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in
* - `resolve` - `{object=}`: Similar to locals, except it takes promises as values, and the
* dialog will not open until all of the promises resolve.
* - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.
* - `parent` - `{element=}`: The element to append the dialog to. Defaults to appending
* to the root element of the application.
* - `onComplete` `{function=}`: Callback function used to announce when the show() action is
* finished.
*
* @returns {promise} A promise that can be resolved with `$mdDialog.hide()` or
* rejected with `mdDialog.cancel()`.
*/
/**
* @ngdoc method
* @name $mdDialog#hide
*
* @description
* Hide an existing dialog and resolve the promise returned from `$mdDialog.show()`.
*
* @param {*=} response An argument for the resolved promise.
*/
/**
* @ngdoc method
* @name $mdDialog#cancel
*
* @description
* Hide an existing dialog and reject the promise returned from `$mdDialog.show()`.
*
* @param {*=} response An argument for the rejected promise.
*/
function MdDialogProvider($$interimElementProvider) {
var alertDialogMethods = ['title', 'content', 'ariaLabel', 'ok'];
return $$interimElementProvider('$mdDialog')
.setDefaults({
methods: ['disableParentScroll', 'hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent'],
options: dialogDefaultOptions
})
.addPreset('alert', {
methods: ['title', 'content', 'ariaLabel', 'ok'],
options: advancedDialogOptions
})
.addPreset('confirm', {
methods: ['title', 'content', 'ariaLabel', 'ok', 'cancel'],
options: advancedDialogOptions
});
/* @ngInject */
function advancedDialogOptions($mdDialog) {
return {
template: [
'<md-dialog aria-label="{{ dialog.ariaLabel }}">',
'<md-content>',
'<h2>{{ dialog.title }}</h2>',
'<p>{{ dialog.content }}</p>',
'</md-content>',
'<div class="md-actions">',
'<md-button ng-if="dialog.$type == \'confirm\'" ng-click="dialog.abort()">',
'{{ dialog.cancel }}',
'</md-button>',
'<md-button ng-click="dialog.hide()" class="md-primary">',
'{{ dialog.ok }}',
'</md-button>',
'</div>',
'</md-dialog>'
].join(''),
controller: function mdDialogCtrl() {
this.hide = function() {
$mdDialog.hide(true);
};
this.abort = function() {
$mdDialog.cancel();
};
},
controllerAs: 'dialog',
bindToController: true
};
}
/* @ngInject */
function dialogDefaultOptions($timeout, $rootElement, $compile, $animate, $mdAria, $document,
$mdUtil, $mdConstant, $mdTheming, $$rAF, $q, $mdDialog) {
return {
hasBackdrop: true,
isolateScope: true,
onShow: onShow,
onRemove: onRemove,
clickOutsideToClose: true,
escapeToClose: true,
targetEvent: null,
disableParentScroll: true,
transformTemplate: function(template) {
return '<div class="md-dialog-container">' + template + '</div>';
}
};
// On show method for dialogs
function onShow(scope, element, options) {
// Incase the user provides a raw dom element, always wrap it in jqLite
options.parent = angular.element(options.parent);
options.popInTarget = angular.element((options.targetEvent || {}).target);
var closeButton = findCloseButton();
configureAria(element.find('md-dialog'));
if (options.hasBackdrop) {
options.backdrop = angular.element('<md-backdrop class="md-dialog-backdrop md-opaque">');
$mdTheming.inherit(options.backdrop, options.parent);
$animate.enter(options.backdrop, options.parent);
}
if (options.disableParentScroll) {
options.oldOverflowStyle = options.parent.css('overflow');
options.parent.css('overflow', 'hidden');
}
return dialogPopIn(
element,
options.parent,
options.popInTarget && options.popInTarget.length && options.popInTarget
)
.then(function() {
if (options.escapeToClose) {
options.rootElementKeyupCallback = function(e) {
if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
$timeout($mdDialog.cancel);
}
};
$rootElement.on('keyup', options.rootElementKeyupCallback);
}
if (options.clickOutsideToClose) {
options.dialogClickOutsideCallback = function(e) {
// Only close if we click the flex container outside the backdrop
if (e.target === element[0]) {
$timeout($mdDialog.cancel);
}
};
element.on('click', options.dialogClickOutsideCallback);
}
closeButton.focus();
});
function findCloseButton() {
//If no element with class dialog-close, try to find the last
//button child in md-actions and assume it is a close button
var closeButton = element[0].querySelector('.dialog-close');
if (!closeButton) {
var actionButtons = element[0].querySelectorAll('.md-actions button');
closeButton = actionButtons[ actionButtons.length - 1 ];
}
return angular.element(closeButton);
}
}
// On remove function for all dialogs
function onRemove(scope, element, options) {
if (options.backdrop) {
$animate.leave(options.backdrop);
}
if (options.disableParentScroll) {
options.parent.css('overflow', options.oldOverflowStyle);
$document[0].removeEventListener('scroll', options.captureScroll, true);
}
if (options.escapeToClose) {
$rootElement.off('keyup', options.rootElementKeyupCallback);
}
if (options.clickOutsideToClose) {
element.off('click', options.dialogClickOutsideCallback);
}
return dialogPopOut(
element,
options.parent,
options.popInTarget && options.popInTarget.length && options.popInTarget
).then(function() {
options.scope.$destroy();
element.remove();
options.popInTarget && options.popInTarget.focus();
});
}
/**
* Inject ARIA-specific attributes appropriate for Dialogs
*/
function configureAria(element) {
element.attr({
'role': 'dialog'
});
var dialogContent = element.find('md-content');
if (dialogContent.length === 0){
dialogContent = element;
}
$mdAria.expectAsync(element, 'aria-label', function() {
var words = dialogContent.text().split(/\s+/);
if (words.length > 3) words = words.slice(0,3).concat('...');
return words.join(' ');
});
}
function dialogPopIn(container, parentElement, clickElement) {
var dialogEl = container.find('md-dialog');
parentElement.append(container);
transformToClickElement(dialogEl, clickElement);
$$rAF(function() {
dialogEl.addClass('transition-in')
.css($mdConstant.CSS.TRANSFORM, '');
});
return dialogTransitionEnd(dialogEl);
}
function dialogPopOut(container, parentElement, clickElement) {
var dialogEl = container.find('md-dialog');
dialogEl.addClass('transition-out').removeClass('transition-in');
transformToClickElement(dialogEl, clickElement);
return dialogTransitionEnd(dialogEl);
}
function transformToClickElement(dialogEl, clickElement) {
if (clickElement) {
var clickRect = clickElement[0].getBoundingClientRect();
var dialogRect = dialogEl[0].getBoundingClientRect();
var scaleX = Math.min(0.5, clickRect.width / dialogRect.width);
var scaleY = Math.min(0.5, clickRect.height / dialogRect.height);
dialogEl.css($mdConstant.CSS.TRANSFORM, 'translate3d(' +
(-dialogRect.left + clickRect.left + clickRect.width/2 - dialogRect.width/2) + 'px,' +
(-dialogRect.top + clickRect.top + clickRect.height/2 - dialogRect.height/2) + 'px,' +
'0) scale(' + scaleX + ',' + scaleY + ')'
);
}
}
function dialogTransitionEnd(dialogEl) {
var deferred = $q.defer();
dialogEl.on($mdConstant.CSS.TRANSITIONEND, finished);
function finished(ev) {
//Make sure this transitionend didn't bubble up from a child
if (ev.target === dialogEl[0]) {
dialogEl.off($mdConstant.CSS.TRANSITIONEND, finished);
deferred.resolve();
}
}
return deferred.promise;
}
}
}
})();

View File

@@ -0,0 +1,65 @@
.md-dialog-container {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: $z-index-dialog;
}
md-dialog {
&.transition-in {
opacity: 1;
transition: $swift-ease-out;
transform: translate3d(0,0,0) scale(1.0);
}
&.transition-out {
transition: $swift-ease-out;
transform: translate3d(0,100%,0) scale(0.2);
}
opacity: 0;
min-width: 240px;
max-width: 80%;
max-height: 80%;
margin: auto;
position: relative;
overflow: hidden; // stop content from leaking out of dialog parent
box-shadow: $whiteframe-shadow-z5;
display: flex;
flex-direction: column;
md-content {
order: 1;
padding: 24px;
overflow: auto;
-webkit-overflow-scrolling: touch;
*:first-child {
margin-top: 0px;
}
}
.md-actions {
display: flex;
order: 2;
box-sizing: border-box;
align-items: center;
justify-content: flex-end;
padding: 16px 16px;
min-height: $baseline-grid * 5;
> * {
margin-left: 8px;
}
}
&.md-content-overflow .md-actions {
border-top: 1px solid;
}
}

View File

@@ -0,0 +1,479 @@
describe('$mdDialog', function() {
beforeEach(TestUtil.mockRaf);
beforeEach(module('material.components.dialog', 'ngAnimateMock'));
beforeEach(inject(function spyOnMdEffects($$q, $animate) {
spyOn($animate, 'leave').andCallFake(function(element) {
element.remove();
return $$q.when();
});
spyOn($animate, 'enter').andCallFake(function(element, parent) {
parent.append(element);
return $$q.when();
});
}));
describe('#alert()', function() {
hasConfigurationMethods('alert', [
'title', 'content', 'ariaLabel',
'ok', 'targetEvent'
]);
it('shows a basic alert dialog', inject(function($animate, $rootScope, $mdDialog, $mdConstant) {
var parent = angular.element('<div>');
var resolved = false;
$mdDialog.show(
$mdDialog.alert({
parent: parent
})
.title('Title')
.content('Hello world')
.ok('Next')
).then(function() {
resolved = true;
});
$rootScope.$apply();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
container.triggerHandler('transitionend');
$rootScope.$apply();
var title = angular.element(parent[0].querySelector('h2'));
expect(title.text()).toBe('Title');
var content = parent.find('p');
expect(content.text()).toBe('Hello world');
var buttons = parent.find('md-button');
expect(buttons.length).toBe(1);
expect(buttons.eq(0).text()).toBe('Next');
buttons.eq(0).triggerHandler('click');
$rootScope.$apply();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('h2').length).toBe(0);
expect(resolved).toBe(true);
}));
});
describe('#confirm()', function() {
hasConfigurationMethods('confirm', [
'title', 'content', 'ariaLabel',
'ok', 'cancel', 'targetEvent'
]);
it('shows a basic confirm dialog', inject(function($rootScope, $mdDialog, $animate, $mdConstant) {
var parent = angular.element('<div>');
var rejected = false;
$mdDialog.show(
$mdDialog.confirm({
parent: parent
})
.title('Title')
.content('Hello world')
.ok('Next')
.cancel('Forget it')
).catch(function() {
rejected = true;
});
$rootScope.$apply();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
container.triggerHandler('transitionend');
$rootScope.$apply();
var title = parent.find('h2');
expect(title.text()).toBe('Title');
var content = parent.find('p');
expect(content.text()).toBe('Hello world');
var buttons = parent.find('md-button');
expect(buttons.length).toBe(2);
expect(buttons.eq(0).text()).toBe('Next');
expect(buttons.eq(1).text()).toBe('Forget it');
buttons.eq(1).triggerHandler('click');
$rootScope.$digest();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('h2').length).toBe(0);
expect(rejected).toBe(true);
}));
});
describe('#build()', function() {
it('should support onComplete callbacks within `show()`', inject(function($mdDialog, $rootScope, $timeout, $mdConstant) {
var template = '<md-dialog>Hello</md-dialog>';
var parent = angular.element('<div>');
var ready = false;
$mdDialog.show({
template: template,
parent: parent,
onComplete: function(scope, element, options) {
expect( arguments.length ).toEqual( 3 );
ready = true;
}
});
$rootScope.$apply();
expect(ready).toBe( false );
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
container = angular.element(parent[0].querySelector('.md-dialog-container'));
expect(container.length).toBe(1);
expect(ready).toBe( true );
}));
it('should append dialog with container', inject(function($mdDialog, $rootScope) {
var template = '<md-dialog>Hello</md-dialog>';
var parent = angular.element('<div>');
$mdDialog.show({
template: template,
parent: parent
});
$rootScope.$apply();
var container = parent[0].querySelectorAll('.md-dialog-container');
expect(container.length).toBe(1);
}));
it('should escapeToClose == true', inject(function($mdDialog, $rootScope, $rootElement, $timeout, $animate, $mdConstant) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
escapeToClose: true
});
$rootScope.$apply();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(1);
$rootElement.triggerHandler({type: 'keyup',
keyCode: $mdConstant.KEY_CODE.ESCAPE
});
$timeout.flush();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(0);
}));
it('should escapeToClose == false', inject(function($mdDialog, $rootScope, $rootElement, $timeout, $animate, $mdConstant) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
escapeToClose: false
});
$rootScope.$apply();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
container.triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(1);
$rootElement.triggerHandler({ type: 'keyup', keyCode: $mdConstant.KEY_CODE.ESCAPE });
$timeout.flush();
$animate.triggerCallbacks();
expect(parent.find('md-dialog').length).toBe(1);
}));
it('should clickOutsideToClose == true', inject(function($mdDialog, $rootScope, $timeout, $animate, $mdConstant) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
clickOutsideToClose: true
});
$rootScope.$apply();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(1);
container.triggerHandler({
type: 'click',
target: container[0]
});
$timeout.flush();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(0);
}));
it('should clickOutsideToClose == false', inject(function($mdDialog, $rootScope, $timeout, $animate) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
clickOutsideToClose: false
});
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(1);
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
container.triggerHandler('click');
$timeout.flush();
$animate.triggerCallbacks();
expect(parent[0].querySelectorAll('md-dialog').length).toBe(1);
}));
it('should disableParentScroll == true', inject(function($mdDialog, $animate, $rootScope) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
disableParentScroll: true
});
$rootScope.$apply();
$animate.triggerCallbacks();
$rootScope.$apply();
expect(parent.css('overflow')).toBe('hidden');
}));
it('should hasBackdrop == true', inject(function($mdDialog, $animate, $rootScope) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
hasBackdrop: true
});
$rootScope.$apply();
$animate.triggerCallbacks();
$rootScope.$apply();
expect(parent.find('md-dialog').length).toBe(1);
expect(parent.find('md-backdrop').length).toBe(1);
}));
it('should hasBackdrop == false', inject(function($mdDialog, $rootScope) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog>',
parent: parent,
hasBackdrop: false
});
$rootScope.$apply();
expect(parent[0].querySelectorAll('md-dialog').length).toBe(1);
expect(parent[0].querySelectorAll('md-backdrop').length).toBe(0);
}));
it('should focus `md-button.dialog-close` on open', inject(function($mdDialog, $rootScope, $document, $timeout, $mdConstant) {
TestUtil.mockElementFocus(this);
var parent = angular.element('<div>');
$mdDialog.show({
template:
'<md-dialog>' +
'<div class="md-actions">' +
'<button class="dialog-close">Close</button>' +
'</div>' +
'</md-dialog>',
parent: parent
});
$rootScope.$apply();
$timeout.flush();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
container.triggerHandler('transitionend');
$rootScope.$apply();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect($document.activeElement).toBe(parent[0].querySelector('.dialog-close'));
}));
it('should focus the last `md-button` in md-actions open if no `.dialog-close`', inject(function($mdDialog, $rootScope, $document, $timeout, $mdConstant) {
TestUtil.mockElementFocus(this);
var parent = angular.element('<div>');
$mdDialog.show({
template:
'<md-dialog>' +
'<div class="md-actions">' +
'<button id="a">A</md-button>' +
'<button id="focus-target">B</md-button>' +
'</div>' +
'</md-dialog>',
parent: parent
});
$rootScope.$apply();
$timeout.flush();
var container = angular.element(parent[0].querySelector('.md-dialog-container'));
container.triggerHandler('transitionend');
$rootScope.$apply();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect($document.activeElement).toBe(parent[0].querySelector('#focus-target'));
}));
it('should only allow one open at a time', inject(function($mdDialog, $rootScope) {
var parent = angular.element('<div>');
$mdDialog.show({
template: '<md-dialog class="one">',
parent: parent
});
$rootScope.$apply();
expect(parent[0].querySelectorAll('md-dialog.one').length).toBe(1);
expect(parent[0].querySelectorAll('md-dialog.two').length).toBe(0);
$mdDialog.show({
template: '<md-dialog class="two">',
parent: parent
});
$rootScope.$apply();
parent.find('md-dialog').triggerHandler('transitionend');
$rootScope.$apply();
expect(parent[0].querySelectorAll('md-dialog.one').length).toBe(0);
expect(parent[0].querySelectorAll('md-dialog.two').length).toBe(1);
}));
it('should have the dialog role', inject(function($mdDialog, $rootScope) {
var template = '<md-dialog>Hello</md-dialog>';
var parent = angular.element('<div>');
$mdDialog.show({
template: template,
parent: parent
});
$rootScope.$apply();
var dialog = angular.element(parent[0].querySelectorAll('md-dialog'));
expect(dialog.attr('role')).toBe('dialog');
}));
it('should create an ARIA label if one is missing', inject(function($mdDialog, $rootScope) {
var template = '<md-dialog>Hello</md-dialog>';
var parent = angular.element('<div>');
$mdDialog.show({
template: template,
parent: parent
});
$rootScope.$apply();
angular.element(parent[0].querySelector('.md-dialog-container')).triggerHandler('transitionend');
$rootScope.$apply();
var dialog = angular.element(parent[0].querySelector('md-dialog'));
expect(dialog.attr('aria-label')).toEqual(dialog.text());
}));
it('should not modify an existing ARIA label', inject(function($mdDialog, $rootScope){
var template = '<md-dialog aria-label="Some Other Thing">Hello</md-dialog>';
var parent = angular.element('<div>');
$mdDialog.show({
template: template,
parent: parent
});
$rootScope.$apply();
var dialog = angular.element(parent[0].querySelector('md-dialog'));
expect(dialog.attr('aria-label')).not.toEqual(dialog.text());
expect(dialog.attr('aria-label')).toEqual('Some Other Thing');
}));
});
function hasConfigurationMethods(preset, methods) {
angular.forEach(methods, function(method) {
return it('supports config method #' + method, inject(function($mdDialog) {
var dialog = $mdDialog[preset]();
expect(typeof dialog[method]).toBe('function');
expect(dialog[method]()).toEqual(dialog);
}));
});
}
});
describe('$mdDialog with custom interpolation symbols', function() {
beforeEach(TestUtil.mockRaf);
beforeEach(module('material.components.dialog', 'ngAnimateMock'));
beforeEach(module(function($interpolateProvider) {
$interpolateProvider.startSymbol('[[').endSymbol(']]');
}));
it('displays #alert() correctly', inject(function($mdDialog, $rootScope) {
var parent = angular.element('<div>');
var dialog = $mdDialog.
alert({parent: parent}).
ariaLabel('test alert').
title('Title').
content('Hello, world !').
ok('OK');
$mdDialog.show(dialog);
$rootScope.$digest();
var mdContainer = angular.element(parent[0].querySelector('.md-dialog-container'));
var mdDialog = mdContainer.find('md-dialog');
var mdContent = mdDialog.find('md-content');
var title = mdContent.find('h2');
var content = mdContent.find('p');
var mdActions = angular.element(mdDialog[0].querySelector('.md-actions'));
var buttons = mdActions.find('md-button');
expect(mdDialog.attr('aria-label')).toBe('test alert');
expect(title.text()).toBe('Title');
expect(content.text()).toBe('Hello, world !');
expect(buttons.eq(0).text()).toBe('OK');
}));
it('displays #confirm() correctly', inject(function($mdDialog, $rootScope) {
var parent = angular.element('<div>');
var dialog = $mdDialog.
confirm({parent: parent}).
ariaLabel('test alert').
title('Title').
content('Hello, world !').
cancel('CANCEL').
ok('OK');
$mdDialog.show(dialog);
$rootScope.$digest();
var mdContainer = angular.element(parent[0].querySelector('.md-dialog-container'));
var mdDialog = mdContainer.find('md-dialog');
var mdContent = mdDialog.find('md-content');
var title = mdContent.find('h2');
var content = mdContent.find('p');
var mdActions = angular.element(mdDialog[0].querySelector('.md-actions'));
var buttons = mdActions.find('md-button');
expect(mdDialog.attr('aria-label')).toBe('test alert');
expect(title.text()).toBe('Title');
expect(content.text()).toBe('Hello, world !');
expect(buttons.eq(0).text()).toBe('CANCEL');
expect(buttons.eq(1).text()).toBe('OK');
}));
});

View File

@@ -0,0 +1,51 @@
<div ng-controller="AppCtrl">
<md-toolbar class="md-theme-light">
<h1 class="md-toolbar-tools">
<span>Full Bleed</span>
</h1>
</md-toolbar>
<md-content>
<md-list>
<md-item ng-repeat="item in messages">
<md-item-content>
<div class="md-tile-content">
<h3>{{item.what}}</h3>
<h4>{{item.who}}</h4>
<p>
{{item.notes}}
</p>
</div>
</md-item-content>
<md-divider ng-if="!$last"></md-divider>
</md-item>
</md-list>
</md-content>
<md-toolbar class="md-theme-light">
<h1 class="md-toolbar-tools">
<span>Inset</span>
</h1>
</md-toolbar>
<md-content>
<md-list>
<md-item ng-repeat="item in messages">
<md-item-content>
<div class="md-tile-left">
<img ng-src="{{item.face}}" class="face" alt="{{item.who}}">
</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 ng-if="!$last"></md-divider>
</md-item>
</md-list>
</md-content>
</div>

View File

@@ -0,0 +1,34 @@
angular.module('dividerDemo1', ['ngMaterial'])
.controller('AppCtrl', function($scope) {
$scope.messages = [{
face: '/img/list/60.jpeg',
what: 'Brunch this weekend?',
who: 'Min Li Chan',
when: '3:08PM',
notes: " I'll be in your neighborhood doing errands"
}, {
face: '/img/list/60.jpeg',
what: 'Brunch this weekend?',
who: 'Min Li Chan',
when: '3:08PM',
notes: " I'll be in your neighborhood doing errands"
}, {
face: '/img/list/60.jpeg',
what: 'Brunch this weekend?',
who: 'Min Li Chan',
when: '3:08PM',
notes: " I'll be in your neighborhood doing errands"
}, {
face: '/img/list/60.jpeg',
what: 'Brunch this weekend?',
who: 'Min Li Chan',
when: '3:08PM',
notes: " I'll be in your neighborhood doing errands"
}, {
face: '/img/list/60.jpeg',
what: 'Brunch this weekend?',
who: 'Min Li Chan',
when: '3:08PM',
notes: " I'll be in your neighborhood doing errands"
}];
});

View File

@@ -0,0 +1,6 @@
.face {
border-radius: 30px;
border: 1px solid #ddd;
width: 48px;
margin: 16px;
}

View File

@@ -0,0 +1,3 @@
md-divider.md-THEME_NAME-theme {
border-top-color: '{{foreground-4}}';
}

Some files were not shown because too many files have changed in this diff Show More