├── .bowerrc ├── .gitignore ├── README.md ├── bower.json ├── config.xml ├── gulpfile.js ├── hooks ├── README.md └── after_prepare │ └── 010_add_platform_class.js ├── ionic.project ├── package.json ├── scss └── ionic.app.scss └── www ├── css ├── ionic.app.css ├── ionic.app.min.css └── style.css ├── index.html ├── js ├── app.js ├── localstorage.js └── quotes.js ├── lib └── ionic │ ├── css │ ├── ionic.css │ └── ionic.min.css │ ├── fonts │ ├── ionicons.eot │ ├── ionicons.svg │ ├── ionicons.ttf │ └── ionicons.woff │ ├── js │ ├── angular-ui │ │ ├── angular-ui-router.js │ │ └── angular-ui-router.min.js │ ├── angular │ │ ├── angular-animate.js │ │ ├── angular-animate.min.js │ │ ├── angular-resource.js │ │ ├── angular-resource.min.js │ │ ├── angular-sanitize.js │ │ ├── angular-sanitize.min.js │ │ ├── angular.js │ │ └── angular.min.js │ ├── ionic-angular.js │ ├── ionic-angular.min.js │ ├── ionic.bundle.js │ ├── ionic.bundle.min.js │ ├── ionic.js │ └── ionic.min.js │ ├── scss │ ├── _action-sheet.scss │ ├── _animations.scss │ ├── _backdrop.scss │ ├── _badge.scss │ ├── _bar.scss │ ├── _button-bar.scss │ ├── _button.scss │ ├── _checkbox.scss │ ├── _form.scss │ ├── _grid.scss │ ├── _items.scss │ ├── _list.scss │ ├── _loading.scss │ ├── _menu.scss │ ├── _mixins.scss │ ├── _modal.scss │ ├── _platform.scss │ ├── _popover.scss │ ├── _popup.scss │ ├── _progress.scss │ ├── _radio.scss │ ├── _range.scss │ ├── _refresher.scss │ ├── _reset.scss │ ├── _scaffolding.scss │ ├── _select.scss │ ├── _slide-box.scss │ ├── _spinner.scss │ ├── _tabs.scss │ ├── _toggle.scss │ ├── _transitions.scss │ ├── _type.scss │ ├── _util.scss │ ├── _variables.scss │ ├── ionic.scss │ └── ionicons │ │ ├── _ionicons-font.scss │ │ ├── _ionicons-icons.scss │ │ ├── _ionicons-variables.scss │ │ └── ionicons.scss │ └── version.json └── views ├── portfolio ├── add-modal.html ├── portfolio.html └── portfolio.js ├── quotes ├── quotes.html └── quotes.js └── tabs ├── tabs.html └── tabs.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "www/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | node_modules/ 5 | platforms/ 6 | plugins/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is the project built in the Ionic Definitive Start Guide found on AirPair. You can find the post here: https://www.airpair.com/ionic-framework/posts/the-definitive-ionic-starter-guide. 2 | 3 | ### Setup 4 | 5 | Assuming you have NodeJS installed, setup Ionic and Gulp (for the building of the app) with the following. 6 | 7 | npm install -g ionic gulp 8 | 9 | Then clone this repo and start a local preview of the codebase. 10 | 11 | git clone https://github.com/gnomeontherun/ionic-definitive-guide.git 12 | cd ionic-definitive-guide 13 | npm install 14 | ionic serve 15 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stocks", 3 | "private": "true", 4 | "devDependencies": { 5 | "ionic": "driftyco/ionic-bower#1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | stocks 4 | 5 | Stocks example for 6 | 7 | 8 | Ionic In Action 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util'); 3 | var bower = require('bower'); 4 | var concat = require('gulp-concat'); 5 | var sass = require('gulp-sass'); 6 | var minifyCss = require('gulp-minify-css'); 7 | var rename = require('gulp-rename'); 8 | var sh = require('shelljs'); 9 | 10 | var paths = { 11 | sass: ['./scss/**/*.scss'] 12 | }; 13 | 14 | gulp.task('default', ['sass']); 15 | 16 | gulp.task('sass', function(done) { 17 | gulp.src('./scss/ionic.app.scss') 18 | .pipe(sass({ 19 | errLogToConsole: true 20 | })) 21 | .pipe(gulp.dest('./www/css/')) 22 | .pipe(minifyCss({ 23 | keepSpecialComments: 0 24 | })) 25 | .pipe(rename({ extname: '.min.css' })) 26 | .pipe(gulp.dest('./www/css/')) 27 | .on('end', done); 28 | }); 29 | 30 | gulp.task('watch', function() { 31 | gulp.watch(paths.sass, ['sass']); 32 | }); 33 | 34 | gulp.task('install', ['git-check'], function() { 35 | return bower.commands.install() 36 | .on('log', function(data) { 37 | gutil.log('bower', gutil.colors.cyan(data.id), data.message); 38 | }); 39 | }); 40 | 41 | gulp.task('git-check', function(done) { 42 | if (!sh.which('git')) { 43 | console.log( 44 | ' ' + gutil.colors.red('Git is not installed.'), 45 | '\n Git, the version control system, is required to download Ionic.', 46 | '\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.', 47 | '\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.' 48 | ); 49 | process.exit(1); 50 | } 51 | done(); 52 | }); 53 | -------------------------------------------------------------------------------- /hooks/README.md: -------------------------------------------------------------------------------- 1 | 21 | # Cordova Hooks 22 | 23 | This directory may contain scripts used to customize cordova commands. This 24 | directory used to exist at `.cordova/hooks`, but has now been moved to the 25 | project root. Any scripts you add to these directories will be executed before 26 | and after the commands corresponding to the directory name. Useful for 27 | integrating your own build systems or integrating with version control systems. 28 | 29 | __Remember__: Make your scripts executable. 30 | 31 | ## Hook Directories 32 | The following subdirectories will be used for hooks: 33 | 34 | after_build/ 35 | after_compile/ 36 | after_docs/ 37 | after_emulate/ 38 | after_platform_add/ 39 | after_platform_rm/ 40 | after_platform_ls/ 41 | after_plugin_add/ 42 | after_plugin_ls/ 43 | after_plugin_rm/ 44 | after_plugin_search/ 45 | after_prepare/ 46 | after_run/ 47 | after_serve/ 48 | before_build/ 49 | before_compile/ 50 | before_docs/ 51 | before_emulate/ 52 | before_platform_add/ 53 | before_platform_rm/ 54 | before_platform_ls/ 55 | before_plugin_add/ 56 | before_plugin_ls/ 57 | before_plugin_rm/ 58 | before_plugin_search/ 59 | before_prepare/ 60 | before_run/ 61 | before_serve/ 62 | pre_package/ <-- Windows 8 and Windows Phone only. 63 | 64 | ## Script Interface 65 | 66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: 67 | 68 | * CORDOVA_VERSION - The version of the Cordova-CLI. 69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). 70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) 71 | * CORDOVA_HOOK - Path to the hook that is being executed. 72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) 73 | 74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted. 75 | 76 | 77 | ## Writing hooks 78 | 79 | We highly recommend writting your hooks using Node.js so that they are 80 | cross-platform. Some good examples are shown here: 81 | 82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) 83 | 84 | -------------------------------------------------------------------------------- /hooks/after_prepare/010_add_platform_class.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Add Platform Class 4 | // v1.0 5 | // Automatically adds the platform class to the body tag 6 | // after the `prepare` command. By placing the platform CSS classes 7 | // directly in the HTML built for the platform, it speeds up 8 | // rendering the correct layout/style for the specific platform 9 | // instead of waiting for the JS to figure out the correct classes. 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | 14 | var rootdir = process.argv[2]; 15 | 16 | function addPlatformBodyTag(indexPath, platform) { 17 | // add the platform class to the body tag 18 | try { 19 | var platformClass = 'platform-' + platform; 20 | var cordovaClass = 'platform-cordova platform-webview'; 21 | 22 | var html = fs.readFileSync(indexPath, 'utf8'); 23 | 24 | var bodyTag = findBodyTag(html); 25 | if(!bodyTag) return; // no opening body tag, something's wrong 26 | 27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added 28 | 29 | var newBodyTag = bodyTag; 30 | 31 | var classAttr = findClassAttr(bodyTag); 32 | if(classAttr) { 33 | // body tag has existing class attribute, add the classname 34 | var endingQuote = classAttr.substring(classAttr.length-1); 35 | var newClassAttr = classAttr.substring(0, classAttr.length-1); 36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote; 37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr); 38 | 39 | } else { 40 | // add class attribute to the body tag 41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">'); 42 | } 43 | 44 | html = html.replace(bodyTag, newBodyTag); 45 | 46 | fs.writeFileSync(indexPath, html, 'utf8'); 47 | 48 | process.stdout.write('add to body class: ' + platformClass + '\n'); 49 | } catch(e) { 50 | process.stdout.write(e); 51 | } 52 | } 53 | 54 | function findBodyTag(html) { 55 | // get the body tag 56 | try{ 57 | return html.match(/])(.*?)>/gi)[0]; 58 | }catch(e){} 59 | } 60 | 61 | function findClassAttr(bodyTag) { 62 | // get the body tag's class attribute 63 | try{ 64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0]; 65 | }catch(e){} 66 | } 67 | 68 | if (rootdir) { 69 | 70 | // go through each of the platform directories that have been prepared 71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []); 72 | 73 | for(var x=0; x 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /www/js/app.js: -------------------------------------------------------------------------------- 1 | angular.module('App', ['ionic']) 2 | 3 | .config(function($urlRouterProvider) { 4 | $urlRouterProvider.otherwise('/tabs/quotes'); 5 | }) 6 | 7 | .run(function($ionicPlatform) { 8 | $ionicPlatform.ready(function() { 9 | if(window.cordova && window.cordova.plugins.Keyboard) { 10 | cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); 11 | } 12 | if(window.StatusBar) { 13 | StatusBar.styleDefault(); 14 | } 15 | }); 16 | }) 17 | -------------------------------------------------------------------------------- /www/js/localstorage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('App') 4 | 5 | .factory('LocalStorageService', function() { 6 | 7 | // Helper methods to manage an array of data through localstorage 8 | return { 9 | // This pulls out an item from localstorage and tries to parse it as JSON strings 10 | get: function LocalStorageServiceGet(key, defaultValue) { 11 | var stored = localStorage.getItem(key); 12 | try { 13 | stored = angular.fromJson(stored); 14 | } catch(error) { 15 | stored = null; 16 | } 17 | if (defaultValue && stored === null) { 18 | stored = defaultValue; 19 | } 20 | return stored; 21 | }, 22 | // This stores data into localstorage, but converts values to a JSON string first 23 | update: function LocalStorageServiceUpdate(key, value) { 24 | if (value) { 25 | localStorage.setItem(key, angular.toJson(value)); 26 | } 27 | }, 28 | // This will remove a key from localstorage 29 | clear: function LocalStorageServiceClear(key) { 30 | localStorage.removeItem(key); 31 | } 32 | }; 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /www/js/quotes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('App') 4 | 5 | .factory('QuotesService', function($q, $http) { 6 | 7 | // Create a quotes service to simplify how to load data from Yahoo Finance 8 | var QuotesService = {}; 9 | 10 | QuotesService.get = function(symbols) { 11 | // Convert the symbols array into the format required for YQL 12 | symbols = symbols.map(function(symbol) { 13 | return "'" + symbol.toUpperCase() + "'"; 14 | }); 15 | // Create a new deferred object 16 | var defer = $q.defer(); 17 | // Make the http request 18 | $http.get('https://query.yahooapis.com/v1/public/yql?q=select * from yahoo.finance.quotes where symbol in (' + symbols.join(',') + ')&format=json&env=http://datatables.org/alltables.env').success(function(quotes) { 19 | // The API is funny, if only one result is returned it is an object, multiple results are an array. This forces it to be an array for consistency 20 | if (quotes.query.count === 1) { 21 | quotes.query.results.quote = [quotes.query.results.quote]; 22 | } 23 | // Resolve the promise with the data 24 | defer.resolve(quotes.query.results.quote); 25 | }).error(function(error) { 26 | // If an error occurs, reject the promise with the error 27 | defer.reject(error); 28 | }); 29 | // Return the promise 30 | return defer.promise; 31 | }; 32 | 33 | return QuotesService; 34 | }); 35 | -------------------------------------------------------------------------------- /www/lib/ionic/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnomeontherun/ionic-definitive-guide/ae8926604b136b013755c607b89782b9489bc1af/www/lib/ionic/fonts/ionicons.eot -------------------------------------------------------------------------------- /www/lib/ionic/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnomeontherun/ionic-definitive-guide/ae8926604b136b013755c607b89782b9489bc1af/www/lib/ionic/fonts/ionicons.ttf -------------------------------------------------------------------------------- /www/lib/ionic/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnomeontherun/ionic-definitive-guide/ae8926604b136b013755c607b89782b9489bc1af/www/lib/ionic/fonts/ionicons.woff -------------------------------------------------------------------------------- /www/lib/ionic/js/angular/angular-animate.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.3.13 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(N,f,W){'use strict';f.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(X,C,g){g=g.ngAnimateChildren;f.isString(g)&&0===g.length?C.data("$$ngAnimateChildren",!0):X.$watch(g,function(f){C.data("$$ngAnimateChildren",!!f)})}}).factory("$$animateReflow",["$$rAF","$document",function(f,C){return function(g){return f(function(){g()})}}]).config(["$provide","$animateProvider",function(X,C){function g(f){for(var n=0;n=C&&b>=x&&c()}var m=g(e);a=e.data("$$ngAnimateCSS3Data");if(-1!=m.getAttribute("class").indexOf(b)&&a){var k="",t="";n(b.split(" "),function(a, 26 | b){var e=(0=c;e--)d.end&&d.end(f[e]);f.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,f=[],m=a,l;for(f.last=function(){return f[f.length-1]};a;){l="";k=!0;if(f.last()&&x[f.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");d.chars&&d.chars(r(b));return""}),e("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&& 8 | d.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(y.test(a)){if(b=a.match(y))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(z))a=a.substring(b[0].length),b[0].replace(z,e),k=!1}else K.test(a)&&((b=a.match(A))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(A,c)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(r(l)))}if(a==m)throw L("badparse",a);m=a}e()}function r(a){if(!a)return"";var d=M.exec(a);a=d[1]; 9 | var c=d[3];if(d=d[2])q.innerHTML=d.replace(//g,">")}function s(a,d){var c=!1,e=h.bind(a,a.push);return{start:function(a,k,f){a=h.lowercase(a);!c&&x[a]&&(c=a);c||!0!==C[a]||(e("<"),e(a), 10 | h.forEach(k,function(c,f){var k=h.lowercase(f),g="img"===a&&"src"===k||"background"===k;!0!==P[k]||!0===D[k]&&!d(c,g)||(e(" "),e(f),e('="'),e(B(c)),e('"'))}),e(f?"/>":">"))},end:function(a){a=h.lowercase(a);c||!0!==C[a]||(e(""));a==c&&(c=!1)},chars:function(a){c||e(B(a))}}}var L=h.$$minErr("$sanitize"),A=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,z=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, 11 | K=/^]*?)>/i,I=/"\u201d\u2019]/,c=/^mailto:/;return function(e,b){function k(a){a&&g.push(E(a))} 15 | function f(a,c){g.push("');k(c);g.push("")}if(!e)return e;for(var m,l=e,g=[],n,p;m=l.match(d);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),f(n,m[0].replace(c,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular); 16 | //# sourceMappingURL=angular-sanitize.min.js.map 17 | -------------------------------------------------------------------------------- /www/lib/ionic/scss/_action-sheet.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Action Sheets 3 | * -------------------------------------------------- 4 | */ 5 | 6 | .action-sheet-backdrop { 7 | @include transition(background-color 150ms 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.4); 18 | } 19 | } 20 | 21 | .action-sheet-wrapper { 22 | @include translate3d(0, 100%, 0); 23 | @include transition(all cubic-bezier(.36, .66, .04, 1) 500ms); 24 | position: absolute; 25 | bottom: 0; 26 | left: 0; 27 | right: 0; 28 | width: 100%; 29 | max-width: 500px; 30 | margin: auto; 31 | } 32 | 33 | .action-sheet-up { 34 | @include translate3d(0, 0, 0); 35 | } 36 | 37 | .action-sheet { 38 | margin-left: $sheet-margin; 39 | margin-right: $sheet-margin; 40 | width: auto; 41 | z-index: $z-index-action-sheet; 42 | overflow: hidden; 43 | 44 | .button { 45 | display: block; 46 | padding: 1px; 47 | width: 100%; 48 | border-radius: 0; 49 | border-color: $sheet-options-border-color; 50 | background-color: transparent; 51 | 52 | color: $sheet-options-text-color; 53 | font-size: 21px; 54 | 55 | &:hover { 56 | color: $sheet-options-text-color; 57 | } 58 | &.destructive { 59 | color: #ff3b30; 60 | &:hover { 61 | color: #ff3b30; 62 | } 63 | } 64 | } 65 | 66 | .button.active, .button.activated { 67 | box-shadow: none; 68 | border-color: $sheet-options-border-color; 69 | color: $sheet-options-text-color; 70 | background: $sheet-options-bg-active-color; 71 | } 72 | } 73 | 74 | .action-sheet-has-icons .icon { 75 | position: absolute; 76 | left: 16px; 77 | } 78 | 79 | .action-sheet-title { 80 | padding: $sheet-margin * 2; 81 | color: #8f8f8f; 82 | text-align: center; 83 | font-size: 13px; 84 | } 85 | 86 | .action-sheet-group { 87 | margin-bottom: $sheet-margin; 88 | border-radius: $sheet-border-radius; 89 | background-color: #fff; 90 | overflow: hidden; 91 | 92 | .button { 93 | border-width: 1px 0px 0px 0px; 94 | } 95 | .button:first-child:last-child { 96 | border-width: 0; 97 | } 98 | } 99 | 100 | .action-sheet-options { 101 | background: $sheet-options-bg-color; 102 | } 103 | 104 | .action-sheet-cancel { 105 | .button { 106 | font-weight: 500; 107 | } 108 | } 109 | 110 | .action-sheet-open { 111 | pointer-events: none; 112 | 113 | &.modal-open .modal { 114 | pointer-events: none; 115 | } 116 | 117 | .action-sheet-backdrop { 118 | pointer-events: auto; 119 | } 120 | } 121 | 122 | 123 | .platform-android { 124 | 125 | .action-sheet-backdrop.active { 126 | background-color: rgba(0,0,0,0.2); 127 | } 128 | 129 | .action-sheet { 130 | margin: 0; 131 | 132 | .action-sheet-title, 133 | .button { 134 | text-align: left; 135 | border-color: transparent; 136 | font-size: 16px; 137 | color: inherit; 138 | } 139 | 140 | .action-sheet-title { 141 | font-size: 14px; 142 | padding: 16px; 143 | color: #666; 144 | } 145 | 146 | .button.active, 147 | .button.activated { 148 | background: #e8e8e8; 149 | } 150 | } 151 | 152 | .action-sheet-group { 153 | margin: 0; 154 | border-radius: 0; 155 | background-color: #fafafa; 156 | } 157 | 158 | .action-sheet-cancel { 159 | display: none; 160 | } 161 | 162 | .action-sheet-has-icons { 163 | 164 | .button { 165 | padding-left: 56px; 166 | } 167 | 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /www/lib/ionic/scss/_animations.scss: -------------------------------------------------------------------------------- 1 | 2 | // Slide up from the bottom, used for modals 3 | // ------------------------------- 4 | 5 | .slide-in-up { 6 | @include translate3d(0, 100%, 0); 7 | } 8 | .slide-in-up.ng-enter, 9 | .slide-in-up > .ng-enter { 10 | @include transition(all cubic-bezier(.1, .7, .1, 1) 400ms); 11 | } 12 | .slide-in-up.ng-enter-active, 13 | .slide-in-up > .ng-enter-active { 14 | @include translate3d(0, 0, 0); 15 | } 16 | 17 | .slide-in-up.ng-leave, 18 | .slide-in-up > .ng-leave { 19 | @include transition(all ease-in-out 250ms); 20 | } 21 | 22 | 23 | // Scale Out 24 | // Scale from hero (1 in this case) to zero 25 | // ------------------------------- 26 | 27 | @-webkit-keyframes scaleOut { 28 | from { -webkit-transform: scale(1); opacity: 1; } 29 | to { -webkit-transform: scale(0.8); opacity: 0; } 30 | } 31 | @keyframes scaleOut { 32 | from { transform: scale(1); opacity: 1; } 33 | to { transform: scale(0.8); opacity: 0; } 34 | } 35 | 36 | 37 | // Super Scale In 38 | // Scale from super (1.x) to duper (1 in this case) 39 | // ------------------------------- 40 | 41 | @-webkit-keyframes superScaleIn { 42 | from { -webkit-transform: scale(1.2); opacity: 0; } 43 | to { -webkit-transform: scale(1); opacity: 1 } 44 | } 45 | @keyframes superScaleIn { 46 | from { transform: scale(1.2); opacity: 0; } 47 | to { transform: scale(1); opacity: 1; } 48 | } 49 | -------------------------------------------------------------------------------- /www/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: $loading-backdrop-bg-color; 12 | 13 | visibility: hidden; 14 | opacity: 0; 15 | 16 | &.visible { 17 | visibility: visible; 18 | } 19 | &.active { 20 | opacity: 1; 21 | } 22 | 23 | @include transition($loading-backdrop-fadein-duration opacity linear); 24 | } 25 | -------------------------------------------------------------------------------- /www/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 | -------------------------------------------------------------------------------- /www/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 | font-weight: $headings-font-weight; 147 | 148 | line-height: $bar-height; 149 | 150 | &.title-left { 151 | text-align: left; 152 | } 153 | &.title-right { 154 | text-align: right; 155 | } 156 | } 157 | 158 | .title a { 159 | color: inherit; 160 | } 161 | 162 | .button { 163 | z-index: $z-index-bar-button; 164 | padding: 0 $button-bar-button-padding; 165 | min-width: initial; 166 | min-height: $button-bar-button-height - 1; 167 | font-weight: 400; 168 | font-size: $button-bar-button-font-size; 169 | line-height: $button-bar-button-height; 170 | 171 | &.button-icon:before, 172 | .icon:before, 173 | &.icon:before, 174 | &.icon-left:before, 175 | &.icon-right:before { 176 | padding-right: 2px; 177 | padding-left: 2px; 178 | font-size: $button-bar-button-icon-size; 179 | line-height: $button-bar-button-height; 180 | } 181 | 182 | &.button-icon { 183 | font-size: $bar-title-font-size; 184 | .icon:before, 185 | &:before, 186 | &.icon-left:before, 187 | &.icon-right:before { 188 | vertical-align: top; 189 | font-size: $button-large-icon-size; 190 | line-height: $button-bar-button-height; 191 | } 192 | } 193 | &.button-clear { 194 | padding-right: 2px; 195 | padding-left: 2px; 196 | font-weight: 300; 197 | font-size: $bar-title-font-size; 198 | 199 | .icon:before, 200 | &.icon:before, 201 | &.icon-left:before, 202 | &.icon-right:before { 203 | font-size: $button-large-icon-size; 204 | line-height: $button-bar-button-height; 205 | } 206 | } 207 | 208 | &.back-button { 209 | display: block; 210 | margin-right: 5px; 211 | padding: 0; 212 | white-space: nowrap; 213 | font-weight: 400; 214 | } 215 | 216 | &.back-button.active, 217 | &.back-button.activated { 218 | opacity: 0.2; 219 | } 220 | } 221 | 222 | .button-bar > .button, 223 | .buttons > .button { 224 | min-height: $button-bar-button-height - 1; 225 | line-height: $button-bar-button-height; 226 | } 227 | 228 | .button-bar + .button, 229 | .button + .button-bar { 230 | margin-left: 5px; 231 | } 232 | 233 | // Android 4.4 messes with the display property 234 | .buttons, 235 | .buttons.primary-buttons, 236 | .buttons.secondary-buttons { 237 | display: inherit; 238 | } 239 | .buttons span { 240 | display: inline-block; 241 | } 242 | .buttons-left span { 243 | margin-right: 5px; 244 | display: inherit; 245 | } 246 | .buttons-right span { 247 | margin-left: 5px; 248 | display: inherit; 249 | } 250 | 251 | // Place the last button in a bar on the right of the bar 252 | .title + .button:last-child, 253 | > .button + .button:last-child, 254 | > .button.pull-right, 255 | .buttons.pull-right, 256 | .title + .buttons { 257 | position: absolute; 258 | top: 5px; 259 | right: 5px; 260 | bottom: 5px; 261 | } 262 | 263 | } 264 | 265 | .platform-android { 266 | 267 | .nav-bar-has-subheader .bar { 268 | background-image: none; 269 | } 270 | 271 | .bar { 272 | 273 | .back-button .icon:before { 274 | font-size: 24px; 275 | } 276 | 277 | .title { 278 | font-size: 19px; 279 | line-height: $bar-height; 280 | } 281 | } 282 | 283 | } 284 | 285 | // Default styles for buttons inside of styled bars 286 | .bar-light { 287 | .button { 288 | @include button-style($bar-light-bg, $bar-light-border, $bar-light-active-bg, $bar-light-active-border, $bar-light-text); 289 | @include button-clear($bar-light-text, $bar-title-font-size); 290 | } 291 | } 292 | .bar-stable { 293 | .button { 294 | @include button-style($bar-stable-bg, $bar-stable-border, $bar-stable-active-bg, $bar-stable-active-border, $bar-stable-text); 295 | @include button-clear($bar-stable-text, $bar-title-font-size); 296 | } 297 | } 298 | .bar-positive { 299 | .button { 300 | @include button-style($bar-positive-bg, $bar-positive-border, $bar-positive-active-bg, $bar-positive-active-border, $bar-positive-text); 301 | @include button-clear(#fff, $bar-title-font-size); 302 | } 303 | } 304 | .bar-calm { 305 | .button { 306 | @include button-style($bar-calm-bg, $bar-calm-border, $bar-calm-active-bg, $bar-calm-active-border, $bar-calm-text); 307 | @include button-clear(#fff, $bar-title-font-size); 308 | } 309 | } 310 | .bar-assertive { 311 | .button { 312 | @include button-style($bar-assertive-bg, $bar-assertive-border, $bar-assertive-active-bg, $bar-assertive-active-border, $bar-assertive-text); 313 | @include button-clear(#fff, $bar-title-font-size); 314 | } 315 | } 316 | .bar-balanced { 317 | .button { 318 | @include button-style($bar-balanced-bg, $bar-balanced-border, $bar-balanced-active-bg, $bar-balanced-active-border, $bar-balanced-text); 319 | @include button-clear(#fff, $bar-title-font-size); 320 | } 321 | } 322 | .bar-energized { 323 | .button { 324 | @include button-style($bar-energized-bg, $bar-energized-border, $bar-energized-active-bg, $bar-energized-active-border, $bar-energized-text); 325 | @include button-clear(#fff, $bar-title-font-size); 326 | } 327 | } 328 | .bar-royal { 329 | .button { 330 | @include button-style($bar-royal-bg, $bar-royal-border, $bar-royal-active-bg, $bar-royal-active-border, $bar-royal-text); 331 | @include button-clear(#fff, $bar-title-font-size); 332 | } 333 | } 334 | .bar-dark { 335 | .button { 336 | @include button-style($bar-dark-bg, $bar-dark-border, $bar-dark-active-bg, $bar-dark-active-border, $bar-dark-text); 337 | @include button-clear(#fff, $bar-title-font-size); 338 | } 339 | } 340 | 341 | // Header at top 342 | .bar-header { 343 | top: 0; 344 | border-top-width: 0; 345 | border-bottom-width: 1px; 346 | &.has-tabs-top{ 347 | border-bottom-width: 0px; 348 | background-image: none; 349 | } 350 | } 351 | .tabs-top .bar-header{ 352 | border-bottom-width: 0px; 353 | background-image: none; 354 | } 355 | 356 | // Footer at bottom 357 | .bar-footer { 358 | bottom: 0; 359 | border-top-width: 1px; 360 | border-bottom-width: 0; 361 | background-position: top; 362 | 363 | height: $bar-footer-height; 364 | 365 | &.item-input-inset { 366 | position: absolute; 367 | } 368 | } 369 | 370 | // Don't render padding if the bar is just for tabs 371 | .bar-tabs { 372 | padding: 0; 373 | } 374 | 375 | .bar-subheader { 376 | top: $bar-height; 377 | display: block; 378 | 379 | height: $bar-subheader-height; 380 | } 381 | .bar-subfooter { 382 | bottom: $bar-footer-height; 383 | display: block; 384 | 385 | height: $bar-subfooter-height; 386 | } 387 | 388 | .nav-bar-block { 389 | position: absolute; 390 | top: 0; 391 | right: 0; 392 | left: 0; 393 | z-index: $z-index-bar; 394 | } 395 | 396 | .bar .back-button.hide, 397 | .bar .buttons .hide { 398 | display: none; 399 | } 400 | 401 | .nav-bar-tabs-top .bar { 402 | background-image: none; 403 | } 404 | 405 | -------------------------------------------------------------------------------- /www/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: $button-border-radius 0px 0px $button-border-radius; 49 | } 50 | &:last-child { 51 | border-right-width: 1px; 52 | border-radius: 0px $button-border-radius $button-border-radius 0px; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /www/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 | -------------------------------------------------------------------------------- /www/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, $checkbox-on-border-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, $checkbox-off-border-light); 18 | } 19 | .checkbox-stable { 20 | @include checkbox-style($checkbox-off-border-stable, $checkbox-on-bg-stable, $checkbox-off-border-stable); 21 | } 22 | .checkbox-positive { 23 | @include checkbox-style($checkbox-off-border-positive, $checkbox-on-bg-positive, $checkbox-off-border-positive); 24 | } 25 | .checkbox-calm { 26 | @include checkbox-style($checkbox-off-border-calm, $checkbox-on-bg-calm, $checkbox-off-border-calm); 27 | } 28 | .checkbox-assertive { 29 | @include checkbox-style($checkbox-off-border-assertive, $checkbox-on-bg-assertive, $checkbox-off-border-assertive); 30 | } 31 | .checkbox-balanced { 32 | @include checkbox-style($checkbox-off-border-balanced, $checkbox-on-bg-balanced, $checkbox-off-border-balanced); 33 | } 34 | .checkbox-energized{ 35 | @include checkbox-style($checkbox-off-border-energized, $checkbox-on-bg-energized, $checkbox-off-border-energized); 36 | } 37 | .checkbox-royal { 38 | @include checkbox-style($checkbox-off-border-royal, $checkbox-on-bg-royal, $checkbox-off-border-royal); 39 | } 40 | .checkbox-dark { 41 | @include checkbox-style($checkbox-off-border-dark, $checkbox-on-bg-dark, $checkbox-off-border-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 | @include 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: 33%; 96 | left: 25%; 97 | display: table; 98 | width: ($checkbox-width / 2); 99 | height: ($checkbox-width / 4) - 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 | .platform-android .checkbox-platform input:before, 108 | .platform-android .checkbox-platform .checkbox-icon:before, 109 | .checkbox-square input:before, 110 | .checkbox-square .checkbox-icon:before { 111 | border-radius: 2px; 112 | width: 72%; 113 | height: 72%; 114 | margin-top: 14%; 115 | margin-left: 14%; 116 | border-width: 2px; 117 | } 118 | 119 | .platform-android .checkbox-platform input:after, 120 | .platform-android .checkbox-platform .checkbox-icon:after, 121 | .checkbox-square input:after, 122 | .checkbox-square .checkbox-icon:after { 123 | border-width: 2px; 124 | top: 19%; 125 | left: 25%; 126 | width: ($checkbox-width / 2) - 1; 127 | height: 7px; 128 | } 129 | 130 | .grade-c .checkbox input:after, 131 | .grade-c .checkbox-icon:after { 132 | @include rotate(0); 133 | top: 3px; 134 | left: 4px; 135 | border: none; 136 | color: $checkbox-check-color; 137 | content: '\2713'; 138 | font-weight: bold; 139 | font-size: 20px; 140 | } 141 | 142 | // what the checkmark looks like when its checked 143 | .checkbox input:checked:after, 144 | input:checked + .checkbox-icon:after { 145 | opacity: 1; 146 | } 147 | 148 | // make sure item content have enough padding on left to fit the checkbox 149 | .item-checkbox { 150 | padding-left: ($item-padding * 2) + $checkbox-width; 151 | 152 | &.active { 153 | box-shadow: none; 154 | } 155 | } 156 | 157 | // position the checkbox to the left within an item 158 | .item-checkbox .checkbox { 159 | position: absolute; 160 | top: 50%; 161 | right: $item-padding / 2; 162 | left: $item-padding / 2; 163 | z-index: $z-index-item-checkbox; 164 | margin-top: (($checkbox-height + ($checkbox-height / 2)) / 2) * -1; 165 | } 166 | 167 | 168 | .item-checkbox.item-checkbox-right { 169 | padding-right: ($item-padding * 2) + $checkbox-width; 170 | padding-left: $item-padding; 171 | } 172 | 173 | .item-checkbox-right .checkbox input, 174 | .item-checkbox-right .checkbox-icon { 175 | float: right; 176 | } 177 | -------------------------------------------------------------------------------- /www/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, 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 | // prevent flex-shrink on WP 83 | .platform-windowsphone .item-input input{ 84 | flex-shrink: 1; 85 | } 86 | 87 | .item-input-inset { 88 | @include display-flex(); 89 | @include align-items(center); 90 | position: relative; 91 | overflow: hidden; 92 | padding: ($item-padding / 3) * 2; 93 | } 94 | 95 | .item-input-wrapper { 96 | @include display-flex(); 97 | @include flex(1, 0); 98 | @include align-items(center); 99 | @include border-radius(4px); 100 | padding-right: 8px; 101 | padding-left: 8px; 102 | background: #eee; 103 | } 104 | 105 | .item-input-inset .item-input-wrapper input { 106 | padding-left: 4px; 107 | height: 29px; 108 | background: transparent; 109 | line-height: 18px; 110 | } 111 | 112 | .item-input-wrapper ~ .button { 113 | margin-left: ($item-padding / 3) * 2; 114 | } 115 | 116 | .input-label { 117 | display: table; 118 | padding: 7px 10px 7px 0px; 119 | max-width: 200px; 120 | width: 35%; 121 | color: $input-label-color; 122 | font-size: 16px; 123 | } 124 | 125 | .placeholder-icon { 126 | color: #aaa; 127 | &:first-child { 128 | padding-right: 6px; 129 | } 130 | &:last-child { 131 | padding-left: 6px; 132 | } 133 | } 134 | 135 | .item-stacked-label { 136 | display: block; 137 | background-color: transparent; 138 | box-shadow: none; 139 | 140 | .input-label, .icon { 141 | display: inline-block; 142 | padding: 4px 0 0 0px; 143 | vertical-align: middle; 144 | } 145 | } 146 | 147 | .item-stacked-label input, 148 | .item-stacked-label textarea { 149 | @include border-radius(2px); 150 | padding: 4px 8px 3px 0; 151 | border: none; 152 | background-color: $input-bg; 153 | } 154 | .item-stacked-label input { 155 | overflow: hidden; 156 | height: $line-height-computed + $font-size-base + 12px; 157 | } 158 | 159 | .item-floating-label { 160 | display: block; 161 | background-color: transparent; 162 | box-shadow: none; 163 | 164 | .input-label { 165 | position: relative; 166 | padding: 5px 0 0 0; 167 | opacity: 0; 168 | top: 10px; 169 | @include transition(opacity .15s ease-in, top .2s linear); 170 | 171 | &.has-input { 172 | opacity: 1; 173 | top: 0; 174 | @include transition(opacity .15s ease-in, top .2s linear); 175 | } 176 | } 177 | } 178 | 179 | 180 | // Form Controls 181 | // ------------------------------- 182 | 183 | // Shared size and type resets 184 | textarea, 185 | input[type="text"], 186 | input[type="password"], 187 | input[type="datetime"], 188 | input[type="datetime-local"], 189 | input[type="date"], 190 | input[type="month"], 191 | input[type="time"], 192 | input[type="week"], 193 | input[type="number"], 194 | input[type="email"], 195 | input[type="url"], 196 | input[type="search"], 197 | input[type="tel"], 198 | input[type="color"] { 199 | display: block; 200 | padding-top: 2px; 201 | padding-left: 0; 202 | height: $line-height-computed + $font-size-base; 203 | color: $input-color; 204 | vertical-align: middle; 205 | font-size: $font-size-base; 206 | line-height: $font-size-base + 2; 207 | } 208 | 209 | .platform-ios, 210 | .platform-android { 211 | input[type="datetime-local"], 212 | input[type="date"], 213 | input[type="month"], 214 | input[type="time"], 215 | input[type="week"] { 216 | padding-top: 8px; 217 | } 218 | } 219 | 220 | .item-input { 221 | input, 222 | textarea { 223 | width: 100%; 224 | } 225 | } 226 | 227 | textarea { 228 | padding-left: 0; 229 | @include placeholder($input-color-placeholder, -3px); 230 | } 231 | 232 | // Reset height since textareas have rows 233 | textarea { 234 | height: auto; 235 | } 236 | 237 | // Everything else 238 | textarea, 239 | input[type="text"], 240 | input[type="password"], 241 | input[type="datetime"], 242 | input[type="datetime-local"], 243 | input[type="date"], 244 | input[type="month"], 245 | input[type="time"], 246 | input[type="week"], 247 | input[type="number"], 248 | input[type="email"], 249 | input[type="url"], 250 | input[type="search"], 251 | input[type="tel"], 252 | input[type="color"] { 253 | border: 0; 254 | } 255 | 256 | // Position radios and checkboxes better 257 | input[type="radio"], 258 | input[type="checkbox"] { 259 | margin: 0; 260 | line-height: normal; 261 | } 262 | 263 | // Reset width of input images, buttons, radios, checkboxes 264 | .item-input { 265 | input[type="file"], 266 | input[type="image"], 267 | input[type="submit"], 268 | input[type="reset"], 269 | input[type="button"], 270 | input[type="radio"], 271 | input[type="checkbox"] { 272 | width: auto; // Override of generic input selector 273 | } 274 | } 275 | 276 | // Set the height of file to match text inputs 277 | input[type="file"] { 278 | line-height: $input-height-base; 279 | } 280 | 281 | // Text input classes to hide text caret during scroll 282 | .previous-input-focus, 283 | .cloned-text-input + input, 284 | .cloned-text-input + textarea { 285 | position: absolute !important; 286 | left: -9999px; 287 | width: 200px; 288 | } 289 | 290 | 291 | // Placeholder 292 | // ------------------------------- 293 | input, 294 | textarea { 295 | @include placeholder(); 296 | } 297 | 298 | 299 | // DISABLED STATE 300 | // ------------------------------- 301 | 302 | // Disabled and read-only inputs 303 | input[disabled], 304 | select[disabled], 305 | textarea[disabled], 306 | input[readonly]:not(.cloned-text-input), 307 | textarea[readonly]:not(.cloned-text-input), 308 | select[readonly] { 309 | background-color: $input-bg-disabled; 310 | cursor: not-allowed; 311 | } 312 | // Explicitly reset the colors here 313 | input[type="radio"][disabled], 314 | input[type="checkbox"][disabled], 315 | input[type="radio"][readonly], 316 | input[type="checkbox"][readonly] { 317 | background-color: transparent; 318 | } 319 | -------------------------------------------------------------------------------- /www/lib/ionic/scss/_grid.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid 3 | * -------------------------------------------------- 4 | * Using flexbox for the grid, inspired by Philip Walton: 5 | * http://philipwalton.github.io/solved-by-flexbox/demos/grids/ 6 | * By default each .col within a .row will evenly take up 7 | * available width, and the height of each .col with take 8 | * up the height of the tallest .col in the same .row. 9 | */ 10 | 11 | .row { 12 | @include display-flex(); 13 | padding: ($grid-padding-width / 2); 14 | width: 100%; 15 | } 16 | 17 | .row-wrap { 18 | @include flex-wrap(wrap); 19 | } 20 | 21 | .row-no-padding { 22 | padding: 0; 23 | 24 | > .col { 25 | padding: 0; 26 | } 27 | } 28 | 29 | .row + .row { 30 | margin-top: ($grid-padding-width / 2) * -1; 31 | padding-top: 0; 32 | } 33 | 34 | .col { 35 | @include flex(1); 36 | display: block; 37 | padding: ($grid-padding-width / 2); 38 | width: 100%; 39 | } 40 | 41 | 42 | /* Vertically Align Columns */ 43 | /* .row-* vertically aligns every .col in the .row */ 44 | .row-top { 45 | @include align-items(flex-start); 46 | } 47 | .row-bottom { 48 | @include align-items(flex-end); 49 | } 50 | .row-center { 51 | @include align-items(center); 52 | } 53 | .row-stretch { 54 | @include align-items(stretch); 55 | } 56 | .row-baseline { 57 | @include align-items(baseline); 58 | } 59 | 60 | /* .col-* vertically aligns an individual .col */ 61 | .col-top { 62 | @include align-self(flex-start); 63 | } 64 | .col-bottom { 65 | @include align-self(flex-end); 66 | } 67 | .col-center { 68 | @include align-self(center); 69 | } 70 | 71 | /* Column Offsets */ 72 | .col-offset-10 { 73 | margin-left: 10%; 74 | } 75 | .col-offset-20 { 76 | margin-left: 20%; 77 | } 78 | .col-offset-25 { 79 | margin-left: 25%; 80 | } 81 | .col-offset-33, .col-offset-34 { 82 | margin-left: 33.3333%; 83 | } 84 | .col-offset-50 { 85 | margin-left: 50%; 86 | } 87 | .col-offset-66, .col-offset-67 { 88 | margin-left: 66.6666%; 89 | } 90 | .col-offset-75 { 91 | margin-left: 75%; 92 | } 93 | .col-offset-80 { 94 | margin-left: 80%; 95 | } 96 | .col-offset-90 { 97 | margin-left: 90%; 98 | } 99 | 100 | 101 | /* Explicit Column Percent Sizes */ 102 | /* By default each grid column will evenly distribute */ 103 | /* across the grid. However, you can specify individual */ 104 | /* columns to take up a certain size of the available area */ 105 | .col-10 { 106 | @include flex(0, 0, 10%); 107 | max-width: 10%; 108 | } 109 | .col-20 { 110 | @include flex(0, 0, 20%); 111 | max-width: 20%; 112 | } 113 | .col-25 { 114 | @include flex(0, 0, 25%); 115 | max-width: 25%; 116 | } 117 | .col-33, .col-34 { 118 | @include flex(0, 0, 33.3333%); 119 | max-width: 33.3333%; 120 | } 121 | .col-50 { 122 | @include flex(0, 0, 50%); 123 | max-width: 50%; 124 | } 125 | .col-66, .col-67 { 126 | @include flex(0, 0, 66.6666%); 127 | max-width: 66.6666%; 128 | } 129 | .col-75 { 130 | @include flex(0, 0, 75%); 131 | max-width: 75%; 132 | } 133 | .col-80 { 134 | @include flex(0, 0, 80%); 135 | max-width: 80%; 136 | } 137 | .col-90 { 138 | @include flex(0, 0, 90%); 139 | max-width: 90%; 140 | } 141 | 142 | 143 | /* Responsive Grid Classes */ 144 | /* Adding a class of responsive-X to a row */ 145 | /* will trigger the flex-direction to */ 146 | /* change to column and add some margin */ 147 | /* to any columns in the row for clearity */ 148 | 149 | @include responsive-grid-break('.responsive-sm', $grid-responsive-sm-break); 150 | @include responsive-grid-break('.responsive-md', $grid-responsive-md-break); 151 | @include responsive-grid-break('.responsive-lg', $grid-responsive-lg-break); 152 | -------------------------------------------------------------------------------- /www/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 2px 0; 22 | font-size: 16px; 23 | font-weight: normal; 24 | } 25 | h3 { 26 | margin: 0 0 4px 0; 27 | font-size: 14px; 28 | } 29 | h4 { 30 | margin: 0 0 4px 0; 31 | font-size: 12px; 32 | } 33 | h5, h6 { 34 | margin: 0 0 3px 0; 35 | font-size: 10px; 36 | } 37 | p { 38 | color: #666; 39 | font-size: 14px; 40 | margin-bottom: 2px; 41 | } 42 | 43 | h1:last-child, 44 | h2:last-child, 45 | h3:last-child, 46 | h4:last-child, 47 | h5:last-child, 48 | h6:last-child, 49 | p:last-child { 50 | margin-bottom: 0; 51 | } 52 | 53 | // Align badges within items 54 | .badge { 55 | @include display-flex(); 56 | position: absolute; 57 | top: $item-padding; 58 | right: ($item-padding * 2); 59 | } 60 | &.item-button-right .badge { 61 | right: ($item-padding * 2) + 35; 62 | } 63 | &.item-divider .badge { 64 | top: ceil($item-padding / 2); 65 | } 66 | .badge + .badge { 67 | margin-right: 5px; 68 | } 69 | 70 | // Different themes for items 71 | &.item-light { 72 | @include item-style($item-light-bg, $item-light-border, $item-light-text); 73 | } 74 | &.item-stable { 75 | @include item-style($item-stable-bg, $item-stable-border, $item-stable-text); 76 | } 77 | &.item-positive { 78 | @include item-style($item-positive-bg, $item-positive-border, $item-positive-text); 79 | } 80 | &.item-calm { 81 | @include item-style($item-calm-bg, $item-calm-border, $item-calm-text); 82 | } 83 | &.item-assertive { 84 | @include item-style($item-assertive-bg, $item-assertive-border, $item-assertive-text); 85 | } 86 | &.item-balanced { 87 | @include item-style($item-balanced-bg, $item-balanced-border, $item-balanced-text); 88 | } 89 | &.item-energized { 90 | @include item-style($item-energized-bg, $item-energized-border, $item-energized-text); 91 | } 92 | &.item-royal { 93 | @include item-style($item-royal-bg, $item-royal-border, $item-royal-text); 94 | } 95 | &.item-dark { 96 | @include item-style($item-dark-bg, $item-dark-border, $item-dark-text); 97 | } 98 | 99 | &[ng-click]:hover { 100 | cursor: pointer; 101 | } 102 | 103 | } 104 | 105 | .list-borderless .item, 106 | .item-borderless { 107 | border-width: 0; 108 | } 109 | 110 | // Link and Button Active States 111 | .item.active, 112 | .item.activated, 113 | .item-complex.active .item-content, 114 | .item-complex.activated .item-content, 115 | .item .item-content.active, 116 | .item .item-content.activated { 117 | @include item-active-style($item-default-active-bg, $item-default-active-border); 118 | 119 | // Different active themes for and 8 |

Add Stock

9 | 10 | 11 | 12 | 13 |
14 | 18 | 22 | 26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /www/views/portfolio/portfolio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{stock.symbol}} ({{stock.quantity}} @ {{stock.price | currency}}) 15 |
16 | 17 |
{{getCurrentValue(stock) | currency:'$'}}
18 |
{{getChange(stock) | currency}}
19 |
20 | 21 |
22 | 23 |
24 | 25 | 26 |
27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /www/views/portfolio/portfolio.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('App') 4 | 5 | .config(function($stateProvider) { 6 | // Declare the state for the portfolio, with the template and controller 7 | $stateProvider 8 | .state('tabs.portfolio', { 9 | url: '/portfolio', 10 | views: { 11 | portfolio: { 12 | controller: 'PortfolioController', 13 | templateUrl: 'views/portfolio/portfolio.html' 14 | } 15 | } 16 | }); 17 | }) 18 | 19 | .controller('PortfolioController', function($scope, $ionicModal, $ionicPopup, LocalStorageService, QuotesService) { 20 | // Create the portfolio model from localstorage, and other models 21 | $scope.portfolio = LocalStorageService.get('portfolio', []); 22 | $scope.item = {}; 23 | $scope.state = { 24 | remove: false 25 | }; 26 | // Private method to update the portfolio 27 | function updatePortfolio() { 28 | LocalStorageService.update('portfolio', $scope.portfolio); 29 | } 30 | // Method to get the latest quotes 31 | $scope.getQuotes = function() { 32 | var symbols = []; 33 | angular.forEach($scope.portfolio, function(stock) { 34 | if (symbols.indexOf(stock.symbol) < 0) { 35 | symbols.push(stock.symbol); 36 | } 37 | }); 38 | 39 | if (symbols.length) { 40 | QuotesService.get(symbols).then(function(quotes) { 41 | var items = {}; 42 | angular.forEach(quotes, function(quote) { 43 | items[quote.Symbol] = quote; 44 | }); 45 | $scope.quotes = items; 46 | }); 47 | } 48 | }; 49 | // Method to calculate the current value of the stocks 50 | $scope.getCurrentValue = function(stock) { 51 | return parseFloat($scope.quotes[stock.symbol].LastTradePriceOnly) * stock.quantity; 52 | }; 53 | // Method to calculate the change in value 54 | $scope.getChange = function(stock) { 55 | return $scope.getCurrentValue(stock) - stock.price * stock.quantity; 56 | }; 57 | // Method to determine if the stock has positive or negative return for background color 58 | $scope.quoteClass = function(stock) { 59 | if (!stock) { 60 | return ''; 61 | } 62 | var className = ''; 63 | var currentValue = $scope.getCurrentValue(stock); 64 | if (currentValue && currentValue > stock.price) { 65 | className = 'positive'; 66 | } else if (currentValue && currentValue < stock.price) { 67 | className = 'negative'; 68 | } 69 | 70 | return className; 71 | } 72 | // Create an Ionic modal instance for adding a new stock 73 | $ionicModal.fromTemplateUrl('views/portfolio/add-modal.html', { 74 | scope: $scope 75 | }).then(function(modal) { 76 | $scope.modal = modal; 77 | }); 78 | // Open the modal 79 | $scope.openModal = function() { 80 | $scope.modal.show(); 81 | }; 82 | // Close the modal and reset the model 83 | $scope.closeModal = function() { 84 | $scope.item = {}; 85 | $scope.modal.hide(); 86 | }; 87 | // Ensure the modal is completely destroyed after the scope is destroyed 88 | $scope.$on('$destroy', function() { 89 | $scope.modal.remove(); 90 | }); 91 | // Method to add a new stock purchase 92 | $scope.addStock = function(item) { 93 | $scope.state.remove = false; 94 | QuotesService.get([item.symbol]).then(function(quote) { 95 | if (quote[0].Name) { 96 | item.symbol = item.symbol.toUpperCase(); 97 | $scope.portfolio.push(item); 98 | updatePortfolio(); 99 | $scope.closeModal(); 100 | $scope.getQuotes(); 101 | } else { 102 | $ionicPopup.alert({ 103 | title: 'Could not find symbol.' 104 | }); 105 | } 106 | }); 107 | }; 108 | // Method to remove an item from the portfolio 109 | $scope.remove = function($index) { 110 | $scope.portfolio.splice($index, 1); 111 | updatePortfolio(); 112 | }; 113 | // Get the quotes on load 114 | $scope.getQuotes(); 115 | 116 | }); 117 | -------------------------------------------------------------------------------- /www/views/quotes/quotes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
{{stock.LastTradePriceOnly | currency:'$'}}
16 |
{{stock.Change}}
17 |
18 | {{stock.symbol}} 19 | 20 | Remove 21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 |
29 |
30 | 33 | 34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /www/views/quotes/quotes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('App') 4 | 5 | .config(function($stateProvider) { 6 | // Declare the state for the quotes, with the template and controller 7 | $stateProvider 8 | .state('tabs.quotes', { 9 | url: '/quotes', 10 | views: { 11 | quotes: { 12 | controller: 'QuotesController', 13 | templateUrl: 'views/quotes/quotes.html' 14 | } 15 | } 16 | }); 17 | }) 18 | 19 | .controller('QuotesController', function($scope, $ionicPopup, $ionicLoading, LocalStorageService, QuotesService) { 20 | 21 | // Get symbols from localstorage, set default values 22 | $scope.symbols = LocalStorageService.get('quotes', ['YHOO', 'AAPL', 'GOOG', 'MSFT', 'FB', 'TWTR']); 23 | $scope.form = { 24 | query: '' 25 | }; 26 | $scope.state = { 27 | reorder: false 28 | }; 29 | // Function to update the symbols in localstorage 30 | function updateSymbols() { 31 | var symbols = []; 32 | angular.forEach($scope.quotes, function(stock) { 33 | symbols.push(stock.Symbol); 34 | }); 35 | $scope.symbols = symbols; 36 | LocalStorageService.update('quotes', symbols); 37 | } 38 | // Method to handle reordering of items in the list 39 | $scope.reorder = function(stock, $fromIndex, $toIndex) { 40 | $scope.quotes.splice($fromIndex, 1); 41 | $scope.quotes.splice($toIndex, 0, stock); 42 | updateSymbols(); 43 | }; 44 | // Method to load quotes, or show an alert on error, and finally close the loader 45 | $scope.getQuotes = function() { 46 | QuotesService.get($scope.symbols).then(function(quotes) { 47 | $scope.quotes = quotes; 48 | }, function(error) { 49 | $ionicPopup.alert({ 50 | template: 'Could not load quotes right now. Please try again later.' 51 | }); 52 | }).finally(function() { 53 | $ionicLoading.hide(); 54 | $scope.$broadcast('scroll.refreshComplete'); 55 | }); 56 | }; 57 | // Method to load a quote's data and add it to the list, or show alert for not found 58 | $scope.add = function() { 59 | if ($scope.form.query) { 60 | QuotesService.get([$scope.form.query]).then(function(results) { 61 | if (results[0].Name) { 62 | $scope.symbols.push($scope.form.query); 63 | $scope.quotes.push(results[0]); 64 | $scope.form.query = ''; 65 | updateSymbols(); 66 | } else { 67 | $ionicPopup.alert({ 68 | title: 'Could not locate symbol.' 69 | }); 70 | } 71 | }); 72 | } 73 | }; 74 | // Method to remove a quote from the list 75 | $scope.remove = function($index) { 76 | $scope.symbols.splice($index, 1); 77 | $scope.quotes.splice($index, 1); 78 | updateSymbols(); 79 | }; 80 | // Method to give a class based on the quote price vs closing 81 | $scope.quoteClass = function(quote) { 82 | if (quote.PreviousClose < quote.LastTradePriceOnly) { 83 | return 'positive'; 84 | } 85 | if (quote.PreviousClose > quote.LastTradePriceOnly) { 86 | return 'negative'; 87 | } 88 | return ''; 89 | }; 90 | // Start by showing the loader the first time, and request the quotes 91 | $ionicLoading.show(); 92 | $scope.getQuotes(); 93 | 94 | }); 95 | -------------------------------------------------------------------------------- /www/views/tabs/tabs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /www/views/tabs/tabs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('App') 4 | 5 | .config(function($stateProvider) { 6 | $stateProvider 7 | .state('tabs', { 8 | abstract: true, 9 | url: '/tabs', 10 | templateUrl: 'views/tabs/tabs.html' 11 | }); 12 | }); 13 | --------------------------------------------------------------------------------