├── .gitignore ├── Procfile ├── .DS_Store ├── server ├── data.db └── config.js ├── client ├── img │ ├── ionic.png │ └── splash-background.png ├── lib │ └── ionic │ │ ├── fonts │ │ ├── ionicons.eot │ │ ├── ionicons.ttf │ │ └── ionicons.woff │ │ ├── version.json │ │ ├── scss │ │ ├── _progress.scss │ │ ├── ionicons │ │ │ ├── ionicons.scss │ │ │ ├── _ionicons-font.scss │ │ │ └── _ionicons-animation.scss │ │ ├── _backdrop.scss │ │ ├── ionic.scss │ │ ├── _button-bar.scss │ │ ├── _loading.scss │ │ ├── _slide-box.scss │ │ ├── _menu.scss │ │ ├── _radio.scss │ │ ├── _badge.scss │ │ ├── _action-sheet.scss │ │ ├── _modal.scss │ │ ├── _popup.scss │ │ ├── _list.scss │ │ ├── _select.scss │ │ ├── _range.scss │ │ ├── _grid.scss │ │ ├── _type.scss │ │ ├── _platform.scss │ │ ├── _popover.scss │ │ ├── _toggle.scss │ │ ├── _checkbox.scss │ │ ├── _util.scss │ │ ├── _form.scss │ │ ├── _button.scss │ │ ├── _reset.scss │ │ ├── _scaffolding.scss │ │ ├── _bar.scss │ │ ├── _tabs.scss │ │ ├── _mixins.scss │ │ └── _items.scss │ │ └── js │ │ ├── angular │ │ ├── angular-resource.min.js │ │ ├── angular-sanitize.min.js │ │ └── angular-animate.min.js │ │ └── angular-ui │ │ └── angular-ui-router.min.js ├── css │ └── style.css ├── app.js └── index.html ├── .env ├── README.md ├── app.json ├── package.json ├── LICENSE └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node server.js 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/.DS_Store -------------------------------------------------------------------------------- /server/data.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/server/data.db -------------------------------------------------------------------------------- /client/img/ionic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/client/img/ionic.png -------------------------------------------------------------------------------- /client/img/splash-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/client/img/splash-background.png -------------------------------------------------------------------------------- /client/lib/ionic/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/client/lib/ionic/fonts/ionicons.eot -------------------------------------------------------------------------------- /client/lib/ionic/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/client/lib/ionic/fonts/ionicons.ttf -------------------------------------------------------------------------------- /client/lib/ionic/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyric/mcontacts/master/client/lib/ionic/fonts/ionicons.woff -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | DATABASE_URL=postgres://qafqqhvcjyinsw:dErMS1knbF-BIfBfvItnJ03bPY@ec2-54-243-48-227.compute-1.amazonaws.com:5432/d19d91t9tv1h5o?ssl=true 2 | -------------------------------------------------------------------------------- /client/lib/ionic/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-beta.13", 3 | "codename": "lanthanum-leopard", 4 | "date": "2014-09-24", 5 | "time": "20:17:36" 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Heroku Connect demo app - mContacts 2 | 3 | This is a simple demo app showing how you can build a mobile app on Heroku which 4 | accesses data in your Salesforce account via _Heroku Connect_. 5 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_progress.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Progress 4 | * -------------------------------------------------- 5 | */ 6 | 7 | progress { 8 | display: block; 9 | margin: $progress-margin; 10 | width: $progress-width; 11 | } 12 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QuizLive Mobile Template", 3 | "description": "Heroku mobile app template using Node and AngularJS", 4 | "repository": "https://github.com/heroku/mobile-template1", 5 | "logo": "https://node-js-sample.herokuapp.com/node.svg", 6 | "keywords": ["node", "express", "angularjs","ionic","force.com"], 7 | "addons": [ 8 | "heroku-postgresql" 9 | ], 10 | "scripts": { 11 | } 12 | } -------------------------------------------------------------------------------- /client/lib/ionic/scss/ionicons/ionicons.scss: -------------------------------------------------------------------------------- 1 | @import "ionicons-variables"; 2 | /*! 3 | Ionicons, v1.5.2 4 | Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ 5 | https://twitter.com/benjsperry https://twitter.com/ionicframework 6 | MIT License: https://github.com/driftyco/ionicons 7 | */ 8 | 9 | @import "ionicons-font"; 10 | @import "ionicons-animation"; 11 | @import "ionicons-icons"; 12 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_backdrop.scss: -------------------------------------------------------------------------------- 1 | 2 | .backdrop { 3 | position: fixed; 4 | top: 0; 5 | left: 0; 6 | z-index: $z-index-backdrop; 7 | 8 | width: 100%; 9 | height: 100%; 10 | 11 | background-color: rgba(0,0,0,0.4); 12 | 13 | visibility: hidden; 14 | opacity: 0; 15 | 16 | &.visible { 17 | visibility: visible; 18 | } 19 | &.active { 20 | opacity: 1; 21 | } 22 | 23 | @include transition(0.1s opacity linear); 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mcontacts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "dependencies": { 7 | "body-parser": "^1.3.1", 8 | "bookshelf": "^0.7.7", 9 | "express": "^4.4.0", 10 | "knex": "^0.6.22", 11 | "method-override": "^2.2.0", 12 | "pg": "^3.4.4" 13 | }, 14 | "devDependencies": {}, 15 | "scripts": { 16 | }, 17 | "author": { 18 | "name":"Scott Persinger", 19 | "email":"scottp@heroku.com", 20 | "url":"https://twitter.com/persingerscott" 21 | }, 22 | "repository":"https://github.com/scottpersinger/mcontacts", 23 | "homepage":"https://github.com/scottpersinger/mcontacts", 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/ionic.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @import 4 | // Ionicons 5 | "ionicons/ionicons.scss", 6 | 7 | // Variables 8 | "mixins", 9 | "variables", 10 | 11 | // Base 12 | "reset", 13 | "scaffolding", 14 | "type", 15 | 16 | // Components 17 | "action-sheet", 18 | "backdrop", 19 | "bar", 20 | "tabs", 21 | "menu", 22 | "modal", 23 | "popover", 24 | "popup", 25 | "loading", 26 | "items", 27 | "list", 28 | "badge", 29 | "slide-box", 30 | 31 | // Forms 32 | "form", 33 | "checkbox", 34 | "toggle", 35 | "radio", 36 | "range", 37 | "select", 38 | "progress", 39 | 40 | // Buttons 41 | "button", 42 | "button-bar", 43 | 44 | // Util 45 | "animations", 46 | "grid", 47 | "util", 48 | "platform"; 49 | -------------------------------------------------------------------------------- /client/css/style.css: -------------------------------------------------------------------------------- 1 | /* Add your own CSS if you like */ 2 | .button { 3 | border-radius: 3px; 4 | font-weight: bold; 5 | } 6 | 7 | .button.button-positive { 8 | background-color: #00a1df; 9 | border-color: #00a1df; 10 | } 11 | 12 | /* home screen */ 13 | .home-content { 14 | background: url(/img/splash-background.png) no-repeat; 15 | background-size: cover; 16 | } 17 | 18 | .home-content > .scroll { 19 | display: flex; 20 | flex-direction: column; 21 | height: 100%; 22 | } 23 | 24 | .home-content h1 { 25 | font-size: 64px; 26 | font-weight: 700; 27 | text-align: center; 28 | text-transform: uppercase; 29 | } 30 | 31 | .home-content .row-logo { 32 | flex-grow: 1; 33 | } 34 | 35 | .home-content .row-buttons { 36 | flex-grow: 0; 37 | } 38 | 39 | .home-content .button:last-child { 40 | margin-bottom: 0; 41 | } -------------------------------------------------------------------------------- /client/lib/ionic/scss/ionicons/_ionicons-font.scss: -------------------------------------------------------------------------------- 1 | // Ionicons Font Path 2 | // -------------------------- 3 | 4 | @font-face { 5 | font-family: $ionicons-font-family; 6 | src:url("#{$ionicons-font-path}/ionicons.eot?v=#{$ionicons-version}"); 7 | src:url("#{$ionicons-font-path}/ionicons.eot?v=#{$ionicons-version}#iefix") format("embedded-opentype"), 8 | url("#{$ionicons-font-path}/ionicons.ttf?v=#{$ionicons-version}") format("truetype"), 9 | url("#{$ionicons-font-path}/ionicons.woff?v=#{$ionicons-version}") format("woff"), 10 | url("#{$ionicons-font-path}/ionicons.svg?v=#{$ionicons-version}#Ionicons") format("svg"); 11 | font-weight: normal; 12 | font-style: normal; 13 | } 14 | 15 | .ion { 16 | display: inline-block; 17 | font-family: $ionicons-font-family; 18 | speak: none; 19 | font-style: normal; 20 | font-weight: normal; 21 | font-variant: normal; 22 | text-transform: none; 23 | text-rendering: auto; 24 | line-height: 1; 25 | -webkit-font-smoothing: antialiased; 26 | -moz-osx-font-smoothing: grayscale; 27 | } -------------------------------------------------------------------------------- /client/lib/ionic/scss/_button-bar.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Button Bar 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .button-bar { 8 | @include display-flex(); 9 | @include flex(1); 10 | width: 100%; 11 | 12 | &.button-bar-inline { 13 | display: block; 14 | width: auto; 15 | 16 | @include clearfix(); 17 | 18 | > .button { 19 | width: auto; 20 | display: inline-block; 21 | float: left; 22 | } 23 | } 24 | } 25 | 26 | .button-bar > .button { 27 | @include flex(1); 28 | display: block; 29 | 30 | overflow: hidden; 31 | 32 | padding: 0 16px; 33 | 34 | width: 0; 35 | 36 | border-width: 1px 0px 1px 1px; 37 | border-radius: 0; 38 | text-align: center; 39 | text-overflow: ellipsis; 40 | white-space: nowrap; 41 | 42 | &:before, 43 | .icon:before { 44 | line-height: 44px; 45 | } 46 | 47 | &:first-child { 48 | border-radius: 2px 0px 0px 2px; 49 | } 50 | &:last-child { 51 | border-right-width: 1px; 52 | border-radius: 0px 2px 2px 0px; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License: 2 | 3 | Copyright (C) 2014 Heroku, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /client/lib/ionic/scss/_loading.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Loading 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .loading-container { 8 | position: absolute; 9 | left: 0; 10 | top: 0; 11 | right: 0; 12 | bottom: 0; 13 | 14 | z-index: $z-index-loading; 15 | 16 | @include display-flex(); 17 | @include justify-content(center); 18 | @include align-items(center); 19 | 20 | @include transition(0.2s opacity linear); 21 | visibility: hidden; 22 | opacity: 0; 23 | 24 | &:not(.visible) .icon { 25 | display: none; 26 | } 27 | &.visible { 28 | visibility: visible; 29 | } 30 | &.active { 31 | opacity: 1; 32 | } 33 | 34 | .loading { 35 | padding: $loading-padding; 36 | 37 | border-radius: $loading-border-radius; 38 | background-color: $loading-bg-color; 39 | 40 | color: $loading-text-color; 41 | 42 | text-align: center; 43 | text-overflow: ellipsis; 44 | font-size: $loading-font-size; 45 | 46 | h1, h2, h3, h4, h5, h6 { 47 | color: $loading-text-color; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_slide-box.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Slide Box 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .slider { 8 | position: relative; 9 | visibility: hidden; 10 | // Make sure items don't scroll over ever 11 | overflow: hidden; 12 | } 13 | 14 | .slider-slides { 15 | position: relative; 16 | height: 100%; 17 | } 18 | 19 | .slider-slide { 20 | position: relative; 21 | display: block; 22 | float: left; 23 | width: 100%; 24 | height: 100%; 25 | vertical-align: top; 26 | } 27 | 28 | .slider-slide-image { 29 | > img { 30 | width: 100%; 31 | } 32 | } 33 | 34 | .slider-pager { 35 | position: absolute; 36 | bottom: 20px; 37 | z-index: $z-index-slider-pager; 38 | width: 100%; 39 | height: 15px; 40 | text-align: center; 41 | 42 | .slider-pager-page { 43 | display: inline-block; 44 | margin: 0px 3px; 45 | width: 15px; 46 | color: #000; 47 | text-decoration: none; 48 | 49 | opacity: 0.3; 50 | 51 | &.active { 52 | @include transition(opacity 0.4s ease-in); 53 | opacity: 1; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_menu.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Menus 4 | * -------------------------------------------------- 5 | * Side panel structure 6 | */ 7 | 8 | .menu { 9 | position: absolute; 10 | top: 0; 11 | bottom: 0; 12 | z-index: $z-index-menu; 13 | overflow: hidden; 14 | 15 | min-height: 100%; 16 | max-height: 100%; 17 | width: $menu-width; 18 | 19 | background-color: $menu-bg; 20 | 21 | .scroll-content { 22 | z-index: $z-index-menu-scroll-content; 23 | } 24 | 25 | .bar-header { 26 | z-index: $z-index-menu-bar-header; 27 | } 28 | } 29 | 30 | .menu-content { 31 | @include transform(none); 32 | box-shadow: $menu-side-shadow; 33 | } 34 | 35 | .menu-open .menu-content .pane, 36 | .menu-open .menu-content .scroll-content { 37 | pointer-events: none; 38 | } 39 | 40 | .grade-b .menu-content, 41 | .grade-c .menu-content { 42 | @include box-sizing(content-box); 43 | right: -1px; 44 | left: -1px; 45 | border-right: 1px solid #ccc; 46 | border-left: 1px solid #ccc; 47 | box-shadow: none; 48 | } 49 | 50 | .menu-left { 51 | left: 0; 52 | } 53 | 54 | .menu-right { 55 | right: 0; 56 | } 57 | 58 | .aside-open.aside-resizing .menu-right { 59 | display: none; 60 | } 61 | 62 | .menu-animated { 63 | @include transition-transform($menu-animation-speed ease); 64 | } 65 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_radio.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Radio Button Inputs 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .item-radio { 8 | padding: 0; 9 | 10 | &:hover { 11 | cursor: pointer; 12 | } 13 | } 14 | 15 | .item-radio .item-content { 16 | /* give some room to the right for the checkmark icon */ 17 | padding-right: $item-padding * 4; 18 | } 19 | 20 | .item-radio .radio-icon { 21 | /* checkmark icon will be hidden by default */ 22 | position: absolute; 23 | top: 0; 24 | right: 0; 25 | z-index: $z-index-item-radio; 26 | visibility: hidden; 27 | padding: $item-padding - 2; 28 | height: 100%; 29 | font-size: 24px; 30 | } 31 | 32 | .item-radio input { 33 | /* hide any radio button inputs elements (the ugly circles) */ 34 | position: absolute; 35 | left: -9999px; 36 | 37 | &:checked ~ .item-content { 38 | /* style the item content when its checked */ 39 | background: #f7f7f7; 40 | } 41 | 42 | &:checked ~ .radio-icon { 43 | /* show the checkmark icon when its checked */ 44 | visibility: visible; 45 | } 46 | } 47 | 48 | // Hack for Android to correctly display the checked item 49 | // http://timpietrusky.com/advanced-checkbox-hack 50 | .platform-android.grade-b .item-radio, 51 | .platform-android.grade-c .item-radio { 52 | -webkit-animation: androidCheckedbugfix infinite 1s; 53 | } 54 | @-webkit-keyframes androidCheckedbugfix { 55 | from { padding: 0; } 56 | to { padding: 0; } 57 | } 58 | -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | DEBUG = true; 2 | 3 | exports.db_client = 'pg'; 4 | exports.db_url = process.env.DATABASE_URL; // + "?ssl=true"; 5 | exports.DEBUG = DEBUG; 6 | exports.SQL_DEBUG = true; 7 | 8 | exports.knex_options = { 9 | client: exports.db_client, 10 | connection: exports.db_url, 11 | debug: exports.SQL_DEBUG 12 | }; 13 | 14 | if (process.env.SF_OAUTH_CLIENT_ID) { 15 | salesforce = { 16 | username: process.env.SF_USERNAME, 17 | password: process.env.SF_PASSWORD, 18 | token: process.env.SF_TOKEN, 19 | clientId: process.env.SF_OAUTH_CLIENT_ID, 20 | clientSecret: process.env.SF_OAUTH_CLIENT_SECRET, 21 | redirectUri: process.env.SF_OAUTH_REDIRECT_URI, 22 | environment: 'production' 23 | } 24 | for (var k in salesforce) { 25 | if (!salesforce[k]) { 26 | console.log("[warn] config var " + k + " is not set. Force.com connection may fail."); 27 | } 28 | } 29 | } else { 30 | salesforce = null; 31 | } 32 | 33 | exports.salesforce = salesforce; 34 | 35 | exports.debug = function() { 36 | if (DEBUG) { 37 | console.log.apply(console, ["[debug]"].concat(Array.prototype.slice.call(arguments, 0))); 38 | } 39 | } 40 | 41 | exports.info = function() { 42 | if (DEBUG) { 43 | console.log.apply(console, ["[info]"].concat(Array.prototype.slice.call(arguments, 0))); 44 | } 45 | } 46 | 47 | exports.warn = function() { 48 | console.log.apply(console, ["[WARN]"].concat(Array.prototype.slice.call(arguments, 0))); 49 | } 50 | 51 | exports.error = function() { 52 | console.log.apply(console, ["[ERROR]"].concat(Array.prototype.slice.call(arguments, 0))); 53 | } -------------------------------------------------------------------------------- /client/lib/ionic/scss/_badge.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Badges 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .badge { 8 | @include badge-style($badge-default-bg, $badge-default-text); 9 | z-index: $z-index-badge; 10 | display: inline-block; 11 | padding: 3px 8px; 12 | min-width: 10px; 13 | border-radius: $badge-border-radius; 14 | vertical-align: baseline; 15 | text-align: center; 16 | white-space: nowrap; 17 | font-weight: $badge-font-weight; 18 | font-size: $badge-font-size; 19 | line-height: $badge-line-height; 20 | 21 | &:empty { 22 | display: none; 23 | } 24 | } 25 | 26 | //Be sure to override specificity of rule that 'badge color matches tab color by default' 27 | .tabs .tab-item .badge, 28 | .badge { 29 | &.badge-light { 30 | @include badge-style($badge-light-bg, $badge-light-text); 31 | } 32 | &.badge-stable { 33 | @include badge-style($badge-stable-bg, $badge-stable-text); 34 | } 35 | &.badge-positive { 36 | @include badge-style($badge-positive-bg, $badge-positive-text); 37 | } 38 | &.badge-calm { 39 | @include badge-style($badge-calm-bg, $badge-calm-text); 40 | } 41 | &.badge-assertive { 42 | @include badge-style($badge-assertive-bg, $badge-assertive-text); 43 | } 44 | &.badge-balanced { 45 | @include badge-style($badge-balanced-bg, $badge-balanced-text); 46 | } 47 | &.badge-energized { 48 | @include badge-style($badge-energized-bg, $badge-energized-text); 49 | } 50 | &.badge-royal { 51 | @include badge-style($badge-royal-bg, $badge-royal-text); 52 | } 53 | &.badge-dark { 54 | @include badge-style($badge-dark-bg, $badge-dark-text); 55 | } 56 | } 57 | 58 | // Quick fix for labels/badges in buttons 59 | .button .badge { 60 | position: relative; 61 | top: -1px; 62 | } 63 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_action-sheet.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Action Sheets 3 | * -------------------------------------------------- 4 | */ 5 | 6 | .action-sheet-backdrop { 7 | @include transition(background-color 300ms ease-in-out); 8 | position: fixed; 9 | top: 0; 10 | left: 0; 11 | z-index: $z-index-action-sheet; 12 | width: 100%; 13 | height: 100%; 14 | background-color: rgba(0,0,0,0); 15 | 16 | &.active { 17 | background-color: rgba(0,0,0,0.5); 18 | } 19 | } 20 | 21 | .action-sheet-wrapper { 22 | @include translate3d(0, 100%, 0); 23 | @include transition(all ease-in-out 300ms); 24 | position: absolute; 25 | bottom: 0; 26 | width: 100%; 27 | } 28 | 29 | .action-sheet-up { 30 | @include translate3d(0, 0, 0); 31 | } 32 | 33 | .action-sheet { 34 | margin-left: 15px; 35 | margin-right: 15px; 36 | width: auto; 37 | z-index: $z-index-action-sheet; 38 | overflow: hidden; 39 | 40 | .button { 41 | display: block; 42 | padding: 1px; 43 | width: 100%; 44 | border-radius: 0; 45 | 46 | background-color: transparent; 47 | 48 | color: $positive; 49 | font-size: 18px; 50 | 51 | &.destructive { 52 | color: $assertive; 53 | } 54 | } 55 | } 56 | 57 | .action-sheet-title { 58 | padding: 10px; 59 | color: lighten($base-color, 40%); 60 | text-align: center; 61 | font-size: 12px; 62 | } 63 | 64 | .action-sheet-group { 65 | margin-bottom: 5px; 66 | border-radius: $sheet-border-radius; 67 | background-color: #fff; 68 | .button { 69 | border-width: 1px 0px 0px 0px; 70 | border-radius: 0; 71 | 72 | &.active { 73 | background-color: transparent; 74 | color: inherit; 75 | } 76 | } 77 | .button:first-child:last-child { 78 | border-width: 0; 79 | } 80 | } 81 | 82 | .action-sheet-open { 83 | pointer-events: none; 84 | 85 | &.modal-open .modal { 86 | pointer-events: none; 87 | } 88 | 89 | .action-sheet-backdrop { 90 | pointer-events: auto; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/ionicons/_ionicons-animation.scss: -------------------------------------------------------------------------------- 1 | // Animation Icons 2 | // -------------------------- 3 | 4 | .#{$ionicons-prefix}spin { 5 | -webkit-animation: spin 1s infinite linear; 6 | -moz-animation: spin 1s infinite linear; 7 | -o-animation: spin 1s infinite linear; 8 | animation: spin 1s infinite linear; 9 | } 10 | 11 | @-moz-keyframes spin { 12 | 0% { -moz-transform: rotate(0deg); } 13 | 100% { -moz-transform: rotate(359deg); } 14 | } 15 | @-webkit-keyframes spin { 16 | 0% { -webkit-transform: rotate(0deg); } 17 | 100% { -webkit-transform: rotate(359deg); } 18 | } 19 | @-o-keyframes spin { 20 | 0% { -o-transform: rotate(0deg); } 21 | 100% { -o-transform: rotate(359deg); } 22 | } 23 | @-ms-keyframes spin { 24 | 0% { -ms-transform: rotate(0deg); } 25 | 100% { -ms-transform: rotate(359deg); } 26 | } 27 | @keyframes spin { 28 | 0% { transform: rotate(0deg); } 29 | 100% { transform: rotate(359deg); } 30 | } 31 | 32 | 33 | .#{$ionicons-prefix}loading-a, 34 | .#{$ionicons-prefix}loading-b, 35 | .#{$ionicons-prefix}loading-c, 36 | .#{$ionicons-prefix}loading-d, 37 | .#{$ionicons-prefix}looping, 38 | .#{$ionicons-prefix}refreshing, 39 | .#{$ionicons-prefix}ios7-reloading { 40 | @extend .ion; 41 | @extend .#{$ionicons-prefix}spin; 42 | } 43 | 44 | .#{$ionicons-prefix}loading-a { 45 | -webkit-animation-timing-function: steps(8, start); 46 | -moz-animation-timing-function: steps(8, start); 47 | animation-timing-function: steps(8, start); 48 | } 49 | 50 | .#{$ionicons-prefix}loading-a:before { 51 | @extend .#{$ionicons-prefix}load-a:before; 52 | } 53 | 54 | .#{$ionicons-prefix}loading-b:before { 55 | @extend .#{$ionicons-prefix}load-b:before; 56 | } 57 | 58 | .#{$ionicons-prefix}loading-c:before { 59 | @extend .#{$ionicons-prefix}load-c:before; 60 | } 61 | 62 | .#{$ionicons-prefix}loading-d:before { 63 | @extend .#{$ionicons-prefix}load-d:before; 64 | } 65 | 66 | .#{$ionicons-prefix}looping:before { 67 | @extend .#{$ionicons-prefix}loop:before; 68 | } 69 | 70 | .#{$ionicons-prefix}refreshing:before { 71 | @extend .#{$ionicons-prefix}refresh:before; 72 | } 73 | 74 | .#{$ionicons-prefix}ios7-reloading:before { 75 | @extend .#{$ionicons-prefix}ios7-reload:before; 76 | } 77 | -------------------------------------------------------------------------------- /client/app.js: -------------------------------------------------------------------------------- 1 | angular.module('mcontacts', ['ionic', 'ngResource']) 2 | 3 | .config(function($stateProvider, $urlRouterProvider, $httpProvider) { 4 | 5 | // ************ APP ROUTING ***************** 6 | 7 | $stateProvider.state('tabs', { 8 | url: "/tab", 9 | abstract: true, 10 | templateUrl: "tabs-container.html" 11 | }) 12 | 13 | .state('tabs.contacts', { 14 | url: '/contacts', 15 | views: { 16 | 'tab-contacts': { 17 | templateUrl: 'tab-contacts.html', 18 | controller: 'ContactsCtrl' 19 | } 20 | } 21 | }) 22 | 23 | .state('tabs.contact-detail', { 24 | url:'/contacts/:contactId', 25 | views: { 26 | 'tab-contacts': { 27 | templateUrl: 'contact-detail.html', 28 | controller: 'ContactDetailCtrl' 29 | } 30 | } 31 | }) 32 | 33 | // if none of the above states are matched, use this as the fallback 34 | $urlRouterProvider.otherwise('/tab/contacts'); 35 | 36 | }) 37 | 38 | // ************ CONTROLLERS ***************** 39 | 40 | .controller('ContactsCtrl', function($scope, $location, Contact) { 41 | $scope.contacts = Contact.query(); 42 | 43 | $scope.doRefresh = function() { 44 | Contact.query(function(contacts) { 45 | $scope.contacts = contacts; 46 | $scope.$broadcast('scroll.refreshComplete'); 47 | }); 48 | } 49 | 50 | }) 51 | 52 | .controller('ContactDetailCtrl', function($scope, $stateParams, $ionicModal, Contact) { 53 | $scope.contact = Contact.get({contactId:$stateParams.contactId}); 54 | 55 | $scope.edit = function() { 56 | $scope.modal.show(); 57 | } 58 | 59 | $ionicModal.fromTemplateUrl('contact-edit.html', { 60 | scope: $scope, 61 | animation: 'slide-in-up' 62 | }).then(function(modal) { 63 | $scope.modal = modal; 64 | }); 65 | 66 | $scope.save = function() { 67 | new Contact($scope.contact).$save(function() { 68 | $scope.modal.hide(); 69 | }); 70 | } 71 | 72 | $scope.closeModal = function() { 73 | $scope.modal.hide(); 74 | }; 75 | 76 | }) 77 | 78 | // ************ SERVER RESOURCES (via Ajax) ***************** 79 | 80 | .factory('Contact', function($resource) { 81 | return $resource('/resource/contacts/:contactId', null); 82 | }) 83 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'), 2 | config = require('./server/config'), 3 | express = require('express'), 4 | bodyParser = require('body-parser'), 5 | methodOverride = require('method-override'), 6 | path = require('path'), 7 | knex = require('knex')(config.knex_options) 8 | ; 9 | 10 | console.log("Connecting to ", config.knex_options); 11 | 12 | /********************* APP SETUP *****************************/ 13 | 14 | app = express(); 15 | server = http.createServer(app); 16 | 17 | logger = { 18 | debug: config.debug, 19 | warn: config.warn, 20 | error: config.error 21 | }; 22 | 23 | 24 | app.use(bodyParser()); 25 | app.use(methodOverride()); 26 | 27 | app.use(express.static(path.join(__dirname, 'client/'))); 28 | 29 | // Logging 30 | app.use(function(req, res, next) { 31 | logger.debug(req.method, req.url); 32 | next(); 33 | }); 34 | 35 | app.use(function(err, req, res, next) { 36 | logger.error(err.stack); 37 | res.status(500).send(err.message); 38 | }); 39 | 40 | 41 | /********************* ROUTES *****************************/ 42 | // Simple hack to only allow admin to load the admin page. 43 | 44 | var contactTable = 'salesforce.contact'; 45 | 46 | app.get('/resource/contacts', function(req, res) { 47 | knex(contactTable).select().where(knex.raw('email is not null')).orderBy('lastname').limit(50).then(function(rows) { 48 | res.json(rows); 49 | }).catch(function(err) { 50 | console.log(err); 51 | res.status(500).send(err); 52 | }); 53 | }); 54 | 55 | app.get('/resource/contacts/:contactId', function(req, res) { 56 | knex(contactTable).select().where({id: req.params.contactId}).then(function(rows) { 57 | if (rows.length > 0) { 58 | res.json(rows[0]); 59 | } else { 60 | res.json({}); 61 | } 62 | }); 63 | }); 64 | 65 | app.post('/resource/contacts', function(req, res) { 66 | knex(contactTable).where({id: req.body.id}).update(req.body).then(function() { 67 | res.send('OK'); 68 | }).catch(function(err) { 69 | res.status(500).send(err); 70 | }); 71 | }); 72 | 73 | /********************* SERVER STARTT *****************************/ 74 | 75 | app.set('port', process.env.PORT || 5000); 76 | 77 | server.listen(app.get('port'), function() { 78 | console.log('Express server listening on port ' + app.get('port')); 79 | }); 80 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_modal.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Modals 4 | * -------------------------------------------------- 5 | * Modals are independent windows that slide in from off-screen. 6 | */ 7 | 8 | .modal-backdrop { 9 | @include transition(background-color 300ms ease-in-out); 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | z-index: $z-index-modal; 14 | width: 100%; 15 | height: 100%; 16 | background-color: $modal-backdrop-bg-inactive; 17 | 18 | &.active { 19 | background-color: $modal-backdrop-bg-active; 20 | } 21 | } 22 | 23 | .modal { 24 | display: block; 25 | position: absolute; 26 | top: 0; 27 | z-index: $z-index-modal; 28 | overflow: hidden; 29 | min-height: 100%; 30 | width: 100%; 31 | background-color: $modal-bg-color; 32 | } 33 | 34 | @media (min-width: $modal-inset-mode-break-point) { 35 | // inset mode is when the modal doesn't fill the entire 36 | // display but instead is centered within a large display 37 | .modal { 38 | top: $modal-inset-mode-top; 39 | right: $modal-inset-mode-right; 40 | bottom: $modal-inset-mode-bottom; 41 | left: $modal-inset-mode-left; 42 | overflow: visible; 43 | min-height: $modal-inset-mode-min-height; 44 | width: (100% - $modal-inset-mode-left - $modal-inset-mode-right); 45 | } 46 | 47 | .modal.ng-leave-active { 48 | bottom: 0; 49 | } 50 | 51 | // remove ios header padding from inset header 52 | .platform-ios.platform-cordova .modal-wrapper .modal{ 53 | .bar-header:not(.bar-subheader) { 54 | height: $bar-height; 55 | > * { 56 | margin-top: 0; 57 | } 58 | } 59 | .tabs-top > .tabs, 60 | .tabs.tabs-top { 61 | top: $bar-height; 62 | } 63 | .has-header, 64 | .bar-subheader { 65 | top: $bar-height; 66 | } 67 | .has-subheader { 68 | top: (2 * $bar-height); 69 | } 70 | .has-tabs-top { 71 | top: $bar-height + $tabs-height; 72 | } 73 | .has-header.has-subheader.has-tabs-top { 74 | top: 2 * $bar-height + $tabs-height; 75 | } 76 | } 77 | } 78 | 79 | // disable clicks on all but the modal 80 | .modal-open { 81 | pointer-events: none; 82 | 83 | .modal, 84 | .modal-backdrop { 85 | pointer-events: auto; 86 | } 87 | // prevent clicks on modal when loading overlay is active though 88 | &.loading-active { 89 | .modal, 90 | .modal-backdrop { 91 | pointer-events: none; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_popup.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Popups 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .popup-container { 8 | position: absolute; 9 | top: 0; 10 | left: 0; 11 | bottom: 0; 12 | right: 0; 13 | background: rgba(0,0,0,0); 14 | 15 | @include display-flex(); 16 | @include justify-content(center); 17 | @include align-items(center); 18 | 19 | z-index: $z-index-popup; 20 | 21 | // Start hidden 22 | visibility: hidden; 23 | &.popup-showing { 24 | visibility: visible; 25 | } 26 | 27 | &.popup-hidden .popup { 28 | @include animation-name(scaleOut); 29 | @include animation-duration($popup-leave-animation-duration); 30 | @include animation-timing-function(ease-in-out); 31 | @include animation-fill-mode(both); 32 | } 33 | 34 | &.active .popup { 35 | @include animation-name(superScaleIn); 36 | @include animation-duration($popup-enter-animation-duration); 37 | @include animation-timing-function(ease-in-out); 38 | @include animation-fill-mode(both); 39 | } 40 | 41 | .popup { 42 | width: $popup-width; 43 | max-width: 100%; 44 | max-height: 90%; 45 | 46 | border-radius: $popup-border-radius; 47 | background-color: $popup-background-color; 48 | 49 | @include display-flex(); 50 | @include flex-direction(column); 51 | } 52 | } 53 | 54 | .popup-head { 55 | padding: 15px 10px; 56 | border-bottom: 1px solid #eee; 57 | text-align: center; 58 | } 59 | .popup-title { 60 | margin: 0; 61 | padding: 0; 62 | font-size: 15px; 63 | } 64 | .popup-sub-title { 65 | margin: 5px 0 0 0; 66 | padding: 0; 67 | font-weight: normal; 68 | font-size: 11px; 69 | } 70 | .popup-body { 71 | padding: 10px; 72 | overflow: scroll; 73 | } 74 | 75 | .popup-buttons { 76 | @include display-flex(); 77 | @include flex-direction(row); 78 | padding: 10px; 79 | min-height: $popup-button-min-height + 20; 80 | 81 | .button { 82 | @include flex(1); 83 | display: block; 84 | min-height: $popup-button-min-height; 85 | border-radius: $popup-button-border-radius; 86 | line-height: $popup-button-line-height; 87 | 88 | margin-right: 5px; 89 | &:last-child { 90 | margin-right: 0px; 91 | } 92 | } 93 | } 94 | 95 | .popup-open { 96 | pointer-events: none; 97 | 98 | &.modal-open .modal { 99 | pointer-events: none; 100 | } 101 | 102 | .popup-backdrop, .popup { 103 | pointer-events: auto; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_list.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Lists 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .list { 8 | position: relative; 9 | padding-top: $item-border-width; 10 | padding-bottom: $item-border-width; 11 | padding-left: 0; // reset padding because ul and ol 12 | margin-bottom: 20px; 13 | } 14 | .list:last-child { 15 | margin-bottom: 0px; 16 | &.card{ 17 | margin-bottom:40px; 18 | } 19 | } 20 | 21 | 22 | /** 23 | * List Header 24 | * -------------------------------------------------- 25 | */ 26 | 27 | .list-header { 28 | margin-top: $list-header-margin-top; 29 | padding: $list-header-padding; 30 | background-color: $list-header-bg; 31 | color: $list-header-color; 32 | font-weight: bold; 33 | } 34 | 35 | // when its a card make sure it doesn't duplicate top and bottom borders 36 | .card.list .list-item { 37 | padding-right: 1px; 38 | padding-left: 1px; 39 | } 40 | 41 | 42 | /** 43 | * Cards and Inset Lists 44 | * -------------------------------------------------- 45 | * A card and list-inset are close to the same thing, except a card as a box shadow. 46 | */ 47 | 48 | .card, 49 | .list-inset { 50 | overflow: hidden; 51 | margin: ($content-padding * 2) $content-padding; 52 | border-radius: $card-border-radius; 53 | background-color: $card-body-bg; 54 | } 55 | 56 | .card { 57 | padding-top: $item-border-width; 58 | padding-bottom: $item-border-width; 59 | box-shadow: 0 1px 2px rgba(0, 0, 0, .10); 60 | } 61 | 62 | .padding { 63 | .card, .list-inset { 64 | margin-left: 0; 65 | margin-right: 0; 66 | } 67 | } 68 | 69 | .card .item, 70 | .list-inset .item, 71 | .padding > .list .item 72 | { 73 | &:first-child { 74 | border-top-left-radius: $card-border-radius; 75 | border-top-right-radius: $card-border-radius; 76 | 77 | .item-content { 78 | border-top-left-radius: $card-border-radius; 79 | border-top-right-radius: $card-border-radius; 80 | } 81 | } 82 | &:last-child { 83 | border-bottom-right-radius: $card-border-radius; 84 | border-bottom-left-radius: $card-border-radius; 85 | 86 | .item-content { 87 | border-bottom-right-radius: $card-border-radius; 88 | border-bottom-left-radius: $card-border-radius; 89 | } 90 | } 91 | } 92 | 93 | .card .item:last-child, 94 | .list-inset .item:last-child { 95 | margin-bottom: $item-border-width * -1; 96 | } 97 | 98 | .card .item, 99 | .list-inset .item, 100 | .padding > .list .item, 101 | .padding-horizontal > .list .item { 102 | margin-right: 0; 103 | margin-left: 0; 104 | 105 | &.item-input input { 106 | padding-right: 44px; 107 | } 108 | } 109 | .padding-left > .list .item { 110 | margin-left: 0; 111 | } 112 | .padding-right > .list .item { 113 | margin-right: 0; 114 | } 115 | -------------------------------------------------------------------------------- /client/lib/ionic/js/angular/angular-resource.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.25 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&& 7 | b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f * { 111 | margin-top: $ios-statusbar-height; 112 | } 113 | } 114 | .tabs-top > .tabs, 115 | .tabs.tabs-top { 116 | top: $bar-height + $ios-statusbar-height; 117 | } 118 | 119 | .has-header, 120 | .bar-subheader { 121 | top: $bar-height + $ios-statusbar-height; 122 | } 123 | .has-subheader { 124 | top: (2 * $bar-height) + $ios-statusbar-height; 125 | } 126 | .has-tabs-top { 127 | top: $bar-height + $tabs-height + $ios-statusbar-height; 128 | } 129 | .has-header.has-subheader.has-tabs-top { 130 | top: 2 * $bar-height + $tabs-height + $ios-statusbar-height; 131 | } 132 | } 133 | &.status-bar-hide { 134 | // Cordova doesn't adjust the body height correctly, this makes up for it 135 | margin-bottom: 20px; 136 | } 137 | } 138 | 139 | @media (orientation:landscape) { 140 | .platform-ios.platform-browser.platform-ipad { 141 | position: fixed; // required for iPad 7 Safari 142 | } 143 | } 144 | 145 | .platform-c:not(.enable-transitions) * { 146 | // disable transitions on grade-c devices (Android 2) 147 | -webkit-transition: none !important; 148 | transition: none !important; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_popover.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Popovers 4 | * -------------------------------------------------- 5 | * Popovers are independent views which float over content 6 | */ 7 | 8 | .popover-backdrop { 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | z-index: $z-index-popover; 13 | width: 100%; 14 | height: 100%; 15 | background-color: $popover-backdrop-bg-inactive; 16 | 17 | &.active { 18 | background-color: $popover-backdrop-bg-active; 19 | } 20 | } 21 | 22 | .popover { 23 | position: absolute; 24 | top: 25%; 25 | left: 50%; 26 | z-index: $z-index-popover; 27 | display: block; 28 | margin-top: 12px; 29 | margin-left: -$popover-width / 2; 30 | height: $popover-height; 31 | width: $popover-width; 32 | background-color: $popover-bg-color; 33 | box-shadow: $popover-box-shadow; 34 | opacity: 0; 35 | 36 | .item:first-child { 37 | border-top: 0; 38 | } 39 | 40 | .item:last-child { 41 | border-bottom: 0; 42 | } 43 | 44 | &.popover-bottom { 45 | margin-top: -12px; 46 | } 47 | } 48 | 49 | 50 | // Set popover border-radius 51 | .popover, 52 | .popover .bar-header { 53 | border-radius: $popover-border-radius; 54 | } 55 | .popover .scroll-content { 56 | z-index: 1; 57 | margin: 2px 0; 58 | } 59 | .popover .bar-header { 60 | border-bottom-right-radius: 0; 61 | border-bottom-left-radius: 0; 62 | } 63 | .popover .has-header { 64 | border-top-right-radius: 0; 65 | border-top-left-radius: 0; 66 | } 67 | .popover-arrow { 68 | display: none; 69 | } 70 | 71 | 72 | // iOS Popover 73 | .platform-ios { 74 | 75 | .popover { 76 | box-shadow: $popover-box-shadow-ios; 77 | } 78 | 79 | .popover, 80 | .popover .bar-header { 81 | border-radius: $popover-border-radius-ios; 82 | } 83 | .popover .scroll-content { 84 | margin: 8px 0; 85 | border-radius: $popover-border-radius-ios; 86 | } 87 | .popover .scroll-content.has-header { 88 | margin-top: 0; 89 | } 90 | .popover-arrow { 91 | position: absolute; 92 | display: block; 93 | top: -17px; 94 | width: 30px; 95 | height: 19px; 96 | overflow: hidden; 97 | 98 | &:after { 99 | position: absolute; 100 | top: 12px; 101 | left: 5px; 102 | width: 20px; 103 | height: 20px; 104 | background-color: $popover-bg-color; 105 | border-radius: 3px; 106 | content: ''; 107 | @include rotate(-45deg); 108 | } 109 | } 110 | .popover-bottom .popover-arrow { 111 | top: auto; 112 | bottom: -10px; 113 | &:after { 114 | top: -6px; 115 | } 116 | } 117 | } 118 | 119 | 120 | // Android Popover 121 | .platform-android { 122 | 123 | .popover { 124 | margin-top: -32px; 125 | background-color: $popover-bg-color-android; 126 | box-shadow: $popover-box-shadow-android; 127 | 128 | .item { 129 | border-color: $popover-bg-color-android; 130 | background-color: $popover-bg-color-android; 131 | color: #4d4d4d; 132 | } 133 | &.popover-bottom { 134 | margin-top: 32px; 135 | } 136 | } 137 | 138 | .popover-backdrop, 139 | .popover-backdrop.active { 140 | background-color: transparent; 141 | } 142 | } 143 | 144 | 145 | // disable clicks on all but the popover 146 | .popover-open { 147 | pointer-events: none; 148 | 149 | .popover, 150 | .popover-backdrop { 151 | pointer-events: auto; 152 | } 153 | // prevent clicks on popover when loading overlay is active though 154 | &.loading-active { 155 | .popover, 156 | .popover-backdrop { 157 | pointer-events: none; 158 | } 159 | } 160 | } 161 | 162 | 163 | // wider popover on larger viewports 164 | @media (min-width: $popover-large-break-point) { 165 | .popover { 166 | width: $popover-large-width; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_toggle.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Toggle 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .item-toggle { 8 | pointer-events: none; 9 | } 10 | 11 | .toggle { 12 | // set the color defaults 13 | @include toggle-style($toggle-on-default-border, $toggle-on-default-bg); 14 | 15 | position: relative; 16 | display: inline-block; 17 | pointer-events: auto; 18 | margin: -$toggle-hit-area-expansion; 19 | padding: $toggle-hit-area-expansion; 20 | 21 | &.dragging { 22 | .handle { 23 | background-color: $toggle-handle-dragging-bg-color !important; 24 | } 25 | } 26 | 27 | &.toggle-light { 28 | @include toggle-style($toggle-on-light-border, $toggle-on-light-bg); 29 | } 30 | &.toggle-stable { 31 | @include toggle-style($toggle-on-stable-border, $toggle-on-stable-bg); 32 | } 33 | &.toggle-positive { 34 | @include toggle-style($toggle-on-positive-border, $toggle-on-positive-bg); 35 | } 36 | &.toggle-calm { 37 | @include toggle-style($toggle-on-calm-border, $toggle-on-calm-bg); 38 | } 39 | &.toggle-assertive { 40 | @include toggle-style($toggle-on-assertive-border, $toggle-on-assertive-bg); 41 | } 42 | &.toggle-balanced { 43 | @include toggle-style($toggle-on-balanced-border, $toggle-on-balanced-bg); 44 | } 45 | &.toggle-energized { 46 | @include toggle-style($toggle-on-energized-border, $toggle-on-energized-bg); 47 | } 48 | &.toggle-royal { 49 | @include toggle-style($toggle-on-royal-border, $toggle-on-royal-bg); 50 | } 51 | &.toggle-dark { 52 | @include toggle-style($toggle-on-dark-border, $toggle-on-dark-bg); 53 | } 54 | } 55 | 56 | .toggle input { 57 | // hide the actual input checkbox 58 | display: none; 59 | } 60 | 61 | /* the track appearance when the toggle is "off" */ 62 | .toggle .track { 63 | @include transition-timing-function(ease-in-out); 64 | @include transition-duration($toggle-transition-duration); 65 | @include transition-property((background-color, border)); 66 | 67 | display: inline-block; 68 | box-sizing: border-box; 69 | width: $toggle-width; 70 | height: $toggle-height; 71 | border: solid $toggle-border-width $toggle-off-border-color; 72 | border-radius: $toggle-border-radius; 73 | background-color: $toggle-off-bg-color; 74 | content: ' '; 75 | cursor: pointer; 76 | pointer-events: none; 77 | } 78 | 79 | /* Fix to avoid background color bleeding */ 80 | /* (occured on (at least) Android 4.2, Asus MeMO Pad HD7 ME173X) */ 81 | .platform-android4_2 .toggle .track { 82 | -webkit-background-clip: padding-box; 83 | } 84 | 85 | /* the handle (circle) thats inside the toggle's track area */ 86 | /* also the handle's appearance when it is "off" */ 87 | .toggle .handle { 88 | @include transition($toggle-transition-duration ease-in-out); 89 | position: absolute; 90 | display: block; 91 | width: $toggle-handle-width; 92 | height: $toggle-handle-height; 93 | border-radius: $toggle-handle-radius; 94 | background-color: $toggle-handle-off-bg-color; 95 | top: $toggle-border-width + $toggle-hit-area-expansion; 96 | left: $toggle-border-width + $toggle-hit-area-expansion; 97 | 98 | &:before { 99 | // used to create a larger (but hidden) hit area to slide the handle 100 | position: absolute; 101 | top: -4px; 102 | left: ( ($toggle-handle-width / 2) * -1) - 8; 103 | padding: ($toggle-handle-height / 2) + 5 ($toggle-handle-width + 7); 104 | content: " "; 105 | } 106 | } 107 | 108 | .toggle input:checked + .track .handle { 109 | // the handle when the toggle is "on" 110 | @include translate3d($toggle-width - $toggle-handle-width - ($toggle-border-width * 2), 0, 0); 111 | background-color: $toggle-handle-on-bg-color; 112 | } 113 | 114 | .item-toggle.active { 115 | box-shadow: none; 116 | } 117 | 118 | .item-toggle, 119 | .item-toggle.item-complex .item-content { 120 | // make sure list item content have enough padding on right to fit the toggle 121 | padding-right: ($item-padding * 3) + $toggle-width; 122 | } 123 | 124 | .item-toggle.item-complex { 125 | padding-right: 0; 126 | } 127 | 128 | .item-toggle .toggle { 129 | // position the toggle to the right within a list item 130 | position: absolute; 131 | top: $item-padding / 2; 132 | right: $item-padding; 133 | z-index: $z-index-item-toggle; 134 | } 135 | 136 | .toggle input:disabled + .track { 137 | opacity: .6; 138 | } 139 | -------------------------------------------------------------------------------- /client/lib/ionic/js/angular/angular-sanitize.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.25 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(q,g,r){'use strict';function F(a){var d=[];t(d,g.noop).chars(a);return d.join("")}function m(a){var d={};a=a.split(",");var c;for(c=0;c=c;e--)d.end&&d.end(f[e]);f.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,l,f=[],n=a,h;for(f.last=function(){return f[f.length-1]};a;){h="";l=!0;if(f.last()&&y[f.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(I,"$1").replace(J,"$1");d.chars&&d.chars(s(b));return""}),e("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&&d.comment(a.substring(4, 8 | b)),a=a.substring(b+3),l=!1);else if(z.test(a)){if(b=a.match(z))a=a.replace(b[0],""),l=!1}else if(K.test(a)){if(b=a.match(A))a=a.substring(b[0].length),b[0].replace(A,e),l=!1}else L.test(a)&&((b=a.match(B))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(B,c)),l=!1):(h+="<",a=a.substring(1)));l&&(b=a.indexOf("<"),h+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(s(h)))}if(a==n)throw M("badparse",a);n=a}e()}function s(a){if(!a)return"";var d=N.exec(a);a=d[1];var c=d[3];if(d=d[2])p.innerHTML= 9 | d.replace(//g,">")}function t(a,d){var c=!1,e=g.bind(a,a.push);return{start:function(a,l,f){a=g.lowercase(a);!c&&y[a]&&(c=a);c||!0!==D[a]||(e("<"),e(a),g.forEach(l,function(c,f){var k= 10 | g.lowercase(f),l="img"===a&&"src"===k||"background"===k;!0!==Q[k]||!0===E[k]&&!d(c,l)||(e(" "),e(f),e('="'),e(C(c)),e('"'))}),e(f?"/>":">"))},end:function(a){a=g.lowercase(a);c||!0!==D[a]||(e(""));a==c&&(c=!1)},chars:function(a){c||e(C(a))}}}var M=g.$$minErr("$sanitize"),B=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,A=/^<\/\s*([\w:-]+)[^>]*>/,H=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,L=/^]*?)>/i,J=/"]/,c=/^mailto:/;return function(e,b){function l(a){a&&k.push(F(a))}function f(a,c){k.push("');l(c);k.push("")} 14 | if(!e)return e;for(var n,h=e,k=[],m,p;n=h.match(d);)m=n[0],n[2]==n[3]&&(m="mailto:"+m),p=n.index,l(h.substr(0,p)),f(m,n[0].replace(c,"")),h=h.substring(p+n[0].length);l(h);return a(k.join(""))}}])})(window,window.angular); 15 | //# sourceMappingURL=angular-sanitize.min.js.map 16 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_checkbox.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Checkbox 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .checkbox { 8 | // set the color defaults 9 | @include checkbox-style($checkbox-off-border-default, $checkbox-on-bg-default); 10 | 11 | position: relative; 12 | display: inline-block; 13 | padding: ($checkbox-height / 4) ($checkbox-width / 4); 14 | cursor: pointer; 15 | } 16 | .checkbox-light { 17 | @include checkbox-style($checkbox-off-border-light, $checkbox-on-bg-light); 18 | } 19 | .checkbox-stable { 20 | @include checkbox-style($checkbox-off-border-stable, $checkbox-on-bg-stable); 21 | } 22 | .checkbox-positive { 23 | @include checkbox-style($checkbox-off-border-positive, $checkbox-on-bg-positive); 24 | } 25 | .checkbox-calm { 26 | @include checkbox-style($checkbox-off-border-calm, $checkbox-on-bg-calm); 27 | } 28 | .checkbox-assertive { 29 | @include checkbox-style($checkbox-off-border-assertive, $checkbox-on-bg-assertive); 30 | } 31 | .checkbox-balanced { 32 | @include checkbox-style($checkbox-off-border-balanced, $checkbox-on-bg-balanced); 33 | } 34 | .checkbox-energized{ 35 | @include checkbox-style($checkbox-off-border-energized, $checkbox-on-bg-energized); 36 | } 37 | .checkbox-royal { 38 | @include checkbox-style($checkbox-off-border-royal, $checkbox-on-bg-royal); 39 | } 40 | .checkbox-dark { 41 | @include checkbox-style($checkbox-off-border-dark, $checkbox-on-bg-dark); 42 | } 43 | 44 | .checkbox input:disabled:before, 45 | .checkbox input:disabled + .checkbox-icon:before { 46 | border-color: $checkbox-off-border-light; 47 | } 48 | 49 | .checkbox input:disabled:checked:before, 50 | .checkbox input:disabled:checked + .checkbox-icon:before { 51 | background: $checkbox-on-bg-light; 52 | } 53 | 54 | 55 | .checkbox.checkbox-input-hidden input { 56 | display: none !important; 57 | } 58 | 59 | .checkbox input, 60 | .checkbox-icon { 61 | position: relative; 62 | width: $checkbox-width; 63 | height: $checkbox-height; 64 | display: block; 65 | border: 0; 66 | background: transparent; 67 | cursor: pointer; 68 | -webkit-appearance: none; 69 | 70 | &:before { 71 | // what the checkbox looks like when its not checked 72 | display: table; 73 | width: 100%; 74 | height: 100%; 75 | border-width: $checkbox-border-width; 76 | border-style: solid; 77 | border-radius: $checkbox-border-radius; 78 | background: $checkbox-off-bg-color; 79 | content: ' '; 80 | transition: background-color 20ms ease-in-out; 81 | } 82 | } 83 | 84 | .checkbox input:checked:before, 85 | input:checked + .checkbox-icon:before { 86 | border-width: $checkbox-border-width + 1; 87 | } 88 | 89 | // the checkmark within the box 90 | .checkbox input:after, 91 | .checkbox-icon:after { 92 | @include transition(opacity .05s ease-in-out); 93 | @include rotate(-45deg); 94 | position: absolute; 95 | top: 30%; 96 | left: 26%; 97 | display: table; 98 | width: ($checkbox-width / 2) + 1; 99 | height: ($checkbox-width / 3) + 1; 100 | border: $checkbox-check-width solid $checkbox-check-color; 101 | border-top: 0; 102 | border-right: 0; 103 | content: ' '; 104 | opacity: 0; 105 | } 106 | 107 | .grade-c .checkbox input:after, 108 | .grade-c .checkbox-icon:after { 109 | @include rotate(0); 110 | top: 3px; 111 | left: 4px; 112 | border: none; 113 | color: $checkbox-check-color; 114 | content: '\2713'; 115 | font-weight: bold; 116 | font-size: 20px; 117 | } 118 | 119 | // what the checkmark looks like when its checked 120 | .checkbox input:checked:after, 121 | input:checked + .checkbox-icon:after { 122 | opacity: 1; 123 | } 124 | 125 | // make sure item content have enough padding on left to fit the checkbox 126 | .item-checkbox { 127 | padding-left: ($item-padding * 2) + $checkbox-width; 128 | 129 | &.active { 130 | box-shadow: none; 131 | } 132 | } 133 | 134 | // position the checkbox to the left within an item 135 | .item-checkbox .checkbox { 136 | position: absolute; 137 | top: 50%; 138 | right: $item-padding / 2; 139 | left: $item-padding / 2; 140 | z-index: $z-index-item-checkbox; 141 | margin-top: (($checkbox-height + ($checkbox-height / 2)) / 2) * -1; 142 | } 143 | 144 | 145 | .item-checkbox.item-checkbox-right { 146 | padding-right: ($item-padding * 2) + $checkbox-width; 147 | padding-left: $item-padding; 148 | } 149 | 150 | .item-checkbox-right .checkbox input, 151 | .item-checkbox-right .checkbox-icon { 152 | float: right; 153 | } -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 45 | 46 | 53 | 54 | 55 | 59 | 60 | 88 | 89 | 93 | 94 | 109 | 110 | 114 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_util.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Utility Classes 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .hide { 8 | display: none; 9 | } 10 | .opacity-hide { 11 | opacity: 0; 12 | } 13 | .grade-b .opacity-hide, 14 | .grade-c .opacity-hide { 15 | opacity: 1; 16 | display: none; 17 | } 18 | .show { 19 | display: block; 20 | } 21 | .opacity-show { 22 | opacity: 1; 23 | } 24 | .invisible { 25 | visibility: hidden; 26 | } 27 | 28 | .keyboard-open .hide-on-keyboard-open { 29 | display: none; 30 | } 31 | 32 | .keyboard-open .tabs.hide-on-keyboard-open + .pane .has-tabs, 33 | .keyboard-open .bar-footer.hide-on-keyboard-open + .pane .has-footer { 34 | bottom: 0; 35 | } 36 | 37 | .inline { 38 | display: inline-block; 39 | } 40 | 41 | .disable-pointer-events { 42 | pointer-events: none; 43 | } 44 | 45 | .enable-pointer-events { 46 | pointer-events: auto; 47 | } 48 | 49 | .disable-user-behavior { 50 | // used to prevent the browser from doing its native behavior. this doesnt 51 | // prevent the scrolling, but cancels the contextmenu, tap highlighting, etc 52 | 53 | @include user-select(none); 54 | @include touch-callout(none); 55 | @include tap-highlight-transparent(); 56 | 57 | -webkit-user-drag: none; 58 | 59 | -ms-touch-action: none; 60 | -ms-content-zooming: none; 61 | } 62 | 63 | // Fill the screen to block clicks (a better pointer-events: none) for the body 64 | // to avoid full-page reflows and paints which can cause flickers 65 | .click-block { 66 | position: absolute; 67 | top: 0; 68 | left: 0; 69 | z-index: $z-index-click-block; 70 | width: 100%; 71 | height: 100%; 72 | background: transparent; 73 | } 74 | 75 | .no-resize { 76 | resize: none; 77 | } 78 | 79 | .block { 80 | display: block; 81 | clear: both; 82 | &:after { 83 | display: block; 84 | visibility: hidden; 85 | clear: both; 86 | height: 0; 87 | content: "."; 88 | } 89 | } 90 | 91 | .full-image { 92 | width: 100%; 93 | } 94 | 95 | .clearfix { 96 | *zoom: 1; 97 | &:before, 98 | &:after { 99 | display: table; 100 | content: ""; 101 | // Fixes Opera/contenteditable bug: 102 | // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 103 | line-height: 0; 104 | } 105 | &:after { 106 | clear: both; 107 | } 108 | } 109 | 110 | /** 111 | * Content Padding 112 | * -------------------------------------------------- 113 | */ 114 | 115 | .padding { 116 | padding: $content-padding; 117 | } 118 | 119 | .padding-top, 120 | .padding-vertical { 121 | padding-top: $content-padding; 122 | } 123 | 124 | .padding-right, 125 | .padding-horizontal { 126 | padding-right: $content-padding; 127 | } 128 | 129 | .padding-bottom, 130 | .padding-vertical { 131 | padding-bottom: $content-padding; 132 | } 133 | 134 | .padding-left, 135 | .padding-horizontal { 136 | padding-left: $content-padding; 137 | } 138 | 139 | 140 | /** 141 | * Rounded 142 | * -------------------------------------------------- 143 | */ 144 | 145 | .rounded { 146 | border-radius: $border-radius-base; 147 | } 148 | 149 | 150 | /** 151 | * Utility Colors 152 | * -------------------------------------------------- 153 | * Utility colors are added to help set a naming convention. You'll 154 | * notice we purposely do not use words like "red" or "blue", but 155 | * instead have colors which represent an emotion or generic theme. 156 | */ 157 | 158 | .light, a.light { 159 | color: $light; 160 | } 161 | .light-bg { 162 | background-color: $light; 163 | } 164 | .light-border { 165 | border-color: $button-light-border; 166 | } 167 | 168 | .stable, a.stable { 169 | color: $stable; 170 | } 171 | .stable-bg { 172 | background-color: $stable; 173 | } 174 | .stable-border { 175 | border-color: $button-stable-border; 176 | } 177 | 178 | .positive, a.positive { 179 | color: $positive; 180 | } 181 | .positive-bg { 182 | background-color: $positive; 183 | } 184 | .positive-border { 185 | border-color: $button-positive-border; 186 | } 187 | 188 | .calm, a.calm { 189 | color: $calm; 190 | } 191 | .calm-bg { 192 | background-color: $calm; 193 | } 194 | .calm-border { 195 | border-color: $button-calm-border; 196 | } 197 | 198 | .assertive, a.assertive { 199 | color: $assertive; 200 | } 201 | .assertive-bg { 202 | background-color: $assertive; 203 | } 204 | .assertive-border { 205 | border-color: $button-assertive-border; 206 | } 207 | 208 | .balanced, a.balanced { 209 | color: $balanced; 210 | } 211 | .balanced-bg { 212 | background-color: $balanced; 213 | } 214 | .balanced-border { 215 | border-color: $button-balanced-border; 216 | } 217 | 218 | .energized, a.energized { 219 | color: $energized; 220 | } 221 | .energized-bg { 222 | background-color: $energized; 223 | } 224 | .energized-border { 225 | border-color: $button-energized-border; 226 | } 227 | 228 | .royal, a.royal { 229 | color: $royal; 230 | } 231 | .royal-bg { 232 | background-color: $royal; 233 | } 234 | .royal-border { 235 | border-color: $button-royal-border; 236 | } 237 | 238 | .dark, a.dark { 239 | color: $dark; 240 | } 241 | .dark-bg { 242 | background-color: $dark; 243 | } 244 | .dark-border { 245 | border-color: $button-dark-border; 246 | } 247 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_form.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Forms 3 | * -------------------------------------------------- 4 | */ 5 | 6 | // Make all forms have space below them 7 | form { 8 | margin: 0 0 $line-height-base; 9 | } 10 | 11 | // Groups of fields with labels on top (legends) 12 | legend { 13 | display: block; 14 | margin-bottom: $line-height-base; 15 | padding: 0; 16 | width: 100%; 17 | border: $input-border-width solid $input-border; 18 | color: $dark; 19 | font-size: $font-size-base * 1.5; 20 | line-height: $line-height-base * 2; 21 | 22 | small { 23 | color: $stable; 24 | font-size: $line-height-base * .75; 25 | } 26 | } 27 | 28 | // Set font for forms 29 | label, 30 | input, 31 | button, 32 | select, 33 | textarea { 34 | @include font-shorthand($font-size-base, normal, $line-height-base); // Set size, weight, line-height here 35 | } 36 | input, 37 | button, 38 | select, 39 | textarea { 40 | font-family: $font-family-base; // And only set font-family here for those that need it (note the missing label element) 41 | } 42 | 43 | 44 | // Input List 45 | // ------------------------------- 46 | 47 | .item-input { 48 | @include display-flex(); 49 | @include align-items(center); 50 | position: relative; 51 | overflow: hidden; 52 | padding: 6px 0 5px 16px; 53 | 54 | input { 55 | @include border-radius(0); 56 | @include flex(1, 0, 220px); 57 | @include appearance(none); 58 | margin: 0; 59 | padding-right: 24px; 60 | background-color: transparent; 61 | } 62 | 63 | .button .icon { 64 | @include flex(0, 0, 24px); 65 | position: static; 66 | display: inline-block; 67 | height: auto; 68 | text-align: center; 69 | font-size: 16px; 70 | } 71 | 72 | .button-bar { 73 | @include border-radius(0); 74 | @include flex(1, 0, 220px); 75 | @include appearance(none); 76 | } 77 | 78 | .icon { 79 | min-width: 14px; 80 | } 81 | } 82 | 83 | .item-input-inset { 84 | @include display-flex(); 85 | @include align-items(center); 86 | position: relative; 87 | overflow: hidden; 88 | padding: ($item-padding / 3) * 2; 89 | } 90 | 91 | .item-input-wrapper { 92 | @include display-flex(); 93 | @include flex(1, 0); 94 | @include align-items(center); 95 | @include border-radius(4px); 96 | padding-right: 8px; 97 | padding-left: 8px; 98 | background: #eee; 99 | } 100 | 101 | .item-input-inset .item-input-wrapper input { 102 | padding-left: 4px; 103 | height: 29px; 104 | background: transparent; 105 | line-height: 18px; 106 | } 107 | 108 | .item-input-wrapper ~ .button { 109 | margin-left: ($item-padding / 3) * 2; 110 | } 111 | 112 | .input-label { 113 | @include flex(1, 0, 100px); 114 | display: table; 115 | padding: 7px 10px 7px 0px; 116 | max-width: 200px; 117 | width: 35%; 118 | color: $input-label-color; 119 | font-size: 16px; 120 | } 121 | 122 | .placeholder-icon { 123 | color: #aaa; 124 | &:first-child { 125 | padding-right: 6px; 126 | } 127 | &:last-child { 128 | padding-left: 6px; 129 | } 130 | } 131 | 132 | .item-stacked-label { 133 | display: block; 134 | background-color: transparent; 135 | box-shadow: none; 136 | 137 | .input-label, .icon { 138 | display: inline-block; 139 | padding: 4px 0 0 0px; 140 | vertical-align: middle; 141 | } 142 | } 143 | 144 | .item-stacked-label input, 145 | .item-stacked-label textarea { 146 | @include border-radius(2px); 147 | padding: 4px 8px 3px 0; 148 | border: none; 149 | background-color: $input-bg; 150 | } 151 | .item-stacked-label input { 152 | overflow: hidden; 153 | height: $line-height-computed + $font-size-base + 12px; 154 | } 155 | 156 | .item-floating-label { 157 | display: block; 158 | background-color: transparent; 159 | box-shadow: none; 160 | 161 | .input-label { 162 | position: relative; 163 | padding: 5px 0 0 0; 164 | opacity: 0; 165 | top: 10px; 166 | @include transition(opacity .15s ease-in, top .2s linear); 167 | 168 | &.has-input { 169 | opacity: 1; 170 | top: 0; 171 | @include transition(opacity .15s ease-in, top .2s linear); 172 | } 173 | } 174 | } 175 | 176 | 177 | // Form Controls 178 | // ------------------------------- 179 | 180 | // Shared size and type resets 181 | textarea, 182 | input[type="text"], 183 | input[type="password"], 184 | input[type="datetime"], 185 | input[type="datetime-local"], 186 | input[type="date"], 187 | input[type="month"], 188 | input[type="time"], 189 | input[type="week"], 190 | input[type="number"], 191 | input[type="email"], 192 | input[type="url"], 193 | input[type="search"], 194 | input[type="tel"], 195 | input[type="color"] { 196 | display: block; 197 | padding-top: 2px; 198 | padding-left: 0; 199 | height: $line-height-computed + $font-size-base; 200 | color: $input-color; 201 | vertical-align: middle; 202 | font-size: $font-size-base; 203 | line-height: $font-size-base + 2; 204 | } 205 | 206 | .platform-ios, 207 | .platform-android { 208 | input[type="datetime-local"], 209 | input[type="date"], 210 | input[type="month"], 211 | input[type="time"], 212 | input[type="week"] { 213 | padding-top: 8px; 214 | } 215 | } 216 | 217 | input, 218 | textarea { 219 | width: 100%; 220 | } 221 | textarea { 222 | padding-left: 0; 223 | @include placeholder($input-color-placeholder, -3px); 224 | } 225 | 226 | // Reset height since textareas have rows 227 | textarea { 228 | height: auto; 229 | } 230 | 231 | // Everything else 232 | textarea, 233 | input[type="text"], 234 | input[type="password"], 235 | input[type="datetime"], 236 | input[type="datetime-local"], 237 | input[type="date"], 238 | input[type="month"], 239 | input[type="time"], 240 | input[type="week"], 241 | input[type="number"], 242 | input[type="email"], 243 | input[type="url"], 244 | input[type="search"], 245 | input[type="tel"], 246 | input[type="color"] { 247 | border: 0; 248 | } 249 | 250 | // Position radios and checkboxes better 251 | input[type="radio"], 252 | input[type="checkbox"] { 253 | margin: 0; 254 | line-height: normal; 255 | } 256 | 257 | // Reset width of input images, buttons, radios, checkboxes 258 | input[type="file"], 259 | input[type="image"], 260 | input[type="submit"], 261 | input[type="reset"], 262 | input[type="button"], 263 | input[type="radio"], 264 | input[type="checkbox"] { 265 | width: auto; // Override of generic input selector 266 | } 267 | 268 | // Set the height of file to match text inputs 269 | input[type="file"] { 270 | line-height: $input-height-base; 271 | } 272 | 273 | // Text input classes to hide text caret during scroll 274 | .previous-input-focus, 275 | .cloned-text-input + input, 276 | .cloned-text-input + textarea { 277 | position: absolute !important; 278 | left: -9999px; 279 | width: 200px; 280 | } 281 | 282 | 283 | // Placeholder 284 | // ------------------------------- 285 | input, 286 | textarea { 287 | @include placeholder(); 288 | } 289 | 290 | 291 | // DISABLED STATE 292 | // ------------------------------- 293 | 294 | // Disabled and read-only inputs 295 | input[disabled], 296 | select[disabled], 297 | textarea[disabled], 298 | input[readonly]:not(.cloned-text-input), 299 | textarea[readonly]:not(.cloned-text-input), 300 | select[readonly] { 301 | background-color: $input-bg-disabled; 302 | cursor: not-allowed; 303 | } 304 | // Explicitly reset the colors here 305 | input[type="radio"][disabled], 306 | input[type="checkbox"][disabled], 307 | input[type="radio"][readonly], 308 | input[type="checkbox"][readonly] { 309 | background-color: transparent; 310 | } 311 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_button.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Buttons 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .button { 8 | // set the color defaults 9 | @include button-style($button-default-bg, $button-default-border, $button-default-active-bg, $button-default-active-border, $button-default-text); 10 | 11 | position: relative; 12 | display: inline-block; 13 | margin: 0; 14 | padding: 0 $button-padding; 15 | 16 | min-width: ($button-padding * 3) + $button-font-size; 17 | min-height: $button-height + 5px; 18 | 19 | border-width: $button-border-width; 20 | border-style: solid; 21 | border-radius: $button-border-radius; 22 | 23 | vertical-align: top; 24 | text-align: center; 25 | 26 | text-overflow: ellipsis; 27 | font-size: $button-font-size; 28 | line-height: $button-height - $button-border-width + 1px; 29 | 30 | cursor: pointer; 31 | 32 | &:after { 33 | // used to create a larger button "hit" area 34 | position: absolute; 35 | top: -6px; 36 | right: -6px; 37 | bottom: -6px; 38 | left: -6px; 39 | content: ' '; 40 | } 41 | 42 | .icon { 43 | vertical-align: top; 44 | pointer-events: none; 45 | } 46 | 47 | .icon:before, 48 | &.icon:before, 49 | &.icon-left:before, 50 | &.icon-right:before { 51 | display: inline-block; 52 | padding: 0 0 $button-border-width 0; 53 | vertical-align: inherit; 54 | font-size: $button-icon-size; 55 | line-height: $button-height - $button-border-width; 56 | pointer-events: none; 57 | } 58 | &.icon-left:before { 59 | float: left; 60 | padding-right: .2em; 61 | padding-left: 0; 62 | } 63 | &.icon-right:before { 64 | float: right; 65 | padding-right: 0; 66 | padding-left: .2em; 67 | } 68 | 69 | &.button-block, &.button-full { 70 | margin-top: $button-block-margin; 71 | margin-bottom: $button-block-margin; 72 | } 73 | 74 | &.button-light { 75 | @include button-style($button-light-bg, $button-light-border, $button-light-active-bg, $button-light-active-border, $button-light-text); 76 | @include button-clear($button-light-border); 77 | @include button-outline($button-light-border); 78 | } 79 | 80 | &.button-stable { 81 | @include button-style($button-stable-bg, $button-stable-border, $button-stable-active-bg, $button-stable-active-border, $button-stable-text); 82 | @include button-clear($button-stable-border); 83 | @include button-outline($button-stable-border); 84 | } 85 | 86 | &.button-positive { 87 | @include button-style($button-positive-bg, $button-positive-border, $button-positive-active-bg, $button-positive-active-border, $button-positive-text); 88 | @include button-clear($button-positive-bg); 89 | @include button-outline($button-positive-bg); 90 | } 91 | 92 | &.button-calm { 93 | @include button-style($button-calm-bg, $button-calm-border, $button-calm-active-bg, $button-calm-active-border, $button-calm-text); 94 | @include button-clear($button-calm-bg); 95 | @include button-outline($button-calm-bg); 96 | } 97 | 98 | &.button-assertive { 99 | @include button-style($button-assertive-bg, $button-assertive-border, $button-assertive-active-bg, $button-assertive-active-border, $button-assertive-text); 100 | @include button-clear($button-assertive-bg); 101 | @include button-outline($button-assertive-bg); 102 | } 103 | 104 | &.button-balanced { 105 | @include button-style($button-balanced-bg, $button-balanced-border, $button-balanced-active-bg, $button-balanced-active-border, $button-balanced-text); 106 | @include button-clear($button-balanced-bg); 107 | @include button-outline($button-balanced-bg); 108 | } 109 | 110 | &.button-energized { 111 | @include button-style($button-energized-bg, $button-energized-border, $button-energized-active-bg, $button-energized-active-border, $button-energized-text); 112 | @include button-clear($button-energized-bg); 113 | @include button-outline($button-energized-bg); 114 | } 115 | 116 | &.button-royal { 117 | @include button-style($button-royal-bg, $button-royal-border, $button-royal-active-bg, $button-royal-active-border, $button-royal-text); 118 | @include button-clear($button-royal-bg); 119 | @include button-outline($button-royal-bg); 120 | } 121 | 122 | &.button-dark { 123 | @include button-style($button-dark-bg, $button-dark-border, $button-dark-active-bg, $button-dark-active-border, $button-dark-text); 124 | @include button-clear($button-dark-bg); 125 | @include button-outline($button-dark-bg); 126 | } 127 | } 128 | 129 | .button-small { 130 | padding: 2px $button-small-padding 1px; 131 | min-width: $button-small-height; 132 | min-height: $button-small-height + 2; 133 | font-size: $button-small-font-size; 134 | line-height: $button-small-height - $button-border-width - 1; 135 | 136 | .icon:before, 137 | &.icon:before, 138 | &.icon-left:before, 139 | &.icon-right:before { 140 | font-size: $button-small-icon-size; 141 | line-height: $button-small-icon-size + 3; 142 | margin-top: 3px; 143 | } 144 | } 145 | 146 | .button-large { 147 | padding: 0 $button-large-padding; 148 | min-width: ($button-large-padding * 3) + $button-large-font-size; 149 | min-height: $button-large-height + 5; 150 | font-size: $button-large-font-size; 151 | line-height: $button-large-height - $button-border-width; 152 | 153 | .icon:before, 154 | &.icon:before, 155 | &.icon-left:before, 156 | &.icon-right:before { 157 | padding-bottom: ($button-border-width * 2); 158 | font-size: $button-large-icon-size; 159 | line-height: $button-large-height - ($button-border-width * 2) - 1; 160 | } 161 | } 162 | 163 | .button-icon { 164 | @include transition(opacity .1s); 165 | padding: 0 6px; 166 | min-width: initial; 167 | border-color: transparent; 168 | background: none; 169 | 170 | &.button.active, 171 | &.button.activated { 172 | border-color: transparent; 173 | background: none; 174 | box-shadow: none; 175 | opacity: 0.3; 176 | } 177 | 178 | .icon:before, 179 | &.icon:before { 180 | font-size: $button-large-icon-size; 181 | } 182 | } 183 | 184 | .button-clear { 185 | @include button-clear($button-default-border); 186 | @include transition(opacity .1s); 187 | padding: 0 $button-clear-padding; 188 | max-height: $button-height; 189 | border-color: transparent; 190 | background: none; 191 | box-shadow: none; 192 | 193 | &.active, 194 | &.activated { 195 | opacity: 0.3; 196 | } 197 | } 198 | 199 | .button-outline { 200 | @include button-outline($button-default-border); 201 | @include transition(opacity .1s); 202 | background: none; 203 | box-shadow: none; 204 | } 205 | 206 | .padding > .button.button-block:first-child { 207 | margin-top: 0; 208 | } 209 | 210 | .button-block { 211 | display: block; 212 | clear: both; 213 | 214 | &:after { 215 | clear: both; 216 | } 217 | } 218 | 219 | .button-full, 220 | .button-full > .button { 221 | display: block; 222 | margin-right: 0; 223 | margin-left: 0; 224 | border-right-width: 0; 225 | border-left-width: 0; 226 | border-radius: 0; 227 | } 228 | 229 | button.button-block, 230 | button.button-full, 231 | .button-full > button.button, 232 | input.button.button-block { 233 | width: 100%; 234 | } 235 | 236 | a.button { 237 | text-decoration: none; 238 | 239 | .icon:before, 240 | &.icon:before, 241 | &.icon-left:before, 242 | &.icon-right:before { 243 | margin-top: 2px; 244 | } 245 | } 246 | 247 | .button.disabled, 248 | .button[disabled] { 249 | opacity: .4; 250 | cursor: default !important; 251 | pointer-events: none; 252 | } 253 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_reset.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Resets 4 | * -------------------------------------------------- 5 | * Adapted from normalize.css and some reset.css. We don't care even one 6 | * bit about old IE, so we don't need any hacks for that in here. 7 | * 8 | * There are probably other things we could remove here, as well. 9 | * 10 | * normalize.css v2.1.2 | MIT License | git.io/normalize 11 | 12 | * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) 13 | * http://cssreset.com 14 | */ 15 | 16 | html, body, div, span, applet, object, iframe, 17 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 18 | a, abbr, acronym, address, big, cite, code, 19 | del, dfn, em, img, ins, kbd, q, s, samp, 20 | small, strike, strong, sub, sup, tt, var, 21 | b, i, u, center, 22 | dl, dt, dd, ol, ul, li, 23 | fieldset, form, label, legend, 24 | table, caption, tbody, tfoot, thead, tr, th, td, 25 | article, aside, canvas, details, embed, fieldset, 26 | figure, figcaption, footer, header, hgroup, 27 | menu, nav, output, ruby, section, summary, 28 | time, mark, audio, video { 29 | margin: 0; 30 | padding: 0; 31 | border: 0; 32 | vertical-align: baseline; 33 | font: inherit; 34 | font-size: 100%; 35 | } 36 | 37 | ol, ul { 38 | list-style: none; 39 | } 40 | blockquote, q { 41 | quotes: none; 42 | } 43 | blockquote:before, blockquote:after, 44 | q:before, q:after { 45 | content: ''; 46 | content: none; 47 | } 48 | 49 | /** 50 | * Prevent modern browsers from displaying `audio` without controls. 51 | * Remove excess height in iOS 5 devices. 52 | */ 53 | 54 | audio:not([controls]) { 55 | display: none; 56 | height: 0; 57 | } 58 | 59 | /** 60 | * Hide the `template` element in IE, Safari, and Firefox < 22. 61 | */ 62 | 63 | [hidden], 64 | template { 65 | display: none; 66 | } 67 | 68 | script { 69 | display: none !important; 70 | } 71 | 72 | /* ========================================================================== 73 | Base 74 | ========================================================================== */ 75 | 76 | /** 77 | * 1. Set default font family to sans-serif. 78 | * 2. Prevent iOS text size adjust after orientation change, without disabling 79 | * user zoom. 80 | */ 81 | 82 | html { 83 | @include user-select(none); 84 | font-family: sans-serif; /* 1 */ 85 | -webkit-text-size-adjust: 100%; 86 | -ms-text-size-adjust: 100%; /* 2 */ 87 | -webkit-text-size-adjust: 100%; /* 2 */ 88 | } 89 | 90 | /** 91 | * Remove default margin. 92 | */ 93 | 94 | body { 95 | margin: 0; 96 | line-height: 1; 97 | } 98 | 99 | 100 | /** 101 | * Remove default outlines. 102 | */ 103 | a, 104 | button, 105 | :focus, 106 | a:focus, 107 | button:focus, 108 | a:active, 109 | a:hover { 110 | outline: 0; 111 | } 112 | 113 | /* * 114 | * Remove tap highlight color 115 | */ 116 | 117 | a { 118 | -webkit-user-drag: none; 119 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 120 | -webkit-tap-highlight-color: transparent; 121 | 122 | &[href]:hover { 123 | cursor: pointer; 124 | } 125 | } 126 | 127 | /* ========================================================================== 128 | Typography 129 | ========================================================================== */ 130 | 131 | 132 | /** 133 | * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 134 | */ 135 | 136 | b, 137 | strong { 138 | font-weight: bold; 139 | } 140 | 141 | /** 142 | * Address styling not present in Safari 5 and Chrome. 143 | */ 144 | 145 | dfn { 146 | font-style: italic; 147 | } 148 | 149 | /** 150 | * Address differences between Firefox and other browsers. 151 | */ 152 | 153 | hr { 154 | -moz-box-sizing: content-box; 155 | box-sizing: content-box; 156 | height: 0; 157 | } 158 | 159 | 160 | /** 161 | * Correct font family set oddly in Safari 5 and Chrome. 162 | */ 163 | 164 | code, 165 | kbd, 166 | pre, 167 | samp { 168 | font-size: 1em; 169 | font-family: monospace, serif; 170 | } 171 | 172 | /** 173 | * Improve readability of pre-formatted text in all browsers. 174 | */ 175 | 176 | pre { 177 | white-space: pre-wrap; 178 | } 179 | 180 | /** 181 | * Set consistent quote types. 182 | */ 183 | 184 | q { 185 | quotes: "\201C" "\201D" "\2018" "\2019"; 186 | } 187 | 188 | /** 189 | * Address inconsistent and variable font size in all browsers. 190 | */ 191 | 192 | small { 193 | font-size: 80%; 194 | } 195 | 196 | /** 197 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 198 | */ 199 | 200 | sub, 201 | sup { 202 | position: relative; 203 | vertical-align: baseline; 204 | font-size: 75%; 205 | line-height: 0; 206 | } 207 | 208 | sup { 209 | top: -0.5em; 210 | } 211 | 212 | sub { 213 | bottom: -0.25em; 214 | } 215 | 216 | /** 217 | * Define consistent border, margin, and padding. 218 | */ 219 | 220 | fieldset { 221 | margin: 0 2px; 222 | padding: 0.35em 0.625em 0.75em; 223 | border: 1px solid #c0c0c0; 224 | } 225 | 226 | /** 227 | * 1. Correct `color` not being inherited in IE 8/9. 228 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 229 | */ 230 | 231 | legend { 232 | padding: 0; /* 2 */ 233 | border: 0; /* 1 */ 234 | } 235 | 236 | /** 237 | * 1. Correct font family not being inherited in all browsers. 238 | * 2. Correct font size not being inherited in all browsers. 239 | * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. 240 | * 4. Remove any default :focus styles 241 | * 5. Make sure webkit font smoothing is being inherited 242 | * 6. Remove default gradient in Android Firefox / FirefoxOS 243 | */ 244 | 245 | button, 246 | input, 247 | select, 248 | textarea { 249 | margin: 0; /* 3 */ 250 | font-size: 100%; /* 2 */ 251 | font-family: inherit; /* 1 */ 252 | outline-offset: 0; /* 4 */ 253 | outline-style: none; /* 4 */ 254 | outline-width: 0; /* 4 */ 255 | -webkit-font-smoothing: inherit; /* 5 */ 256 | background-image: none; /* 6 */ 257 | } 258 | 259 | /** 260 | * Address Firefox 4+ setting `line-height` on `input` using `importnt` in 261 | * the UA stylesheet. 262 | */ 263 | 264 | button, 265 | input { 266 | line-height: normal; 267 | } 268 | 269 | /** 270 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 271 | * All other form control elements do not inherit `text-transform` values. 272 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. 273 | * Correct `select` style inheritance in Firefox 4+ and Opera. 274 | */ 275 | 276 | button, 277 | select { 278 | text-transform: none; 279 | } 280 | 281 | /** 282 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 283 | * and `video` controls. 284 | * 2. Correct inability to style clickable `input` types in iOS. 285 | * 3. Improve usability and consistency of cursor style between image-type 286 | * `input` and others. 287 | */ 288 | 289 | button, 290 | html input[type="button"], /* 1 */ 291 | input[type="reset"], 292 | input[type="submit"] { 293 | cursor: pointer; /* 3 */ 294 | -webkit-appearance: button; /* 2 */ 295 | } 296 | 297 | /** 298 | * Re-set default cursor for disabled elements. 299 | */ 300 | 301 | button[disabled], 302 | html input[disabled] { 303 | cursor: default; 304 | } 305 | 306 | /** 307 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 308 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome 309 | * (include `-moz` to future-proof). 310 | */ 311 | 312 | input[type="search"] { 313 | -webkit-box-sizing: content-box; /* 2 */ 314 | -moz-box-sizing: content-box; 315 | box-sizing: content-box; 316 | -webkit-appearance: textfield; /* 1 */ 317 | } 318 | 319 | /** 320 | * Remove inner padding and search cancel button in Safari 5 and Chrome 321 | * on OS X. 322 | */ 323 | 324 | input[type="search"]::-webkit-search-cancel-button, 325 | input[type="search"]::-webkit-search-decoration { 326 | -webkit-appearance: none; 327 | } 328 | 329 | /** 330 | * Remove inner padding and border in Firefox 4+. 331 | */ 332 | 333 | button::-moz-focus-inner, 334 | input::-moz-focus-inner { 335 | padding: 0; 336 | border: 0; 337 | } 338 | 339 | /** 340 | * 1. Remove default vertical scrollbar in IE 8/9. 341 | * 2. Improve readability and alignment in all browsers. 342 | */ 343 | 344 | textarea { 345 | overflow: auto; /* 1 */ 346 | vertical-align: top; /* 2 */ 347 | } 348 | 349 | 350 | img { 351 | -webkit-user-drag: none; 352 | } 353 | 354 | /* ========================================================================== 355 | Tables 356 | ========================================================================== */ 357 | 358 | /** 359 | * Remove most spacing between table cells. 360 | */ 361 | 362 | table { 363 | border-spacing: 0; 364 | border-collapse: collapse; 365 | } 366 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_scaffolding.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Scaffolding 4 | * -------------------------------------------------- 5 | */ 6 | 7 | *, 8 | *:before, 9 | *:after { 10 | @include box-sizing(border-box); 11 | } 12 | 13 | html { 14 | overflow: hidden; 15 | -ms-touch-action: pan-y; 16 | touch-action: pan-y; 17 | } 18 | 19 | body, 20 | .ionic-body { 21 | @include touch-callout(none); 22 | @include font-smoothing(antialiased); 23 | @include text-size-adjust(none); 24 | @include tap-highlight-transparent(); 25 | @include user-select(none); 26 | 27 | top: 0; 28 | right: 0; 29 | bottom: 0; 30 | left: 0; 31 | overflow: hidden; 32 | 33 | margin: 0; 34 | padding: 0; 35 | 36 | color: $base-color; 37 | word-wrap: break-word; 38 | font-size: $font-size-base; 39 | font-family: $font-family-base; 40 | line-height: $line-height-computed; 41 | text-rendering: optimizeLegibility; 42 | -webkit-backface-visibility: hidden; 43 | -webkit-user-drag: none; 44 | } 45 | 46 | body.grade-b, 47 | body.grade-c { 48 | // disable optimizeLegibility for low end devices 49 | text-rendering: auto; 50 | } 51 | 52 | .content { 53 | // used for content areas not using the content directive 54 | position: relative; 55 | } 56 | 57 | .scroll-content { 58 | position: absolute; 59 | top: 0; 60 | right: 0; 61 | bottom: 0; 62 | left: 0; 63 | overflow: hidden; 64 | 65 | // Hide the top border if any 66 | margin-top: -1px; 67 | 68 | // Prevents any distortion of lines 69 | padding-top:1px; 70 | 71 | width: auto; 72 | height: auto; 73 | } 74 | 75 | .scroll-content-false, 76 | .menu .scroll-content.scroll-content-false{ 77 | z-index: $z-index-scroll-content-false; 78 | } 79 | 80 | .scroll-view { 81 | position: relative; 82 | display: block; 83 | overflow: hidden; 84 | 85 | // Hide the top border if any 86 | margin-top: -1px; 87 | } 88 | 89 | /** 90 | * Scroll is the scroll view component available for complex and custom 91 | * scroll view functionality. 92 | */ 93 | .scroll { 94 | @include user-select(none); 95 | @include touch-callout(none); 96 | @include text-size-adjust(none); 97 | @include transform-origin(left, top); 98 | } 99 | 100 | // hide webkit scrollbars 101 | ::-webkit-scrollbar { 102 | display:none; 103 | } 104 | 105 | // Scroll bar styles 106 | .scroll-bar { 107 | position: absolute; 108 | z-index: $z-index-scroll-bar; 109 | } 110 | // hide the scroll-bar during animations 111 | .ng-animate .scroll-bar { 112 | visibility: hidden; 113 | } 114 | .scroll-bar-h { 115 | right: 2px; 116 | bottom: 3px; 117 | left: 2px; 118 | height: 3px; 119 | 120 | .scroll-bar-indicator { 121 | height: 100%; 122 | } 123 | } 124 | 125 | .scroll-bar-v { 126 | top: 2px; 127 | right: 3px; 128 | bottom: 2px; 129 | width: 3px; 130 | 131 | .scroll-bar-indicator { 132 | width: 100%; 133 | } 134 | } 135 | .scroll-bar-indicator { 136 | position: absolute; 137 | border-radius: 4px; 138 | background: rgba(0,0,0,0.3); 139 | opacity: 1; 140 | @include transition(opacity .3s linear); 141 | 142 | &.scroll-bar-fade-out { 143 | opacity: 0; 144 | } 145 | } 146 | .grade-b .scroll-bar-indicator, 147 | .grade-c .scroll-bar-indicator { 148 | // disable rgba background and border radius for low end devices 149 | border-radius: 0; 150 | background: #aaa; 151 | 152 | &.scroll-bar-fade-out { 153 | @include transition(none); 154 | } 155 | } 156 | 157 | @keyframes refresh-spin { 158 | 0% { transform: translate3d(0,0,0) rotate(0); } 159 | 100% { transform: translate3d(0,0,0) rotate(180deg); } 160 | } 161 | 162 | @-webkit-keyframes refresh-spin { 163 | 0% {-webkit-transform: translate3d(0,0,0) rotate(0); } 164 | 100% {-webkit-transform: translate3d(0,0,0) rotate(180deg); } 165 | } 166 | 167 | @keyframes refresh-spin-back { 168 | 0% { transform: translate3d(0,0,0) rotate(180deg); } 169 | 100% { transform: translate3d(0,0,0) rotate(0); } 170 | } 171 | 172 | @-webkit-keyframes refresh-spin-back { 173 | 0% {-webkit-transform: translate3d(0,0,0) rotate(180deg); } 174 | 100% {-webkit-transform: translate3d(0,0,0) rotate(0); } 175 | } 176 | 177 | // Scroll refresher (for pull to refresh) 178 | .scroll-refresher { 179 | position: absolute; 180 | top: -60px; 181 | right: 0; 182 | left: 0; 183 | overflow: hidden; 184 | margin: auto; 185 | height: 60px; 186 | 187 | .ionic-refresher-content { 188 | position: absolute; 189 | bottom: 15px; 190 | left: 0; 191 | width: 100%; 192 | color: $scroll-refresh-icon-color; 193 | text-align: center; 194 | 195 | font-size: 30px; 196 | 197 | .text-refreshing, 198 | .text-pulling { 199 | font-size: 16px; 200 | line-height: 16px; 201 | } 202 | &.ionic-refresher-with-text { 203 | bottom: 10px; 204 | } 205 | } 206 | 207 | .icon-refreshing, 208 | .icon-pulling { 209 | width: 100%; 210 | -webkit-backface-visibility: hidden; 211 | -webkit-transform-style: preserve-3d; 212 | backface-visibility: hidden; 213 | transform-style: preserve-3d; 214 | } 215 | .icon-pulling { 216 | @include animation-name(refresh-spin-back); 217 | @include animation-duration(200ms); 218 | @include animation-timing-function(linear); 219 | @include animation-fill-mode(none); 220 | -webkit-transform: translate3d(0,0,0) rotate(0deg); 221 | transform: translate3d(0,0,0) rotate(0deg); 222 | } 223 | .icon-refreshing, 224 | .text-refreshing { 225 | display: none; 226 | } 227 | .icon-refreshing { 228 | @include animation-duration(1.5s); 229 | } 230 | 231 | &.active { 232 | .icon-pulling:not(.pulling-rotation-disabled) { 233 | @include animation-name(refresh-spin); 234 | -webkit-transform: translate3d(0,0,0) rotate(-180deg); 235 | transform: translate3d(0,0,0) rotate(-180deg); 236 | } 237 | &.refreshing { 238 | @include transition(transform .2s); 239 | @include transition(-webkit-transform .2s); 240 | -webkit-transform: scale(1,1); 241 | transform: scale(1,1); 242 | .icon-pulling, 243 | .text-pulling { 244 | display: none; 245 | } 246 | .icon-refreshing, 247 | .text-refreshing { 248 | display: block; 249 | } 250 | &.refreshing-tail{ 251 | -webkit-transform: scale(0,0); 252 | transform: scale(0,0); 253 | } 254 | } 255 | } 256 | } 257 | 258 | ion-infinite-scroll { 259 | height: 60px; 260 | width: 100%; 261 | opacity: 0; 262 | display: block; 263 | 264 | @include transition(opacity 0.25s); 265 | @include display-flex(); 266 | @include flex-direction(row); 267 | @include justify-content(center); 268 | @include align-items(center); 269 | 270 | .icon { 271 | color: #666666; 272 | font-size: 30px; 273 | color: $scroll-refresh-icon-color; 274 | } 275 | 276 | &.active { 277 | opacity: 1; 278 | } 279 | } 280 | 281 | .overflow-scroll { 282 | overflow-x: hidden; 283 | overflow-y: scroll; 284 | -webkit-overflow-scrolling: touch; 285 | top: 0; 286 | right: 0; 287 | bottom: 0; 288 | left: 0; 289 | position: absolute; 290 | 291 | .scroll { 292 | position: static; 293 | height: 100%; 294 | -webkit-transform: translate3d(0, 0, 0); // fix iOS bug where relative children of scroller disapear while scrolling. see: http://stackoverflow.com/questions/9807620/ipad-safari-scrolling-causes-html-elements-to-disappear-and-reappear-with-a-dela 295 | } 296 | } 297 | 298 | 299 | // Pad top/bottom of content so it doesn't hide behind .bar-title and .bar-tab. 300 | // Note: For these to work, content must come after both bars in the markup 301 | /* If you change these, change platform.scss as well */ 302 | .has-header { 303 | top: $bar-height; 304 | } 305 | // Force no header 306 | .no-header { 307 | top: 0; 308 | } 309 | 310 | .has-subheader { 311 | top: $bar-height * 2; 312 | } 313 | .has-tabs-top { 314 | top: $bar-height + $tabs-height; 315 | } 316 | .has-header.has-subheader.has-tabs-top { 317 | top: 2 * $bar-height + $tabs-height; 318 | } 319 | 320 | .has-footer { 321 | bottom: $bar-height; 322 | } 323 | .has-subfooter { 324 | bottom: $bar-height * 2; 325 | } 326 | 327 | .has-tabs, 328 | .bar-footer.has-tabs { 329 | bottom: $tabs-height; 330 | } 331 | 332 | .has-footer.has-tabs { 333 | bottom: $tabs-height + $bar-height; 334 | } 335 | 336 | // A full screen section with a solid background 337 | .pane { 338 | @include translate3d(0,0,0); 339 | z-index: $z-index-pane; 340 | } 341 | .view { 342 | z-index: $z-index-view; 343 | } 344 | .pane, 345 | .view { 346 | position: absolute; 347 | top: 0; 348 | right: 0; 349 | bottom: 0; 350 | left: 0; 351 | width: 100%; 352 | height: 100%; 353 | background-color: $base-background-color; 354 | overflow: hidden; 355 | } 356 | 357 | ion-nav-view { 358 | position: absolute; 359 | top: 0; 360 | left: 0; 361 | width: 100%; 362 | height: 100%; 363 | background-color: #000; 364 | } 365 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_bar.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Bar (Headers and Footers) 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .bar { 8 | @include display-flex(); 9 | @include translate3d(0,0,0); 10 | @include user-select(none); 11 | position: absolute; 12 | right: 0; 13 | left: 0; 14 | z-index: $z-index-bar; 15 | 16 | box-sizing: border-box; 17 | padding: $bar-padding-portrait; 18 | 19 | width: 100%; 20 | height: $bar-height; 21 | border-width: 0; 22 | border-style: solid; 23 | border-top: 1px solid transparent; 24 | border-bottom: 1px solid $bar-default-border; 25 | 26 | background-color: $bar-default-bg; 27 | 28 | /* border-width: 1px will actually create 2 device pixels on retina */ 29 | /* this nifty trick sets an actual 1px border on hi-res displays */ 30 | background-size: 0; 31 | @media (min--moz-device-pixel-ratio: 1.5), 32 | (-webkit-min-device-pixel-ratio: 1.5), 33 | (min-device-pixel-ratio: 1.5), 34 | (min-resolution: 144dpi), 35 | (min-resolution: 1.5dppx) { 36 | border: none; 37 | background-image: linear-gradient(0deg, $bar-default-border, $bar-default-border 50%, transparent 50%); 38 | background-position: bottom; 39 | background-size: 100% 1px; 40 | background-repeat: no-repeat; 41 | } 42 | 43 | &.bar-clear { 44 | border: none; 45 | background: none; 46 | color: #fff; 47 | 48 | .button { 49 | color: #fff; 50 | } 51 | .title { 52 | color: #fff; 53 | } 54 | } 55 | 56 | &.item-input-inset { 57 | .item-input-wrapper { 58 | margin-top: -1px; 59 | 60 | input { 61 | padding-left: 8px; 62 | width: 94%; 63 | height: 28px; 64 | background: transparent; 65 | } 66 | } 67 | } 68 | 69 | &.bar-light { 70 | @include bar-style($bar-light-bg, $bar-light-border, $bar-light-text); 71 | &.bar-footer{ 72 | background-image: linear-gradient(180deg, $bar-light-border, $bar-light-border 50%, transparent 50%); 73 | } 74 | } 75 | &.bar-stable { 76 | @include bar-style($bar-stable-bg, $bar-stable-border, $bar-stable-text); 77 | &.bar-footer{ 78 | background-image: linear-gradient(180deg, $bar-stable-border, $bar-stable-border 50%, transparent 50%); 79 | } 80 | } 81 | &.bar-positive { 82 | @include bar-style($bar-positive-bg, $bar-positive-border, $bar-positive-text); 83 | &.bar-footer{ 84 | background-image: linear-gradient(180deg, $bar-positive-border, $bar-positive-border 50%, transparent 50%); 85 | } 86 | } 87 | &.bar-calm { 88 | @include bar-style($bar-calm-bg, $bar-calm-border, $bar-calm-text); 89 | &.bar-footer{ 90 | background-image: linear-gradient(180deg, $bar-calm-border, $bar-calm-border 50%, transparent 50%); 91 | } 92 | } 93 | &.bar-assertive { 94 | @include bar-style($bar-assertive-bg, $bar-assertive-border, $bar-assertive-text); 95 | &.bar-footer{ 96 | background-image: linear-gradient(180deg, $bar-assertive-border, $bar-assertive-border 50%, transparent 50%); 97 | } 98 | } 99 | &.bar-balanced { 100 | @include bar-style($bar-balanced-bg, $bar-balanced-border, $bar-balanced-text); 101 | &.bar-footer{ 102 | background-image: linear-gradient(180deg, $bar-balanced-border, $bar-positive-border 50%, transparent 50%); 103 | } 104 | } 105 | &.bar-energized { 106 | @include bar-style($bar-energized-bg, $bar-energized-border, $bar-energized-text); 107 | &.bar-footer{ 108 | background-image: linear-gradient(180deg, $bar-energized-border, $bar-energized-border 50%, transparent 50%); 109 | } 110 | } 111 | &.bar-royal { 112 | @include bar-style($bar-royal-bg, $bar-royal-border, $bar-royal-text); 113 | &.bar-footer{ 114 | background-image: linear-gradient(180deg, $bar-royal-border, $bar-royal-border 50%, transparent 50%); 115 | } 116 | } 117 | &.bar-dark { 118 | @include bar-style($bar-dark-bg, $bar-dark-border, $bar-dark-text); 119 | &.bar-footer{ 120 | background-image: linear-gradient(180deg, $bar-dark-border, $bar-dark-border 50%, transparent 50%); 121 | } 122 | } 123 | 124 | // Title inside of a bar is centered 125 | .title { 126 | position: absolute; 127 | 128 | top: 0; 129 | right: 0; 130 | left: 0; 131 | z-index: $z-index-bar-title; 132 | overflow: hidden; 133 | 134 | margin: 0 10px; 135 | 136 | min-width: 30px; 137 | height: $bar-height - 1; 138 | 139 | text-align: center; 140 | 141 | // Go into ellipsis if too small 142 | text-overflow: ellipsis; 143 | white-space: nowrap; 144 | 145 | font-size: $bar-title-font-size; 146 | 147 | line-height: $bar-height; 148 | 149 | &.title-left { 150 | text-align: left; 151 | } 152 | &.title-right { 153 | text-align: right; 154 | } 155 | } 156 | 157 | .title a { 158 | color: inherit; 159 | } 160 | 161 | .button { 162 | z-index: $z-index-bar-button; 163 | padding: 0 $button-bar-button-padding; 164 | min-width: initial; 165 | min-height: $button-bar-button-height - 1; 166 | font-weight: 400; 167 | font-size: $button-bar-button-font-size; 168 | line-height: $button-bar-button-height; 169 | 170 | &.button-icon:before, 171 | .icon:before, 172 | &.icon:before, 173 | &.icon-left:before, 174 | &.icon-right:before { 175 | padding-right: 2px; 176 | padding-left: 2px; 177 | font-size: $button-bar-button-icon-size; 178 | line-height: $button-bar-button-height; 179 | } 180 | 181 | &.button-icon { 182 | font-size: $bar-title-font-size; 183 | .icon:before, 184 | &:before, 185 | &.icon-left:before, 186 | &.icon-right:before { 187 | vertical-align: top; 188 | font-size: $button-large-icon-size; 189 | line-height: $button-bar-button-height; 190 | } 191 | } 192 | &.button-clear { 193 | padding-right: 2px; 194 | padding-left: 2px; 195 | font-weight: 300; 196 | font-size: $bar-title-font-size; 197 | 198 | .icon:before, 199 | &.icon:before, 200 | &.icon-left:before, 201 | &.icon-right:before { 202 | font-size: $button-large-icon-size; 203 | line-height: $button-bar-button-height; 204 | } 205 | } 206 | 207 | &.back-button { 208 | padding: 0; 209 | opacity: 0.8; 210 | .back-button-title { 211 | display: inline-block; 212 | vertical-align: middle; 213 | margin-left: 4px; 214 | } 215 | } 216 | 217 | &.back-button.active, 218 | &.back-button.activated { 219 | opacity: 1; 220 | } 221 | } 222 | 223 | .button-bar > .button, 224 | .buttons > .button { 225 | min-height: $button-bar-button-height - 1; 226 | line-height: $button-bar-button-height; 227 | } 228 | 229 | .button-bar + .button, 230 | .button + .button-bar { 231 | margin-left: 5px; 232 | } 233 | 234 | // Android 4.4 messes with the display property 235 | .buttons, 236 | .buttons.left-buttons, 237 | .buttons.right-buttons { 238 | display: inherit; 239 | } 240 | .buttons span { 241 | display: inline-flex; 242 | } 243 | 244 | // Place the last button in a bar on the right of the bar 245 | .title + .button:last-child, 246 | > .button + .button:last-child, 247 | > .button.pull-right, 248 | .buttons.pull-right, 249 | .title + .buttons { 250 | position: absolute; 251 | top: 5px; 252 | right: 5px; 253 | bottom: 5px; 254 | } 255 | 256 | } 257 | 258 | // Default styles for buttons inside of styled bars 259 | .bar-light { 260 | .button { 261 | @include button-style($bar-light-bg, $bar-light-border, $bar-light-active-bg, $bar-light-active-border, $bar-light-text); 262 | @include button-clear($bar-light-text, $bar-title-font-size); 263 | } 264 | } 265 | .bar-stable { 266 | .button { 267 | @include button-style($bar-stable-bg, $bar-stable-border, $bar-stable-active-bg, $bar-stable-active-border, $bar-stable-text); 268 | @include button-clear($bar-stable-text, $bar-title-font-size); 269 | } 270 | } 271 | .bar-positive { 272 | .button { 273 | @include button-style($bar-positive-bg, $bar-positive-border, $bar-positive-active-bg, $bar-positive-active-border, $bar-positive-text); 274 | @include button-clear(#fff, $bar-title-font-size); 275 | } 276 | } 277 | .bar-calm { 278 | .button { 279 | @include button-style($bar-calm-bg, $bar-calm-border, $bar-calm-active-bg, $bar-calm-active-border, $bar-calm-text); 280 | @include button-clear(#fff, $bar-title-font-size); 281 | } 282 | } 283 | .bar-assertive { 284 | .button { 285 | @include button-style($bar-assertive-bg, $bar-assertive-border, $bar-assertive-active-bg, $bar-assertive-active-border, $bar-assertive-text); 286 | @include button-clear(#fff, $bar-title-font-size); 287 | } 288 | } 289 | .bar-balanced { 290 | .button { 291 | @include button-style($bar-balanced-bg, $bar-balanced-border, $bar-balanced-active-bg, $bar-balanced-active-border, $bar-balanced-text); 292 | @include button-clear(#fff, $bar-title-font-size); 293 | } 294 | } 295 | .bar-energized { 296 | .button { 297 | @include button-style($bar-energized-bg, $bar-energized-border, $bar-energized-active-bg, $bar-energized-active-border, $bar-energized-text); 298 | @include button-clear(#fff, $bar-title-font-size); 299 | } 300 | } 301 | .bar-royal { 302 | .button { 303 | @include button-style($bar-royal-bg, $bar-royal-border, $bar-royal-active-bg, $bar-royal-active-border, $bar-royal-text); 304 | @include button-clear(#fff, $bar-title-font-size); 305 | } 306 | } 307 | .bar-dark { 308 | .button { 309 | @include button-style($bar-dark-bg, $bar-dark-border, $bar-dark-active-bg, $bar-dark-active-border, $bar-dark-text); 310 | @include button-clear(#fff, $bar-title-font-size); 311 | } 312 | } 313 | 314 | // Header at top 315 | .bar-header { 316 | top: 0; 317 | border-top-width: 0; 318 | border-bottom-width: 1px; 319 | &.has-tabs-top{ 320 | border-bottom-width: 0px; 321 | } 322 | } 323 | 324 | // Footer at bottom 325 | .bar-footer { 326 | bottom: 0; 327 | border-top-width: 1px; 328 | border-bottom-width: 0; 329 | background-position: top; 330 | 331 | &.item-input-inset { 332 | position: absolute; 333 | } 334 | } 335 | 336 | // Don't render padding if the bar is just for tabs 337 | .bar-tabs { 338 | padding: 0; 339 | } 340 | 341 | .bar-subheader { 342 | top: $bar-height; 343 | display: block; 344 | } 345 | .bar-subfooter { 346 | bottom: $bar-height; 347 | display: block; 348 | } 349 | -------------------------------------------------------------------------------- /client/lib/ionic/js/angular/angular-animate.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.25 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(F,e,O){'use strict';e.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(G,s,g){g=g.ngAnimateChildren;e.isString(g)&&0===g.length?s.data("$$ngAnimateChildren",!0):G.$watch(g,function(e){s.data("$$ngAnimateChildren",!!e)})}}).factory("$$animateReflow",["$$rAF","$document",function(e,s){return function(g){return e(function(){g()})}}]).config(["$provide","$animateProvider",function(G,s){function g(e){for(var g=0;g=y&&b>=v&&e()}var h=g(b);a=b.data(q);if(-1!=h.getAttribute("class").indexOf(d)&&a){var m="";u(d.split(" "),function(a,b){m+=(0 .tabs, 46 | .tabs.tabs-light { 47 | @include tab-style($tabs-light-bg, $tabs-light-border, $tabs-light-text); 48 | @include tab-badge-style($tabs-light-text, $tabs-light-bg); 49 | } 50 | .tabs-stable > .tabs, 51 | .tabs.tabs-stable { 52 | @include tab-style($tabs-stable-bg, $tabs-stable-border, $tabs-stable-text); 53 | @include tab-badge-style($tabs-stable-text, $tabs-stable-bg); 54 | } 55 | .tabs-positive > .tabs, 56 | .tabs.tabs-positive { 57 | @include tab-style($tabs-positive-bg, $tabs-positive-border, $tabs-positive-text); 58 | @include tab-badge-style($tabs-positive-text, $tabs-positive-bg); 59 | } 60 | .tabs-calm > .tabs, 61 | .tabs.tabs-calm { 62 | @include tab-style($tabs-calm-bg, $tabs-calm-border, $tabs-calm-text); 63 | @include tab-badge-style($tabs-calm-text, $tabs-calm-bg); 64 | } 65 | .tabs-assertive > .tabs, 66 | .tabs.tabs-assertive { 67 | @include tab-style($tabs-assertive-bg, $tabs-assertive-border, $tabs-assertive-text); 68 | @include tab-badge-style($tabs-assertive-text, $tabs-assertive-bg); 69 | } 70 | .tabs-balanced > .tabs, 71 | .tabs.tabs-balanced { 72 | @include tab-style($tabs-balanced-bg, $tabs-balanced-border, $tabs-balanced-text); 73 | @include tab-badge-style($tabs-balanced-text, $tabs-balanced-bg); 74 | } 75 | .tabs-energized > .tabs, 76 | .tabs.tabs-energized { 77 | @include tab-style($tabs-energized-bg, $tabs-energized-border, $tabs-energized-text); 78 | @include tab-badge-style($tabs-energized-text, $tabs-energized-bg); 79 | } 80 | .tabs-royal > .tabs, 81 | .tabs.tabs-royal { 82 | @include tab-style($tabs-royal-bg, $tabs-royal-border, $tabs-royal-text); 83 | @include tab-badge-style($tabs-royal-text, $tabs-royal-bg); 84 | } 85 | .tabs-dark > .tabs, 86 | .tabs.tabs-dark { 87 | @include tab-style($tabs-dark-bg, $tabs-dark-border, $tabs-dark-text); 88 | @include tab-badge-style($tabs-dark-text, $tabs-dark-bg); 89 | } 90 | 91 | @mixin tabs-striped($style, $color, $background) { 92 | &.#{$style} { 93 | .tabs{ 94 | background-color: $background; 95 | } 96 | .tab-item { 97 | color: rgba($color, $tabs-striped-off-opacity); 98 | opacity: 1; 99 | .badge{ 100 | opacity:$tabs-striped-off-opacity; 101 | } 102 | &.tab-item-active, 103 | &.active, 104 | &.activated { 105 | margin-top: -$tabs-striped-border-width; 106 | color: $color; 107 | border-style: solid; 108 | border-width: $tabs-striped-border-width 0 0 0; 109 | border-color: $color; 110 | .badge{ 111 | top:$tabs-striped-border-width; 112 | opacity: 1; 113 | } 114 | } 115 | } 116 | } 117 | &.tabs-top{ 118 | .tab-item { 119 | &.tab-item-active, 120 | &.active, 121 | &.activated { 122 | .badge { 123 | top: 4%; 124 | } 125 | } 126 | } 127 | } 128 | } 129 | 130 | @mixin tabs-background($style, $color) { 131 | &.#{$style} { 132 | .tabs { 133 | background-color: $color; 134 | } 135 | } 136 | } 137 | 138 | @mixin tabs-color($style, $color) { 139 | &.#{$style} { 140 | .tab-item { 141 | color: rgba($color, $tabs-striped-off-opacity); 142 | opacity: 1; 143 | .badge{ 144 | opacity:$tabs-striped-off-opacity; 145 | } 146 | &.tab-item-active, 147 | &.active, 148 | &.activated { 149 | margin-top: -$tabs-striped-border-width; 150 | color: $color; 151 | border: 0 solid $color; 152 | border-top-width: $tabs-striped-border-width; 153 | .badge{ 154 | top:$tabs-striped-border-width; 155 | opacity: 1; 156 | } 157 | } 158 | } 159 | } 160 | } 161 | 162 | .tabs-striped { 163 | .tabs { 164 | background-color: white; 165 | background-image: none; 166 | border: none; 167 | box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15); 168 | padding-top: $tabs-striped-border-width; 169 | } 170 | .tab-item { 171 | // default android tab style 172 | &.tab-item-active, 173 | &.active, 174 | &.activated { 175 | margin-top: -$tabs-striped-border-width; 176 | border-style: solid; 177 | border-width: $tabs-striped-border-width 0 0 0; 178 | border-color: $dark; 179 | } 180 | } 181 | @include tabs-striped('tabs-light', $light, $dark); 182 | @include tabs-striped('tabs-stable', $stable, $dark); 183 | @include tabs-striped('tabs-positive', $positive, $light); 184 | @include tabs-striped('tabs-calm', $calm, $light); 185 | @include tabs-striped('tabs-assertive', $assertive, $light); 186 | @include tabs-striped('tabs-balanced', $balanced, $light); 187 | @include tabs-striped('tabs-energized', $energized, $light); 188 | @include tabs-striped('tabs-royal', $royal, $light); 189 | @include tabs-striped('tabs-dark', $dark, $light); 190 | 191 | 192 | @include tabs-background('tabs-background-light', $light); 193 | @include tabs-background('tabs-background-stable', $stable); 194 | @include tabs-background('tabs-background-positive', $positive); 195 | @include tabs-background('tabs-background-calm', $calm); 196 | @include tabs-background('tabs-background-assertive', $assertive); 197 | @include tabs-background('tabs-background-balanced', $balanced); 198 | @include tabs-background('tabs-background-energized',$energized); 199 | @include tabs-background('tabs-background-royal', $royal); 200 | @include tabs-background('tabs-background-dark', $dark); 201 | 202 | @include tabs-color('tabs-color-light', $light); 203 | @include tabs-color('tabs-color-stable', $stable); 204 | @include tabs-color('tabs-color-positive', $positive); 205 | @include tabs-color('tabs-color-calm', $calm); 206 | @include tabs-color('tabs-color-assertive', $assertive); 207 | @include tabs-color('tabs-color-balanced', $balanced); 208 | @include tabs-color('tabs-color-energized',$energized); 209 | @include tabs-color('tabs-color-royal', $royal); 210 | @include tabs-color('tabs-color-dark', $dark); 211 | } 212 | 213 | .tabs-top { 214 | &.tabs-striped { 215 | padding-bottom:0; 216 | .tab-item{ 217 | background: transparent; 218 | // animate the top bar, leave bottom for platform consistency 219 | -webkit-transition: all .1s ease; 220 | -moz-transition: all .1s ease; 221 | -ms-transition: all .1s ease; 222 | -o-transition: all .1s ease; 223 | transition: all .1s ease; 224 | &.tab-item-active, 225 | &.active, 226 | &.activated { 227 | margin-top: 0; 228 | margin-bottom: -$tabs-striped-border-width; 229 | border-width: 0px 0px $tabs-striped-border-width 0px !important; 230 | border-style: solid; 231 | } 232 | .badge{ 233 | -webkit-transition: all .2s ease; 234 | -moz-transition: all .2s ease; 235 | -ms-transition: all .2s ease; 236 | -o-transition: all .2s ease; 237 | transition: all .2s ease; 238 | } 239 | } 240 | } 241 | } 242 | 243 | /* Allow parent element to have tabs-top */ 244 | /* If you change this, change platform.scss as well */ 245 | .tabs-top > .tabs, 246 | .tabs.tabs-top { 247 | top: $bar-height; 248 | padding-top: 0; 249 | background-position: bottom; 250 | .tab-item { 251 | &.tab-item-active, 252 | &.active, 253 | &.activated { 254 | .badge { 255 | top: 4%; 256 | } 257 | } 258 | } 259 | } 260 | .tabs-top ~ .bar-header { 261 | border-bottom-width: 0; 262 | } 263 | 264 | .tab-item { 265 | @include flex(1); 266 | display: block; 267 | overflow: hidden; 268 | 269 | max-width: $tab-item-max-width; 270 | height: 100%; 271 | 272 | color: inherit; 273 | text-align: center; 274 | text-decoration: none; 275 | text-overflow: ellipsis; 276 | white-space: nowrap; 277 | 278 | font-weight: 400; 279 | font-size: $tabs-text-font-size; 280 | font-family: $font-family-light-sans-serif; 281 | 282 | opacity: 0.7; 283 | 284 | &:hover { 285 | cursor: pointer; 286 | } 287 | &.tab-hidden{ 288 | display:none; 289 | } 290 | } 291 | 292 | .tabs-item-hide > .tabs, 293 | .tabs.tabs-item-hide { 294 | display: none; 295 | } 296 | 297 | .tabs-icon-top > .tabs .tab-item, 298 | .tabs-icon-top.tabs .tab-item, 299 | .tabs-icon-bottom > .tabs .tab-item, 300 | .tabs-icon-bottom.tabs .tab-item { 301 | font-size: $tabs-text-font-size-side-icon; 302 | line-height: $tabs-text-font-size; 303 | } 304 | 305 | .tab-item .icon { 306 | display: block; 307 | margin: 0 auto; 308 | height: $tabs-icon-size; 309 | font-size: $tabs-icon-size; 310 | } 311 | 312 | .tabs-icon-left.tabs .tab-item, 313 | .tabs-icon-left > .tabs .tab-item, 314 | .tabs-icon-right.tabs .tab-item, 315 | .tabs-icon-right > .tabs .tab-item { 316 | font-size: $tabs-text-font-size-side-icon; 317 | 318 | .icon { 319 | display: inline-block; 320 | vertical-align: top; 321 | margin-top: -.1em; 322 | 323 | &:before { 324 | font-size: $tabs-icon-size - 8; 325 | line-height: $tabs-height; 326 | } 327 | } 328 | } 329 | 330 | .tabs-icon-left > .tabs .tab-item .icon, 331 | .tabs-icon-left.tabs .tab-item .icon { 332 | padding-right: 3px; 333 | } 334 | 335 | .tabs-icon-right > .tabs .tab-item .icon, 336 | .tabs-icon-right.tabs .tab-item .icon { 337 | padding-left: 3px; 338 | } 339 | 340 | .tabs-icon-only > .tabs .icon, 341 | .tabs-icon-only.tabs .icon { 342 | line-height: inherit; 343 | } 344 | 345 | 346 | .tab-item.has-badge { 347 | position: relative; 348 | } 349 | 350 | .tab-item .badge { 351 | position: absolute; 352 | top: 4%; 353 | right: 33%; // fallback 354 | right: calc(50% - 26px); 355 | padding: $tabs-badge-padding; 356 | height: auto; 357 | font-size: $tabs-badge-font-size; 358 | line-height: $tabs-badge-font-size + 4; 359 | } 360 | 361 | 362 | /* Navigational tab */ 363 | 364 | /* Active state for tab */ 365 | .tab-item.tab-item-active, 366 | .tab-item.active, 367 | .tab-item.activated { 368 | opacity: 1; 369 | 370 | &.tab-item-light { 371 | color: $light; 372 | } 373 | &.tab-item-stable { 374 | color: $stable; 375 | } 376 | &.tab-item-positive { 377 | color: $positive; 378 | } 379 | &.tab-item-calm { 380 | color: $calm; 381 | } 382 | &.tab-item-assertive { 383 | color: $assertive; 384 | } 385 | &.tab-item-balanced { 386 | color: $balanced; 387 | } 388 | &.tab-item-energized { 389 | color: $energized; 390 | } 391 | &.tab-item-royal { 392 | color: $royal; 393 | } 394 | &.tab-item-dark { 395 | color: $dark; 396 | } 397 | } 398 | 399 | .item.tabs { 400 | @include display-flex(); 401 | padding: 0; 402 | 403 | .icon:before { 404 | position: relative; 405 | } 406 | } 407 | 408 | .tab-item.disabled, 409 | .tab-item[disabled] { 410 | opacity: .4; 411 | cursor: default; 412 | pointer-events: none; 413 | } 414 | 415 | /** Platform styles **/ 416 | 417 | .tab-item.tab-item-ios { 418 | } 419 | .tab-item.tab-item-android { 420 | border-top: 2px solid inherit; 421 | } 422 | -------------------------------------------------------------------------------- /client/lib/ionic/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | 2 | // Button Mixins 3 | // -------------------------------------------------- 4 | 5 | @mixin button-style($bg-color, $border-color, $active-bg-color, $active-border-color, $color) { 6 | border-color: $border-color; 7 | background-color: $bg-color; 8 | color: $color; 9 | 10 | // Give desktop users something to play with 11 | &:hover { 12 | color: $color; 13 | text-decoration: none; 14 | } 15 | &.active, 16 | &.activated { 17 | border-color: $active-border-color; 18 | background-color: $active-bg-color; 19 | box-shadow: inset 0px 1px 3px rgba(0,0,0,0.15); 20 | } 21 | } 22 | 23 | @mixin button-clear($color, $font-size:"") { 24 | &.button-clear { 25 | border-color: transparent; 26 | background: none; 27 | box-shadow: none; 28 | color: $color; 29 | 30 | @if $font-size != "" { 31 | font-size: $font-size; 32 | } 33 | } 34 | &.button-icon { 35 | border-color: transparent; 36 | background: none; 37 | } 38 | } 39 | 40 | @mixin button-outline($color, $text-color:"") { 41 | &.button-outline { 42 | border-color: $color; 43 | background: transparent; 44 | @if $text-color == "" { 45 | $text-color: $color; 46 | } 47 | color: $text-color; 48 | &.active, 49 | &.activated { 50 | background-color: $color; 51 | box-shadow: none; 52 | color: #fff; 53 | } 54 | } 55 | } 56 | 57 | 58 | // Bar Mixins 59 | // -------------------------------------------------- 60 | 61 | @mixin bar-style($bg-color, $border-color, $color) { 62 | border-color: $border-color; 63 | background-color: $bg-color; 64 | background-image: linear-gradient(0deg, $border-color, $border-color 50%, transparent 50%); 65 | color: $color; 66 | 67 | .title { 68 | color: $color; 69 | } 70 | } 71 | 72 | 73 | // Tab Mixins 74 | // -------------------------------------------------- 75 | 76 | @mixin tab-style($bg-color, $border-color, $color) { 77 | border-color: $border-color; 78 | background-color: $bg-color; 79 | background-image: linear-gradient(0deg, $border-color, $border-color 50%, transparent 50%); 80 | color: $color; 81 | } 82 | 83 | @mixin tab-badge-style($bg-color, $color) { 84 | .tab-item .badge { 85 | background-color: $bg-color; 86 | color: $color; 87 | } 88 | } 89 | 90 | 91 | // Item Mixins 92 | // -------------------------------------------------- 93 | 94 | @mixin item-style($bg-color, $border-color, $color) { 95 | border-color: $border-color; 96 | background-color: $bg-color; 97 | color: $color; 98 | } 99 | 100 | @mixin item-active-style($active-bg-color, $active-border-color) { 101 | border-color: $active-border-color; 102 | background-color: $active-bg-color; 103 | } 104 | 105 | 106 | // Badge Mixins 107 | // -------------------------------------------------- 108 | 109 | @mixin badge-style($bg-color, $color) { 110 | background-color: $bg-color; 111 | color: $color; 112 | } 113 | 114 | 115 | // Range Mixins 116 | // -------------------------------------------------- 117 | 118 | @mixin range-style($track-bg-color) { 119 | &::-webkit-slider-thumb:before { 120 | background: $track-bg-color; 121 | } 122 | } 123 | 124 | 125 | // Checkbox Mixins 126 | // -------------------------------------------------- 127 | 128 | @mixin checkbox-style($off-border-color, $on-bg-color) { 129 | & input:before, 130 | & .checkbox-icon:before { 131 | border-color: $off-border-color; 132 | } 133 | 134 | // what the background looks like when its checked 135 | & input:checked:before, 136 | & input:checked + .checkbox-icon:before { 137 | background: $on-bg-color; 138 | } 139 | } 140 | 141 | 142 | // Toggle Mixins 143 | // -------------------------------------------------- 144 | 145 | @mixin toggle-style($on-border-color, $on-bg-color) { 146 | // the track when the toggle is "on" 147 | & input:checked + .track { 148 | border-color: $on-border-color; 149 | background-color: $on-bg-color; 150 | } 151 | } 152 | 153 | 154 | // Clearfix 155 | // -------------------------------------------------- 156 | 157 | @mixin clearfix { 158 | *zoom: 1; 159 | &:before, 160 | &:after { 161 | display: table; 162 | content: ""; 163 | line-height: 0; 164 | } 165 | &:after { 166 | clear: both; 167 | } 168 | } 169 | 170 | 171 | // Placeholder text 172 | // -------------------------------------------------- 173 | 174 | @mixin placeholder($color: $input-color-placeholder, $text-indent: 0) { 175 | &::-moz-placeholder { /* Firefox 19+ */ 176 | color: $color; 177 | } 178 | &:-ms-input-placeholder { 179 | color: $color; 180 | } 181 | &::-webkit-input-placeholder { 182 | color: $color; 183 | // Safari placeholder margin issue 184 | text-indent: $text-indent; 185 | } 186 | } 187 | 188 | 189 | // Text Mixins 190 | // -------------------------------------------------- 191 | 192 | @mixin text-size-adjust($value: none) { 193 | -webkit-text-size-adjust: $value; 194 | -moz-text-size-adjust: $value; 195 | text-size-adjust: $value; 196 | } 197 | @mixin tap-highlight-transparent() { 198 | -webkit-tap-highlight-color: rgba(0,0,0,0); 199 | -webkit-tap-highlight-color: transparent; // For some Androids 200 | } 201 | @mixin touch-callout($value: none) { 202 | -webkit-touch-callout: $value; 203 | } 204 | 205 | 206 | // Font Mixins 207 | // -------------------------------------------------- 208 | 209 | @mixin font-family-serif() { 210 | font-family: $serif-font-family; 211 | } 212 | @mixin font-family-sans-serif() { 213 | font-family: $sans-font-family; 214 | } 215 | @mixin font-family-monospace() { 216 | font-family: $mono-font-family; 217 | } 218 | @mixin font-shorthand($size: $base-font-size, $weight: normal, $line-height: $base-line-height) { 219 | font-weight: $weight; 220 | font-size: $size; 221 | line-height: $line-height; 222 | } 223 | @mixin font-serif($size: $base-font-size, $weight: normal, $line-height: $base-line-height) { 224 | @include font-family-serif(); 225 | @include font-shorthand($size, $weight, $line-height); 226 | } 227 | @mixin font-sans-serif($size: $base-font-size, $weight: normal, $line-height: $base-line-height) { 228 | @include font-family-sans-serif(); 229 | @include font-shorthand($size, $weight, $line-height); 230 | } 231 | @mixin font-monospace($size: $base-font-size, $weight: normal, $line-height: $base-line-height) { 232 | @include font-family-monospace(); 233 | @include font-shorthand($size, $weight, $line-height); 234 | } 235 | @mixin font-smoothing($font-smoothing) { 236 | -webkit-font-smoothing: $font-smoothing; 237 | font-smoothing: $font-smoothing; 238 | } 239 | 240 | 241 | // Appearance 242 | // -------------------------------------------------- 243 | 244 | @mixin appearance($val) { 245 | -webkit-appearance: $val; 246 | -moz-appearance: $val; 247 | appearance: $val; 248 | } 249 | 250 | 251 | // Border Radius Mixins 252 | // -------------------------------------------------- 253 | 254 | @mixin border-radius($radius) { 255 | -webkit-border-radius: $radius; 256 | -moz-border-radius: $radius; 257 | border-radius: $radius; 258 | } 259 | 260 | // Single Corner Border Radius 261 | @mixin border-top-left-radius($radius) { 262 | -webkit-border-top-left-radius: $radius; 263 | -moz-border-radius-topleft: $radius; 264 | border-top-left-radius: $radius; 265 | } 266 | @mixin border-top-right-radius($radius) { 267 | -webkit-border-top-right-radius: $radius; 268 | -moz-border-radius-topright: $radius; 269 | border-top-right-radius: $radius; 270 | } 271 | @mixin border-bottom-right-radius($radius) { 272 | -webkit-border-bottom-right-radius: $radius; 273 | -moz-border-radius-bottomright: $radius; 274 | border-bottom-right-radius: $radius; 275 | } 276 | @mixin border-bottom-left-radius($radius) { 277 | -webkit-border-bottom-left-radius: $radius; 278 | -moz-border-radius-bottomleft: $radius; 279 | border-bottom-left-radius: $radius; 280 | } 281 | 282 | // Single Side Border Radius 283 | @mixin border-top-radius($radius) { 284 | @include border-top-right-radius($radius); 285 | @include border-top-left-radius($radius); 286 | } 287 | @mixin border-right-radius($radius) { 288 | @include border-top-right-radius($radius); 289 | @include border-bottom-right-radius($radius); 290 | } 291 | @mixin border-bottom-radius($radius) { 292 | @include border-bottom-right-radius($radius); 293 | @include border-bottom-left-radius($radius); 294 | } 295 | @mixin border-left-radius($radius) { 296 | @include border-top-left-radius($radius); 297 | @include border-bottom-left-radius($radius); 298 | } 299 | 300 | 301 | // Box shadows 302 | // -------------------------------------------------- 303 | 304 | @mixin box-shadow($shadow...) { 305 | -webkit-box-shadow: $shadow; 306 | -moz-box-shadow: $shadow; 307 | box-shadow: $shadow; 308 | } 309 | 310 | 311 | // Transition Mixins 312 | // -------------------------------------------------- 313 | 314 | @mixin transition($transition...) { 315 | -webkit-transition: $transition; 316 | -moz-transition: $transition; 317 | transition: $transition; 318 | } 319 | @mixin transition-delay($transition-delay) { 320 | -webkit-transition-delay: $transition-delay; 321 | -moz-transition-delay: $transition-delay; 322 | transition-delay: $transition-delay; 323 | } 324 | @mixin transition-duration($transition-duration) { 325 | -webkit-transition-duration: $transition-duration; 326 | -moz-transition-duration: $transition-duration; 327 | transition-duration: $transition-duration; 328 | } 329 | @mixin transition-timing-function($transition-timing) { 330 | -webkit-transition-timing-function: $transition-timing; 331 | -moz-transition-timing-function: $transition-timing; 332 | transition-timing-function: $transition-timing; 333 | } 334 | @mixin transition-property($property) { 335 | -webkit-transition-property: $property; 336 | -moz-transition-property: $property; 337 | transition-property: $property; 338 | } 339 | @mixin transition-transform($properties...) { 340 | // special case cuz of transform vendor prefixes 341 | -webkit-transition: -webkit-transform $properties; 342 | -moz-transition: -moz-transform $properties; 343 | transition: transform $properties; 344 | } 345 | 346 | 347 | // Animation Mixins 348 | // -------------------------------------------------- 349 | 350 | @mixin animation($animation) { 351 | -webkit-animation: $animation; 352 | -moz-animation: $animation; 353 | animation: $animation; 354 | } 355 | @mixin animation-duration($duration) { 356 | -webkit-animation-duration: $duration; 357 | -moz-animation-duration: $duration; 358 | animation-duration: $duration; 359 | } 360 | @mixin animation-direction($direction) { 361 | -webkit-animation-direction: $direction; 362 | -moz-animation-direction: $direction; 363 | animation-direction: $direction; 364 | } 365 | @mixin animation-timing-function($animation-timing) { 366 | -webkit-animation-timing-function: $animation-timing; 367 | -moz-animation-timing-function: $animation-timing; 368 | animation-timing-function: $animation-timing; 369 | } 370 | @mixin animation-fill-mode($fill-mode) { 371 | -webkit-animation-fill-mode: $fill-mode; 372 | -moz-animation-fill-mode: $fill-mode; 373 | animation-fill-mode: $fill-mode; 374 | } 375 | @mixin animation-name($name) { 376 | -webkit-animation-name: $name; 377 | -moz-animation-name: $name; 378 | animation-name: $name; 379 | } 380 | @mixin animation-iteration-count($count) { 381 | -webkit-animation-iteration-count: $count; 382 | -moz-animation-iteration-count: $count; 383 | animation-iteration-count: $count; 384 | } 385 | 386 | 387 | // Transformation Mixins 388 | // -------------------------------------------------- 389 | 390 | @mixin rotate($degrees) { 391 | @include transform( rotate($degrees) ); 392 | } 393 | @mixin scale($ratio) { 394 | @include transform( scale($ratio) ); 395 | } 396 | @mixin translate($x, $y) { 397 | @include transform( translate($x, $y) ); 398 | } 399 | @mixin skew($x, $y) { 400 | @include transform( skew($x, $y) ); 401 | -webkit-backface-visibility: hidden; 402 | } 403 | @mixin translate3d($x, $y, $z) { 404 | @include transform( translate3d($x, $y, $z) ); 405 | } 406 | @mixin translateZ($z) { 407 | @include transform( translateZ($z) ); 408 | } 409 | @mixin transform($val) { 410 | -webkit-transform: $val; 411 | -moz-transform: $val; 412 | transform: $val; 413 | } 414 | 415 | @mixin transform-origin($left, $top) { 416 | -webkit-transform-origin: $left $top; 417 | -moz-transform-origin: $left $top; 418 | transform-origin: $left $top; 419 | } 420 | 421 | 422 | // Backface visibility 423 | // -------------------------------------------------- 424 | // Prevent browsers from flickering when using CSS 3D transforms. 425 | // Default value is `visible`, but can be changed to `hidden 426 | 427 | @mixin backface-visibility($visibility){ 428 | -webkit-backface-visibility: $visibility; 429 | backface-visibility: $visibility; 430 | } 431 | 432 | 433 | // Background clipping 434 | // -------------------------------------------------- 435 | 436 | @mixin background-clip($clip) { 437 | -webkit-background-clip: $clip; 438 | -moz-background-clip: $clip; 439 | background-clip: $clip; 440 | } 441 | 442 | 443 | // Background sizing 444 | // -------------------------------------------------- 445 | 446 | @mixin background-size($size) { 447 | -webkit-background-size: $size; 448 | -moz-background-size: $size; 449 | background-size: $size; 450 | } 451 | 452 | 453 | // Box sizing 454 | // -------------------------------------------------- 455 | 456 | @mixin box-sizing($boxmodel) { 457 | -webkit-box-sizing: $boxmodel; 458 | -moz-box-sizing: $boxmodel; 459 | box-sizing: $boxmodel; 460 | } 461 | 462 | 463 | // User select 464 | // -------------------------------------------------- 465 | 466 | @mixin user-select($select) { 467 | -webkit-user-select: $select; 468 | -moz-user-select: $select; 469 | -ms-user-select: $select; 470 | user-select: $select; 471 | } 472 | 473 | 474 | // Content Columns 475 | // -------------------------------------------------- 476 | 477 | @mixin content-columns($columnCount, $columnGap: $grid-gutter-width) { 478 | -webkit-column-count: $columnCount; 479 | -moz-column-count: $columnCount; 480 | column-count: $columnCount; 481 | -webkit-column-gap: $columnGap; 482 | -moz-column-gap: $columnGap; 483 | column-gap: $columnGap; 484 | } 485 | 486 | 487 | // Flexbox Mixins 488 | // -------------------------------------------------- 489 | // http://philipwalton.github.io/solved-by-flexbox/ 490 | // https://github.com/philipwalton/solved-by-flexbox 491 | 492 | @mixin display-flex { 493 | display: -webkit-box; 494 | display: -webkit-flex; 495 | display: -moz-box; 496 | display: -moz-flex; 497 | display: -ms-flexbox; 498 | display: flex; 499 | } 500 | 501 | @mixin dislay-inline-flex { 502 | display: -webkit-inline-box; 503 | display: -webkit-inline-flex; 504 | display: -moz-inline-flex; 505 | display: -ms-inline-flexbox; 506 | display: inline-flex; 507 | } 508 | 509 | @mixin flex-direction($value: row) { 510 | @if $value == row-reverse { 511 | -webkit-box-direction: reverse; 512 | -webkit-box-orient: horizontal; 513 | } @else if $value == column { 514 | -webkit-box-direction: normal; 515 | -webkit-box-orient: vertical; 516 | } @else if $value == column-reverse { 517 | -webkit-box-direction: reverse; 518 | -webkit-box-orient: vertical; 519 | } @else { 520 | -webkit-box-direction: normal; 521 | -webkit-box-orient: horizontal; 522 | } 523 | -webkit-flex-direction: $value; 524 | -moz-flex-direction: $value; 525 | -ms-flex-direction: $value; 526 | flex-direction: $value; 527 | } 528 | 529 | @mixin flex-wrap($value: nowrap) { 530 | // No Webkit Box fallback. 531 | -webkit-flex-wrap: $value; 532 | -moz-flex-wrap: $value; 533 | @if $value == nowrap { 534 | -ms-flex-wrap: none; 535 | } @else { 536 | -ms-flex-wrap: $value; 537 | } 538 | flex-wrap: $value; 539 | } 540 | 541 | @mixin flex($fg: 1, $fs: null, $fb: null) { 542 | -webkit-box-flex: $fg; 543 | -webkit-flex: $fg $fs $fb; 544 | -moz-box-flex: $fg; 545 | -moz-flex: $fg $fs $fb; 546 | -ms-flex: $fg $fs $fb; 547 | flex: $fg $fs $fb; 548 | } 549 | 550 | @mixin flex-flow($values: (row nowrap)) { 551 | // No Webkit Box fallback. 552 | -webkit-flex-flow: $values; 553 | -moz-flex-flow: $values; 554 | -ms-flex-flow: $values; 555 | flex-flow: $values; 556 | } 557 | 558 | @mixin align-items($value: stretch) { 559 | @if $value == flex-start { 560 | -webkit-box-align: start; 561 | -ms-flex-align: start; 562 | } @else if $value == flex-end { 563 | -webkit-box-align: end; 564 | -ms-flex-align: end; 565 | } @else { 566 | -webkit-box-align: $value; 567 | -ms-flex-align: $value; 568 | } 569 | -webkit-align-items: $value; 570 | -moz-align-items: $value; 571 | align-items: $value; 572 | } 573 | 574 | @mixin align-self($value: auto) { 575 | -webkit-align-self: $value; 576 | -moz-align-self: $value; 577 | @if $value == flex-start { 578 | -ms-flex-item-align: start; 579 | } @else if $value == flex-end { 580 | -ms-flex-item-align: end; 581 | } @else { 582 | -ms-flex-item-align: $value; 583 | } 584 | align-self: $value; 585 | } 586 | 587 | @mixin align-content($value: stretch) { 588 | -webkit-align-content: $value; 589 | -moz-align-content: $value; 590 | @if $value == flex-start { 591 | -ms-flex-line-pack: start; 592 | } @else if $value == flex-end { 593 | -ms-flex-line-pack: end; 594 | } @else { 595 | -ms-flex-line-pack: $value; 596 | } 597 | align-content: $value; 598 | } 599 | 600 | @mixin justify-content($value: stretch) { 601 | @if $value == flex-start { 602 | -webkit-box-pack: start; 603 | -ms-flex-pack: start; 604 | } @else if $value == flex-end { 605 | -webkit-box-pack: end; 606 | -ms-flex-pack: end; 607 | } @else if $value == space-between { 608 | -webkit-box-pack: justify; 609 | -ms-flex-pack: justify; 610 | } @else { 611 | -webkit-box-pack: $value; 612 | -ms-flex-pack: $value; 613 | } 614 | -webkit-justify-content: $value; 615 | -moz-justify-content: $value; 616 | justify-content: $value; 617 | } 618 | 619 | @mixin responsive-grid-break($selector, $max-width) { 620 | @media (max-width: $max-width) { 621 | #{$selector} { 622 | -webkit-box-direction: normal; 623 | -moz-box-direction: normal; 624 | -webkit-box-orient: vertical; 625 | -moz-box-orient: vertical; 626 | -webkit-flex-direction: column; 627 | -ms-flex-direction: column; 628 | flex-direction: column; 629 | 630 | .col, .col-10, .col-20, .col-25, .col-33, .col-34, .col-50, .col-66, .col-67, .col-75, .col-80, .col-90 { 631 | @include flex(1); 632 | margin-bottom: ($grid-padding-width * 3) / 2; 633 | margin-left: 0; 634 | max-width: 100%; 635 | width: 100%; 636 | } 637 | } 638 | } 639 | } 640 | -------------------------------------------------------------------------------- /client/lib/ionic/js/angular-ui/angular-ui-router.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * State-based routing for AngularJS 3 | * @version v0.2.10 4 | * @link http://angular-ui.github.com/ 5 | * @license MIT License, http://www.opensource.org/licenses/MIT 6 | */ 7 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(a,b,c){"use strict";function d(a,b){return I(new(I(function(){},{prototype:a})),b)}function e(a){return H(arguments,function(b){b!==a&&H(b,function(b,c){a.hasOwnProperty(c)||(a[c]=b)})}),a}function f(a,b){var c=[];for(var d in a.path){if(a.path[d]!==b.path[d])break;c.push(a.path[d])}return c}function g(a,b){if(Array.prototype.indexOf)return a.indexOf(b,Number(arguments[2])||0);var c=a.length>>>0,d=Number(arguments[2])||0;for(d=0>d?Math.ceil(d):Math.floor(d),0>d&&(d+=c);c>d;d++)if(d in a&&a[d]===b)return d;return-1}function h(a,b,c,d){var e,h=f(c,d),i={},j=[];for(var k in h)if(h[k].params&&h[k].params.length){e=h[k].params;for(var l in e)g(j,e[l])>=0||(j.push(e[l]),i[e[l]]=a[e[l]])}return I({},i,b)}function i(a,b){var c={};return H(a,function(a){var d=b[a];c[a]=null!=d?String(d):null}),c}function j(a,b,c){if(!c){c=[];for(var d in a)c.push(d)}for(var e=0;e "));if(o[c]=d,E(a))m.push(c,[function(){return b.get(a)}],h);else{var e=b.annotate(a);H(e,function(a){a!==c&&g.hasOwnProperty(a)&&k(g[a],a)}),m.push(c,a,e)}n.pop(),o[c]=f}}function l(a){return F(a)&&a.then&&a.$$promises}if(!F(g))throw new Error("'invocables' must be an object");var m=[],n=[],o={};return H(g,k),g=n=o=null,function(d,f,g){function h(){--s||(t||e(r,f.$$values),p.$$values=r,p.$$promises=!0,o.resolve(r))}function k(a){p.$$failure=a,o.reject(a)}function n(c,e,f){function i(a){l.reject(a),k(a)}function j(){if(!C(p.$$failure))try{l.resolve(b.invoke(e,g,r)),l.promise.then(function(a){r[c]=a,h()},i)}catch(a){i(a)}}var l=a.defer(),m=0;H(f,function(a){q.hasOwnProperty(a)&&!d.hasOwnProperty(a)&&(m++,q[a].then(function(b){r[a]=b,--m||j()},i))}),m||j(),q[c]=l.promise}if(l(d)&&g===c&&(g=f,f=d,d=null),d){if(!F(d))throw new Error("'locals' must be an object")}else d=i;if(f){if(!l(f))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else f=j;var o=a.defer(),p=o.promise,q=p.$$promises={},r=I({},d),s=1+m.length/3,t=!1;if(C(f.$$failure))return k(f.$$failure),p;f.$$values?(t=e(r,f.$$values),h()):(I(q,f.$$promises),f.then(h,k));for(var u=0,v=m.length;v>u;u+=3)d.hasOwnProperty(m[u])?h():n(m[u],m[u+1],m[u+2]);return p}},this.resolve=function(a,b,c,d){return this.study(a)(b,c,d)}}function m(a,b,c){this.fromConfig=function(a,b,c){return C(a.template)?this.fromString(a.template,b):C(a.templateUrl)?this.fromUrl(a.templateUrl,b):C(a.templateProvider)?this.fromProvider(a.templateProvider,b,c):null},this.fromString=function(a,b){return D(a)?a(b):a},this.fromUrl=function(c,d){return D(c)&&(c=c(d)),null==c?null:a.get(c,{cache:b}).then(function(a){return a.data})},this.fromProvider=function(a,b,d){return c.invoke(a,null,d||{params:b})}}function n(a){function b(b){if(!/^\w+(-+\w+)*$/.test(b))throw new Error("Invalid parameter name '"+b+"' in pattern '"+a+"'");if(f[b])throw new Error("Duplicate parameter name '"+b+"' in pattern '"+a+"'");f[b]=!0,j.push(b)}function c(a){return a.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&")}var d,e=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,f={},g="^",h=0,i=this.segments=[],j=this.params=[];this.source=a;for(var k,l,m;(d=e.exec(a))&&(k=d[2]||d[3],l=d[4]||("*"==d[1]?".*":"[^/]*"),m=a.substring(h,d.index),!(m.indexOf("?")>=0));)g+=c(m)+"("+l+")",b(k),i.push(m),h=e.lastIndex;m=a.substring(h);var n=m.indexOf("?");if(n>=0){var o=this.sourceSearch=m.substring(n);m=m.substring(0,n),this.sourcePath=a.substring(0,h+n),H(o.substring(1).split(/[&?]/),b)}else this.sourcePath=a,this.sourceSearch="";g+=c(m)+"$",i.push(m),this.regexp=new RegExp(g),this.prefix=i[0]}function o(){this.compile=function(a){return new n(a)},this.isMatcher=function(a){return F(a)&&D(a.exec)&&D(a.format)&&D(a.concat)},this.$get=function(){return this}}function p(a){function b(a){var b=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(a.source);return null!=b?b[1].replace(/\\(.)/g,"$1"):""}function c(a,b){return a.replace(/\$(\$|\d{1,2})/,function(a,c){return b["$"===c?0:Number(c)]})}function d(a,b,c){if(!c)return!1;var d=a.invoke(b,b,{$match:c});return C(d)?d:!0}var e=[],f=null;this.rule=function(a){if(!D(a))throw new Error("'rule' must be a function");return e.push(a),this},this.otherwise=function(a){if(E(a)){var b=a;a=function(){return b}}else if(!D(a))throw new Error("'rule' must be a function");return f=a,this},this.when=function(e,f){var g,h=E(f);if(E(e)&&(e=a.compile(e)),!h&&!D(f)&&!G(f))throw new Error("invalid 'handler' in when()");var i={matcher:function(b,c){return h&&(g=a.compile(c),c=["$match",function(a){return g.format(a)}]),I(function(a,e){return d(a,c,b.exec(e.path(),e.search()))},{prefix:E(b.prefix)?b.prefix:""})},regex:function(a,e){if(a.global||a.sticky)throw new Error("when() RegExp must not be global or sticky");return h&&(g=e,e=["$match",function(a){return c(g,a)}]),I(function(b,c){return d(b,e,a.exec(c.path()))},{prefix:b(a)})}},j={matcher:a.isMatcher(e),regex:e instanceof RegExp};for(var k in j)if(j[k])return this.rule(i[k](e,f));throw new Error("invalid 'what' in when()")},this.$get=["$location","$rootScope","$injector",function(a,b,c){function d(b){function d(b){var d=b(c,a);return d?(E(d)&&a.replace().url(d),!0):!1}if(!b||!b.defaultPrevented){var g,h=e.length;for(g=0;h>g;g++)if(d(e[g]))return;f&&d(f)}}return b.$on("$locationChangeSuccess",d),{sync:function(){d()}}}]}function q(a,e,f){function g(a){return 0===a.indexOf(".")||0===a.indexOf("^")}function l(a,b){var d=E(a),e=d?a:a.name,f=g(e);if(f){if(!b)throw new Error("No reference point given for path '"+e+"'");for(var h=e.split("."),i=0,j=h.length,k=b;j>i;i++)if(""!==h[i]||0!==i){if("^"!==h[i])break;if(!k.parent)throw new Error("Path '"+e+"' not valid for state '"+b.name+"'");k=k.parent}else k=b;h=h.slice(i).join("."),e=k.name+(k.name&&h?".":"")+h}var l=w[e];return!l||!d&&(d||l!==a&&l.self!==a)?c:l}function m(a,b){x[a]||(x[a]=[]),x[a].push(b)}function n(b){b=d(b,{self:b,resolve:b.resolve||{},toString:function(){return this.name}});var c=b.name;if(!E(c)||c.indexOf("@")>=0)throw new Error("State must have a valid name");if(w.hasOwnProperty(c))throw new Error("State '"+c+"'' is already defined");var e=-1!==c.indexOf(".")?c.substring(0,c.lastIndexOf(".")):E(b.parent)?b.parent:"";if(e&&!w[e])return m(e,b.self);for(var f in z)D(z[f])&&(b[f]=z[f](b,z.$delegates[f]));if(w[c]=b,!b[y]&&b.url&&a.when(b.url,["$match","$stateParams",function(a,c){v.$current.navigable==b&&j(a,c)||v.transitionTo(b,a,{location:!1})}]),x[c])for(var g=0;g-1}function p(a){var b=a.split("."),c=v.$current.name.split(".");if("**"===b[0]&&(c=c.slice(c.indexOf(b[1])),c.unshift("**")),"**"===b[b.length-1]&&(c.splice(c.indexOf(b[b.length-2])+1,Number.MAX_VALUE),c.push("**")),b.length!=c.length)return!1;for(var d=0,e=b.length;e>d;d++)"*"===b[d]&&(c[d]="*");return c.join("")===b.join("")}function q(a,b){return E(a)&&!C(b)?z[a]:D(b)&&E(a)?(z[a]&&!z.$delegates[a]&&(z.$delegates[a]=z[a]),z[a]=b,this):this}function r(a,b){return F(a)?b=a:b.name=a,n(b),this}function s(a,e,g,m,n,q,r,s,x){function z(){r.url()!==M&&(r.url(M),r.replace())}function A(a,c,d,f,h){var i=d?c:k(a.params,c),j={$stateParams:i};h.resolve=n.resolve(a.resolve,j,h.resolve,a);var l=[h.resolve.then(function(a){h.globals=a})];return f&&l.push(f),H(a.views,function(c,d){var e=c.resolve&&c.resolve!==a.resolve?c.resolve:{};e.$template=[function(){return g.load(d,{view:c,locals:j,params:i,notify:!1})||""}],l.push(n.resolve(e,j,h.resolve,a).then(function(f){if(D(c.controllerProvider)||G(c.controllerProvider)){var g=b.extend({},e,j);f.$$controller=m.invoke(c.controllerProvider,null,g)}else f.$$controller=c.controller;f.$$state=a,f.$$controllerAs=c.controllerAs,h[d]=f}))}),e.all(l).then(function(){return h})}var B=e.reject(new Error("transition superseded")),F=e.reject(new Error("transition prevented")),K=e.reject(new Error("transition aborted")),L=e.reject(new Error("transition failed")),M=r.url(),N=x.baseHref();return u.locals={resolve:null,globals:{$stateParams:{}}},v={params:{},current:u.self,$current:u,transition:null},v.reload=function(){v.transitionTo(v.current,q,{reload:!0,inherit:!1,notify:!1})},v.go=function(a,b,c){return this.transitionTo(a,b,I({inherit:!0,relative:v.$current},c))},v.transitionTo=function(b,c,f){c=c||{},f=I({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},f||{});var g,k=v.$current,n=v.params,o=k.path,p=l(b,f.relative);if(!C(p)){var s={to:b,toParams:c,options:f};if(g=a.$broadcast("$stateNotFound",s,k.self,n),g.defaultPrevented)return z(),K;if(g.retry){if(f.$retry)return z(),L;var w=v.transition=e.when(g.retry);return w.then(function(){return w!==v.transition?B:(s.options.$retry=!0,v.transitionTo(s.to,s.toParams,s.options))},function(){return K}),z(),w}if(b=s.to,c=s.toParams,f=s.options,p=l(b,f.relative),!C(p)){if(f.relative)throw new Error("Could not resolve '"+b+"' from state '"+f.relative+"'");throw new Error("No such state '"+b+"'")}}if(p[y])throw new Error("Cannot transition to abstract state '"+b+"'");f.inherit&&(c=h(q,c||{},v.$current,p)),b=p;var x,D,E=b.path,G=u.locals,H=[];for(x=0,D=E[x];D&&D===o[x]&&j(c,n,D.ownParams)&&!f.reload;x++,D=E[x])G=H[x]=D.locals;if(t(b,k,G,f))return b.self.reloadOnSearch!==!1&&z(),v.transition=null,e.when(v.current);if(c=i(b.params,c||{}),f.notify&&(g=a.$broadcast("$stateChangeStart",b.self,c,k.self,n),g.defaultPrevented))return z(),F;for(var N=e.when(G),O=x;O=x;d--)g=o[d],g.self.onExit&&m.invoke(g.self.onExit,g.self,g.locals.globals),g.locals=null;for(d=x;d1||b.ctrlKey||b.metaKey||b.shiftKey||f.attr("target")||(c(function(){a.go(i.state,j,o)}),b.preventDefault())})}}}function y(a,b,c){return{restrict:"A",controller:["$scope","$element","$attrs",function(d,e,f){function g(){a.$current.self===i&&h()?e.addClass(l):e.removeClass(l)}function h(){return!k||j(k,b)}var i,k,l;l=c(f.uiSrefActive||"",!1)(d),this.$$setStateInfo=function(b,c){i=a.get(b,w(e)),k=c,g()},d.$on("$stateChangeSuccess",g)}]}}function z(a){return function(b){return a.is(b)}}function A(a){return function(b){return a.includes(b)}}function B(a,b){function e(a){this.locals=a.locals.globals,this.params=this.locals.$stateParams}function f(){this.locals=null,this.params=null}function g(c,g){if(null!=g.redirectTo){var h,j=g.redirectTo;if(E(j))h=j;else{if(!D(j))throw new Error("Invalid 'redirectTo' in when()");h=function(a,b){return j(a,b.path(),b.search())}}b.when(c,h)}else a.state(d(g,{parent:null,name:"route:"+encodeURIComponent(c),url:c,onEnter:e,onExit:f}));return i.push(g),this}function h(a,b,d){function e(a){return""!==a.name?a:c}var f={routes:i,params:d,current:c};return b.$on("$stateChangeStart",function(a,c,d,f){b.$broadcast("$routeChangeStart",e(c),e(f))}),b.$on("$stateChangeSuccess",function(a,c,d,g){f.current=e(c),b.$broadcast("$routeChangeSuccess",e(c),e(g)),J(d,f.params)}),b.$on("$stateChangeError",function(a,c,d,f,g,h){b.$broadcast("$routeChangeError",e(c),e(f),h)}),f}var i=[];e.$inject=["$$state"],this.when=g,this.$get=h,h.$inject=["$state","$rootScope","$routeParams"]}var C=b.isDefined,D=b.isFunction,E=b.isString,F=b.isObject,G=b.isArray,H=b.forEach,I=b.extend,J=b.copy;b.module("ui.router.util",["ng"]),b.module("ui.router.router",["ui.router.util"]),b.module("ui.router.state",["ui.router.router","ui.router.util"]),b.module("ui.router",["ui.router.state"]),b.module("ui.router.compat",["ui.router"]),l.$inject=["$q","$injector"],b.module("ui.router.util").service("$resolve",l),m.$inject=["$http","$templateCache","$injector"],b.module("ui.router.util").service("$templateFactory",m),n.prototype.concat=function(a){return new n(this.sourcePath+a+this.sourceSearch)},n.prototype.toString=function(){return this.source},n.prototype.exec=function(a,b){var c=this.regexp.exec(a);if(!c)return null;var d,e=this.params,f=e.length,g=this.segments.length-1,h={};if(g!==c.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(d=0;g>d;d++)h[e[d]]=c[d+1];for(;f>d;d++)h[e[d]]=b[e[d]];return h},n.prototype.parameters=function(){return this.params},n.prototype.format=function(a){var b=this.segments,c=this.params;if(!a)return b.join("");var d,e,f,g=b.length-1,h=c.length,i=b[0];for(d=0;g>d;d++)f=a[c[d]],null!=f&&(i+=encodeURIComponent(f)),i+=b[d+1];for(;h>d;d++)f=a[c[d]],null!=f&&(i+=(e?"&":"?")+c[d]+"="+encodeURIComponent(f),e=!0);return i},b.module("ui.router.util").provider("$urlMatcherFactory",o),p.$inject=["$urlMatcherFactoryProvider"],b.module("ui.router.router").provider("$urlRouter",p),q.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider","$locationProvider"],b.module("ui.router.state").value("$stateParams",{}).provider("$state",q),r.$inject=[],b.module("ui.router.state").provider("$view",r),b.module("ui.router.state").provider("$uiViewScroll",s),t.$inject=["$state","$injector","$uiViewScroll"],u.$inject=["$compile","$controller","$state"],b.module("ui.router.state").directive("uiView",t),b.module("ui.router.state").directive("uiView",u),x.$inject=["$state","$timeout"],y.$inject=["$state","$stateParams","$interpolate"],b.module("ui.router.state").directive("uiSref",x).directive("uiSrefActive",y),z.$inject=["$state"],A.$inject=["$state"],b.module("ui.router.state").filter("isState",z).filter("includedByState",A),B.$inject=["$stateProvider","$urlRouterProvider"],b.module("ui.router.compat").provider("$route",B).directive("ngView",t)}(window,window.angular); -------------------------------------------------------------------------------- /client/lib/ionic/scss/_items.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Items 3 | * -------------------------------------------------- 4 | */ 5 | 6 | .item { 7 | @include item-style($item-default-bg, $item-default-border, $item-default-text); 8 | 9 | position: relative; 10 | z-index: $z-index-item; // Make sure the borders and stuff don't get hidden by children 11 | display: block; 12 | 13 | margin: $item-border-width * -1; 14 | padding: $item-padding; 15 | 16 | border-width: $item-border-width; 17 | border-style: solid; 18 | font-size: $item-font-size; 19 | 20 | h2 { 21 | margin: 0 0 4px 0; 22 | font-size: 16px; 23 | } 24 | h3 { 25 | margin: 0 0 4px 0; 26 | font-size: 14px; 27 | } 28 | h4 { 29 | margin: 0 0 4px 0; 30 | font-size: 12px; 31 | } 32 | h5, h6 { 33 | margin: 0 0 3px 0; 34 | font-size: 10px; 35 | } 36 | p { 37 | color: #666; 38 | font-size: 14px; 39 | } 40 | 41 | h1:last-child, 42 | h2:last-child, 43 | h3:last-child, 44 | h4:last-child, 45 | h5:last-child, 46 | h6:last-child, 47 | p:last-child { 48 | margin-bottom: 0; 49 | } 50 | 51 | // Align badges within items 52 | .badge { 53 | @include display-flex(); 54 | position: absolute; 55 | top: $item-padding; 56 | right: ($item-padding * 2); 57 | } 58 | &.item-button-right .badge { 59 | right: ($item-padding * 2) + 35; 60 | } 61 | &.item-divider .badge { 62 | top: ceil($item-padding / 2); 63 | } 64 | .badge + .badge { 65 | margin-right: 5px; 66 | } 67 | 68 | // Different themes for items 69 | &.item-light { 70 | @include item-style($item-light-bg, $item-light-border, $item-light-text); 71 | } 72 | &.item-stable { 73 | @include item-style($item-stable-bg, $item-stable-border, $item-stable-text); 74 | } 75 | &.item-positive { 76 | @include item-style($item-positive-bg, $item-positive-border, $item-positive-text); 77 | } 78 | &.item-calm { 79 | @include item-style($item-calm-bg, $item-calm-border, $item-calm-text); 80 | } 81 | &.item-assertive { 82 | @include item-style($item-assertive-bg, $item-assertive-border, $item-assertive-text); 83 | } 84 | &.item-balanced { 85 | @include item-style($item-balanced-bg, $item-balanced-border, $item-balanced-text); 86 | } 87 | &.item-energized { 88 | @include item-style($item-energized-bg, $item-energized-border, $item-energized-text); 89 | } 90 | &.item-royal { 91 | @include item-style($item-royal-bg, $item-royal-border, $item-royal-text); 92 | } 93 | &.item-dark { 94 | @include item-style($item-dark-bg, $item-dark-border, $item-dark-text); 95 | } 96 | 97 | &[ng-click]:hover { 98 | cursor: pointer; 99 | } 100 | 101 | } 102 | 103 | // Link and Button Active States 104 | .item.active, 105 | .item.activated, 106 | .item-complex.active .item-content, 107 | .item-complex.activated .item-content, 108 | .item .item-content.active, 109 | .item .item-content.activated { 110 | @include item-active-style($item-default-active-bg, $item-default-active-border); 111 | 112 | // Different active themes for and