├── src ├── app │ ├── index.scss │ ├── app.js │ ├── app.spec.js │ ├── views │ │ ├── partials │ │ │ ├── memory.html │ │ │ ├── visitors.html │ │ │ ├── warnings.html │ │ │ ├── usage.html │ │ │ ├── messages.html │ │ │ ├── bottomSheet.html │ │ │ ├── performance.html │ │ │ ├── controlPanel.html │ │ │ ├── autocomplete.html │ │ │ └── checkboxes.html │ │ ├── table.html │ │ ├── dashboard.html │ │ ├── data-table.html │ │ ├── profile.html │ │ └── main.html │ ├── controllers │ │ ├── TableController.js │ │ ├── MessagesController.js │ │ ├── ProfileController.js │ │ ├── VisitorsController.js │ │ ├── SearchController.js │ │ ├── UsageController.js │ │ ├── MemoryController.js │ │ ├── WarningsController.js │ │ ├── ControlPanelController.js │ │ ├── DataTableController.js │ │ ├── PerformanceController.js │ │ ├── TodoController.js │ │ └── MainController.js │ ├── components │ │ ├── services │ │ │ ├── TodoListService.js │ │ │ ├── NavService.js │ │ │ ├── MessagesService.js │ │ │ ├── TableService.js │ │ │ ├── PerformanceService.js │ │ │ └── CountriesService.js │ │ └── directives │ │ │ ├── panelWidget.js │ │ │ └── messagesSection.js │ ├── index.js │ └── stylesheets │ │ ├── _custom.scss │ │ └── _table.scss ├── favicon.ico ├── assets │ └── images │ │ ├── einstein.jpg │ │ ├── feynman.jpg │ │ └── promo-amd.png ├── index.html └── 404.html ├── .bowerrc ├── .gitignore ├── gulp ├── deploy.js ├── watch.js ├── unit-tests.js ├── e2e-tests.js ├── inject.js ├── styles.js ├── server.js ├── proxy.js └── build.js ├── e2e ├── main.spec.js └── main.po.js ├── gulpfile.js ├── karma.conf.js ├── bower.json ├── .jshintrc ├── protractor.conf.js ├── LICENSE ├── changelog.md ├── package.json └── README.md /src/app/index.scss: -------------------------------------------------------------------------------- 1 | // injector 2 | // endinjector 3 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatlogic/angular-material-dashboard/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | .sass-cache/ 4 | .tmp/ 5 | dist/ 6 | .idea/ 7 | .publish/ 8 | -------------------------------------------------------------------------------- /src/app/app.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('app', [ 'ngMaterial' ]); 5 | 6 | })(); 7 | -------------------------------------------------------------------------------- /src/assets/images/einstein.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatlogic/angular-material-dashboard/HEAD/src/assets/images/einstein.jpg -------------------------------------------------------------------------------- /src/assets/images/feynman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatlogic/angular-material-dashboard/HEAD/src/assets/images/feynman.jpg -------------------------------------------------------------------------------- /src/assets/images/promo-amd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatlogic/angular-material-dashboard/HEAD/src/assets/images/promo-amd.png -------------------------------------------------------------------------------- /src/app/app.spec.js: -------------------------------------------------------------------------------- 1 | describe('Abstract test to make sure that karma works properly', function() { 2 | it('Is true always true?', function() { 3 | expect(true).toBe(true); 4 | }); 5 | }); -------------------------------------------------------------------------------- /src/app/views/partials/memory.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/app/views/partials/visitors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/views/partials/warnings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gulp/deploy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var ghPages = require('gulp-gh-pages'); 5 | 6 | gulp.task('deploy', function() { 7 | return gulp.src('./dist/**/*') 8 | .pipe(ghPages()); 9 | }); 10 | -------------------------------------------------------------------------------- /e2e/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The main view', function () { 4 | var page; 5 | 6 | beforeEach(function () { 7 | browser.get('http://localhost:3000/index.html'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /e2e/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | }; 10 | 11 | module.exports = new MainPage(); 12 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | gulp.paths = { 6 | src: 'src', 7 | dist: 'dist', 8 | tmp: '.tmp', 9 | e2e: 'e2e' 10 | }; 11 | 12 | require('require-dir')('./gulp'); 13 | 14 | gulp.task('default', ['clean'], function () { 15 | gulp.start('build'); 16 | }); 17 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(config) { 4 | 5 | config.set({ 6 | autoWatch : false, 7 | 8 | frameworks: ['jasmine'], 9 | 10 | browsers : ['PhantomJS'], 11 | 12 | plugins : [ 13 | 'karma-phantomjs-launcher', 14 | 'karma-jasmine' 15 | ] 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | gulp.task('watch', ['inject'], function () { 8 | gulp.watch([ 9 | paths.src + '/*.html', 10 | paths.src + '/{app,components}/**/*.scss', 11 | paths.src + '/{app,components}/**/*.js', 12 | 'bower.json' 13 | ], ['inject']); 14 | }); 15 | -------------------------------------------------------------------------------- /src/app/views/partials/usage.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

RAM

5 |
6 |
7 | 8 |

Storage

9 |
10 |
11 | -------------------------------------------------------------------------------- /src/app/controllers/TableController.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | angular 4 | .module('app') 5 | .controller('TableController', [ 6 | 'tableService', 7 | TableController 8 | ]); 9 | 10 | function TableController(tableService) { 11 | var vm = this; 12 | 13 | vm.tableData = []; 14 | 15 | tableService 16 | .loadAllItems() 17 | .then(function(tableData) { 18 | vm.tableData = [].concat(tableData); 19 | }); 20 | } 21 | 22 | })(); 23 | -------------------------------------------------------------------------------- /src/app/controllers/MessagesController.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | angular 4 | .module('app') 5 | .controller('MessagesController', [ 6 | 'messagesService', 7 | MessagesController 8 | ]); 9 | 10 | function MessagesController(messagesService) { 11 | var vm = this; 12 | 13 | vm.messages = []; 14 | 15 | messagesService 16 | .loadAllItems() 17 | .then(function(messages) { 18 | vm.messages = [].concat(messages); 19 | }); 20 | } 21 | 22 | })(); 23 | -------------------------------------------------------------------------------- /src/app/views/partials/messages.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /src/app/views/partials/bottomSheet.html: -------------------------------------------------------------------------------- 1 | 2 | Select action 3 | 4 | 5 | 6 | {{action.icon}} 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/app/views/partials/performance.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | Last week 5 | Last month 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | -------------------------------------------------------------------------------- /src/app/components/services/TodoListService.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('app') 5 | .service('todoListService', [ 6 | '$q', 7 | todoList 8 | ]); 9 | 10 | function todoList($q){ 11 | var todos = [ 12 | {text: 'Continuous integration', done: false}, 13 | {text: 'Implement panel-widget directive', done: true}, 14 | {text: 'Add backend', done: false} 15 | ]; 16 | 17 | return { 18 | loadAllItems : function() { 19 | return $q.when(todos); 20 | } 21 | }; 22 | } 23 | })(); 24 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-material-dashboard", 3 | "description": "Material Design Angular Admin Dashboard", 4 | "homepage": "https://github.com/micrum/angular-material-admin", 5 | "license": "MIT", 6 | "version": "1.3.0", 7 | "dependencies": { 8 | "jquery": "3.3.1", 9 | "angular-animate": "1.7.5", 10 | "angular-cookies": "1.7.5", 11 | "angular-touch": "1.7.5", 12 | "angular-sanitize": "1.7.5", 13 | "angular-ui-router": "1.0.20", 14 | "angular": "1.7.5", 15 | "angular-nvd3": "1.0.0-rc.2", 16 | "angular-material": "1.0.6", 17 | "angular-mocks": "1.7.5", 18 | "angular-material-data-table": "0.10.10" 19 | }, 20 | "devDependencies": {} 21 | } 22 | -------------------------------------------------------------------------------- /src/app/views/partials/controlPanel.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | Staging server 8 | Production server 9 | 10 | 11 | 12 | Reload server 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app/controllers/ProfileController.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | angular 4 | .module('app') 5 | .controller('ProfileController', [ 6 | ProfileController 7 | ]); 8 | 9 | function ProfileController() { 10 | var vm = this; 11 | 12 | vm.user = { 13 | title: 'Admin', 14 | email: 'contact@flatlogic.com', 15 | firstName: '', 16 | lastName: '' , 17 | company: 'FlatLogic Inc.' , 18 | address: 'Fabritsiusa str, 4' , 19 | city: 'Minsk' , 20 | state: '' , 21 | biography: 'We are young and ambitious full service design and technology company. ' + 22 | 'Our focus is JavaScript development and User Interface design.', 23 | postalCode : '220007' 24 | }; 25 | } 26 | 27 | })(); 28 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true, 21 | "validthis": true, 22 | "globals": { 23 | "angular": false, 24 | // Angular Mocks 25 | "inject": false, 26 | // JASMINE 27 | "describe": false, 28 | "it": false, 29 | "before": false, 30 | "beforeEach": false, 31 | "after": false, 32 | "afterEach": false, 33 | "expect": false 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; 4 | 5 | // An example configuration file. 6 | exports.config = { 7 | // The address of a running selenium server. 8 | //seleniumAddress: 'http://localhost:4444/wd/hub', 9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 10 | 11 | // Capabilities to be passed to the webdriver instance. 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | 16 | // Spec patterns are relative to the current working directly when 17 | // protractor is called. 18 | specs: [paths.e2e + '/**/*.js'], 19 | 20 | // Options to be passed to Jasmine-node. 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/app/components/services/NavService.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('app') 5 | .service('navService', [ 6 | '$q', 7 | navService 8 | ]); 9 | 10 | function navService($q){ 11 | var menuItems = [ 12 | { 13 | name: 'Dashboard', 14 | icon: 'dashboard', 15 | sref: '.dashboard' 16 | }, 17 | { 18 | name: 'Profile', 19 | icon: 'person', 20 | sref: '.profile' 21 | }, 22 | { 23 | name: 'Table', 24 | icon: 'view_module', 25 | sref: '.table' 26 | }, 27 | { 28 | name: 'Data Table', 29 | icon: 'view_module', 30 | sref: '.data-table' 31 | } 32 | ]; 33 | 34 | return { 35 | loadAllItems : function() { 36 | return $q.when(menuItems); 37 | } 38 | }; 39 | } 40 | 41 | })(); 42 | -------------------------------------------------------------------------------- /gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var wiredep = require('wiredep'); 8 | 9 | var paths = gulp.paths; 10 | 11 | function runTests (singleRun, done) { 12 | var bowerDeps = wiredep({ 13 | directory: 'bower_components', 14 | exclude: ['bootstrap-sass-official'], 15 | dependencies: true, 16 | devDependencies: true 17 | }); 18 | 19 | var testFiles = bowerDeps.js.concat([ 20 | paths.src + '/{app,components}/**/*.js' 21 | ]); 22 | 23 | gulp.src(testFiles) 24 | .pipe($.karma({ 25 | configFile: 'karma.conf.js', 26 | action: (singleRun)? 'run': 'watch' 27 | })) 28 | .on('error', function (err) { 29 | // Make sure failed tests cause gulp to exit non-zero 30 | throw err; 31 | }); 32 | } 33 | 34 | gulp.task('test', function (done) { runTests(true /* singleRun */, done) }); 35 | gulp.task('test:auto', function (done) { runTests(false /* singleRun */, done) }); 36 | -------------------------------------------------------------------------------- /src/app/controllers/VisitorsController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | angular 3 | .module('app') 4 | .controller('VisitorsController', [ 5 | VisitorsController 6 | ]); 7 | 8 | function VisitorsController() { 9 | var vm = this; 10 | 11 | // TODO: move data to the service 12 | vm.visitorsChartData = [ {key: 'Mobile', y: 5264}, { key: 'Desktop', y: 3872} ]; 13 | 14 | vm.chartOptions = { 15 | chart: { 16 | type: 'pieChart', 17 | height: 210, 18 | donut: true, 19 | x: function (d) { return d.key; }, 20 | y: function (d) { return d.y; }, 21 | valueFormat: (d3.format(".0f")), 22 | color: ['rgb(0, 150, 136)', '#E75753'], 23 | showLabels: false, 24 | showLegend: false, 25 | title: 'Over 9K', 26 | margin: { top: -10 } 27 | } 28 | }; 29 | } 30 | })(); 31 | -------------------------------------------------------------------------------- /gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var paths = gulp.paths; 10 | 11 | // Downloads the selenium webdriver 12 | gulp.task('webdriver-update', $.protractor.webdriver_update); 13 | 14 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 15 | 16 | function runProtractor (done) { 17 | 18 | gulp.src(paths.e2e + '/**/*.js') 19 | .pipe($.protractor.protractor({ 20 | configFile: 'protractor.conf.js', 21 | })) 22 | .on('error', function (err) { 23 | // Make sure failed tests cause gulp to exit non-zero 24 | throw err; 25 | }) 26 | .on('end', function () { 27 | // Close browser sync server 28 | browserSync.exit(); 29 | done(); 30 | }); 31 | } 32 | 33 | gulp.task('protractor', ['protractor:src']); 34 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); 35 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); 36 | -------------------------------------------------------------------------------- /src/app/controllers/SearchController.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | angular 4 | .module('app') 5 | .controller('SearchController', [ 6 | '$timeout', '$q', 'countriesService', 7 | SearchController 8 | ]); 9 | 10 | function SearchController($timeout, $q, countriesService) { 11 | var vm = this; 12 | 13 | vm.countries = countriesService.loadAll(); 14 | vm.selectedCountry = null; 15 | vm.searchText = null; 16 | vm.querySearch = querySearch; 17 | vm.disableCaching = true; 18 | 19 | function querySearch (query) { 20 | var results = query ? vm.countries.filter( createFilterFor(query) ) : [], 21 | deferred; 22 | deferred = $q.defer(); 23 | $timeout(function () { deferred.resolve( results ); }, Math.random() * 1000, false); 24 | return deferred.promise; 25 | } 26 | 27 | function createFilterFor(query) { 28 | var lowercaseQuery = angular.lowercase(query); 29 | return function filterFn(state) { 30 | return (state.value.indexOf(lowercaseQuery) === 0); 31 | }; 32 | } 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /src/app/views/table.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 25 |
#IssueStatusProgress
{{$index + 1}}{{data.issue}}{{data.status}} 18 | 21 | 22 |
26 |
27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 flatlogic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/app/controllers/UsageController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | angular 3 | .module('app') 4 | .controller('UsageController', [ 5 | UsageController 6 | ]); 7 | 8 | function UsageController() { 9 | var vm = this; 10 | 11 | // TODO: move data to the service 12 | vm.ramChartData = [{key: 'Memory', y: 768660}, { key: 'Cache', y: 367404}, {key: 'Swap', y: 41924 }]; 13 | vm.storageChartData = [{key: 'System', y: 126560}, {key: 'Other', y: 224365 }]; 14 | 15 | vm.chartOptions = { 16 | chart: { 17 | type: 'pieChart', 18 | height: 130, 19 | donut: true, 20 | x: function (d) { return d.key; }, 21 | y: function (d) { return d.y; }, 22 | valueFormat: (d3.format(".0f")), 23 | color: ['rgb(0, 150, 136)', '#E75753', 'rgb(235, 235, 235)'], 24 | showLabels: false, 25 | showLegend: false, 26 | title: '83%', 27 | margin: { top: -10, left: -20, right: -20 } 28 | } 29 | }; 30 | } 31 | })(); 32 | -------------------------------------------------------------------------------- /src/app/views/partials/autocomplete.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | Disable caching 5 | Enable caching 6 | 7 | 8 | 9 | 10 | 16 | {{item.display}} 17 | 18 | 19 |

Selected country: 20 | {{vm.selectedCountry.display || 'No country selected'}} 21 |

22 |

Country code: 23 | {{vm.selectedCountry.code || 'No country selected'}} 24 |

25 |
26 |
27 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## [1.4.1] 3 | 4 | ### Updated 5 | 6 | - Minor packages update 7 | 8 | ## [1.4.0] 9 | 10 | ### Updated 11 | 12 | - Minor packages update 13 | 14 | ## [1.3.0] 15 | 16 | ### Updated 17 | 18 | - Angular Material upgraded to 1.0 19 | - Angular upgraded to 1.5 20 | - Dependencies updated 21 | 22 | ## [1.2.0] 23 | 24 | ### Fixed 25 | 26 | - Lot of UX/UI improvements 27 | - Minor fixes 28 | 29 | ### New Features 30 | 31 | - Browsers support 32 | - Added messages section directive 33 | - Changed app structure 34 | 35 | ## [1.1.0] 36 | 37 | ### New Features 38 | 39 | - Implement message-section directive 40 | 41 | ## [1.0.1] 42 | 43 | ### Updated 44 | 45 | - Update dependencies 46 | 47 | ## [1.1.0] 48 | 49 | ### New Features 50 | 51 | - New layout 52 | - Custom theme styles 53 | - New dashboard sections 54 | - Angular Material v0.10.0 55 | - Added md-menu 56 | - Google material icons 57 | - NVD3 charts 58 | - Responsive layout 59 | - Nested views 60 | 61 | ### Fixed 62 | 63 | - Adjusted panel-widget directive 64 | - Stylesheets reorganized 65 | - Widgets reworked 66 | - Adjusted table 67 | - Reorganized app structure 68 | - Adjusted sidebars 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | var wiredep = require('wiredep').stream; 10 | 11 | gulp.task('inject', ['styles'], function () { 12 | 13 | var injectStyles = gulp.src([ 14 | paths.tmp + '/serve/{app,components}/**/*.css', 15 | '!' + paths.tmp + '/serve/app/vendor.css' 16 | ], { read: false }); 17 | 18 | var injectScripts = gulp.src([ 19 | paths.src + '/{app,components}/**/*.js', 20 | '!' + paths.src + '/{app,components}/**/*.spec.js', 21 | '!' + paths.src + '/{app,components}/**/*.mock.js' 22 | ]).pipe($.angularFilesort()); 23 | 24 | var injectOptions = { 25 | ignorePath: [paths.src, paths.tmp + '/serve'], 26 | addRootSlash: false 27 | }; 28 | 29 | var wiredepOptions = { 30 | directory: 'bower_components', 31 | exclude: [/bootstrap\.css/, /foundation\.css/] 32 | }; 33 | 34 | return gulp.src(paths.src + '/*.html') 35 | .pipe($.inject(injectStyles, injectOptions)) 36 | .pipe($.inject(injectScripts, injectOptions)) 37 | .pipe(wiredep(wiredepOptions)) 38 | .pipe(gulp.dest(paths.tmp + '/serve')); 39 | 40 | }); 41 | -------------------------------------------------------------------------------- /src/app/views/dashboard.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 |
17 | -------------------------------------------------------------------------------- /src/app/views/partials/checkboxes.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

{{vm.remaining()}} of {{vm.todos.length}} remaining

4 | Toggle All 5 | 6 |
7 | 8 | 9 | {{todo.text}} 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 | add 20 | 21 |
22 | 23 | Remove completed 24 | 25 |
26 |
-------------------------------------------------------------------------------- /src/app/controllers/MemoryController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | angular 3 | .module('app') 4 | .controller('MemoryController', [ 5 | MemoryController 6 | ]); 7 | 8 | function MemoryController() { 9 | var vm = this; 10 | 11 | // TODO: move data to the service 12 | vm.memoryChartData = [ {key: 'memory', y: 42}, { key: 'free', y: 58} ]; 13 | 14 | vm.chartOptions = { 15 | chart: { 16 | type: 'pieChart', 17 | height: 210, 18 | donut: true, 19 | pie: { 20 | startAngle: function (d) { return d.startAngle/2 -Math.PI/2 }, 21 | endAngle: function (d) { return d.endAngle/2 -Math.PI/2 } 22 | }, 23 | x: function (d) { return d.key; }, 24 | y: function (d) { return d.y; }, 25 | valueFormat: (d3.format(".0f")), 26 | color: ['rgb(0, 150, 136)', 'rgb(191, 191, 191)'], 27 | showLabels: false, 28 | showLegend: false, 29 | tooltips: false, 30 | title: '42%', 31 | titleOffset: -10, 32 | margin: { bottom: -80, left: -20, right: -20 } 33 | } 34 | }; 35 | } 36 | })(); 37 | -------------------------------------------------------------------------------- /src/app/components/directives/panelWidget.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('app') 4 | .directive('panelWidget', function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | transclude: true, 9 | scope: { title: '@', template: '@', options: '@' }, 10 | template: '' + 11 | '
' + 12 | ' ' + 13 | '
' + 14 | '

{{title}}

' + 15 | ' ' + 16 | ' ' + 17 | ' more_vert' + 18 | ' ' + 19 | '
' + 20 | '
' + 21 | '
' + 22 | '
', 23 | compile: function(element, attrs, linker) { 24 | return function(scope, element) { 25 | linker(scope, function(clone) { 26 | element.append(clone); 27 | }); 28 | }; 29 | } 30 | }; 31 | }); 32 | -------------------------------------------------------------------------------- /src/app/components/directives/messagesSection.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app') 6 | .directive('messagesSection', messagesSectionDirective); 7 | 8 | function messagesSectionDirective() { 9 | return { 10 | restrict: 'E', 11 | scope: { 12 | title: '@', 13 | theme: '@', 14 | messages: '=' 15 | }, 16 | template: '' + 17 | '
' + 18 | ' {{title}}' + 19 | ' ' + 20 | ' ' + 21 | ' ' + 22 | '
' + 23 | '

{{message.subject}}

' + 24 | '

{{message.userName}}

' + 25 | '

{{message.text}}

' + 26 | '
' + 27 | '
' + 28 | '
' + 29 | '
', 30 | link : function(scope, element, attrs) { 31 | } 32 | }; 33 | } 34 | })(); -------------------------------------------------------------------------------- /src/app/controllers/WarningsController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | angular 3 | .module('app') 4 | .controller('WarningsController', [ 5 | WarningsController 6 | ]); 7 | 8 | function WarningsController() { 9 | var vm = this; 10 | 11 | // TODO: move data to the service 12 | vm.warningsChartData = warningFunction; 13 | 14 | function warningFunction() { 15 | var sin = []; 16 | for (var i = 0; i < 100; i++) { 17 | sin.push({x: i, y: Math.abs(Math.cos(i/10) *0.25*i + 0.9 - 0.4*i)}); 18 | } 19 | return [ { values: sin, color: 'rgb(0, 150, 136)', area: true } ]; 20 | } 21 | 22 | vm.chartOptions = { 23 | chart: { 24 | type: 'lineChart', 25 | height: 210, 26 | margin: { top: -10, left: -20, right: -20 }, 27 | x: function (d) { return d.x }, 28 | y: function (d) { return d.y }, 29 | showLabels: false, 30 | showLegend: false, 31 | title: 'Over 9K', 32 | showYAxis: false, 33 | showXAxis: false, 34 | tooltip: { contentGenerator: function (d) { return '' + Math.round(d.point.y) + '' } } 35 | } 36 | }; 37 | } 38 | })(); 39 | -------------------------------------------------------------------------------- /src/app/controllers/ControlPanelController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | angular 4 | .module('app') 5 | .controller('ControlPanelController', [ 6 | '$mdDialog', '$interval', 7 | ControlPanelController 8 | ]); 9 | 10 | function ControlPanelController($mdDialog, $interval) { 11 | var vm = this; 12 | 13 | vm.buttonEnabled = false; 14 | vm.showProgress = false; 15 | vm.reloadServer = 'Staging'; 16 | vm.performProgress = performProgress; 17 | vm.determinateValue = 10; 18 | 19 | function performProgress() { 20 | vm.showProgress = true; 21 | interval = $interval(function() { 22 | vm.determinateValue += 1; 23 | if (vm.determinateValue > 100) { 24 | vm.determinateValue = 10; 25 | vm.showProgress = false; 26 | showAlert(); 27 | $interval.cancel(interval) 28 | } 29 | }, 50, 0, true); 30 | } 31 | 32 | function showAlert() { 33 | alert = $mdDialog.alert({ 34 | title: 'Reloading done!', 35 | content: vm.reloadServer + " server reloaded.", 36 | ok: 'Close' 37 | }); 38 | $mdDialog 39 | .show(alert) 40 | .finally(function () { 41 | alert = undefined; 42 | }); 43 | } 44 | } 45 | 46 | })(); 47 | -------------------------------------------------------------------------------- /src/app/controllers/DataTableController.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | angular 4 | .module('app') 5 | .controller('DataTableController', [ 6 | 'tableService', 7 | '$scope', 8 | TableController 9 | 10 | ]); 11 | 12 | function TableController(tableService , $scope) { 13 | var vm = this; 14 | 15 | vm.tableData = []; 16 | vm.totalItems = 0; 17 | 18 | $scope.selected = []; 19 | 20 | $scope.query = { 21 | order: 'name', 22 | limit: 10, 23 | page: 1 24 | }; 25 | $scope.selected = []; 26 | 27 | $scope.render = function (T) { 28 | return T; 29 | } 30 | var lastQuery = null; 31 | vm.getItems = function () { 32 | /** 33 | * I don't know why this function is being called too many times, 34 | * it supposed to call once per pagination, so the next 3 lines are only to avoid 35 | * multiple requests. 36 | */ 37 | var query = JSON.stringify($scope.query); 38 | if (query == lastQuery) return; 39 | lastQuery = query; 40 | GetItemsData($scope.query); 41 | 42 | } 43 | 44 | function GetItemsData(query) { 45 | tableService 46 | .loadByPagination(query) 47 | .then(function(tableData) { 48 | vm.tableData = tableData.items; 49 | // Represents the count of database count of records, not items array! 50 | vm.totalItems = tableData.count; 51 | 52 | }); 53 | 54 | } 55 | 56 | GetItemsData($scope.query); 57 | 58 | 59 | 60 | 61 | } 62 | 63 | })(); 64 | -------------------------------------------------------------------------------- /gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | // var sass = require('gulp-sass'); 9 | 10 | gulp.task('styles', function () { 11 | 12 | var sassOptions = { 13 | style: 'expanded', 14 | 'sourcemap=none': true 15 | }; 16 | 17 | var injectFiles = gulp.src([ 18 | paths.src + '/{app,components}/**/*.scss', 19 | '!' + paths.src + '/app/index.scss', 20 | '!' + paths.src + '/app/vendor.scss' 21 | ], { read: false }); 22 | 23 | var injectOptions = { 24 | transform: function(filePath) { 25 | filePath = filePath.replace(paths.src + '/app/', ''); 26 | filePath = filePath.replace(paths.src + '/components/', '../components/'); 27 | return '@import \'' + filePath + '\';'; 28 | }, 29 | starttag: '// injector', 30 | endtag: '// endinjector', 31 | addRootSlash: false 32 | }; 33 | 34 | var indexFilter = $.filter('index.scss'); 35 | 36 | return gulp.src([ 37 | paths.src + '/app/index.scss', 38 | paths.src + '/app/vendor.scss' 39 | ]) 40 | .pipe(indexFilter) 41 | .pipe($.inject(injectFiles, injectOptions)) 42 | .pipe($.sass(sassOptions) 43 | // .pipe($.rubySass(sassOptions) 44 | .on('error', function (err) { 45 | console.error('Error!', err.message); 46 | }) 47 | ) 48 | 49 | .pipe($.autoprefixer()) 50 | .on('error', function handleError(err) { 51 | console.error(err.toString()); 52 | this.emit('end'); 53 | }) 54 | .pipe(gulp.dest(paths.tmp + '/serve/app/')); 55 | }); 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-material-dashboard", 3 | "version": "1.3.0", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "browser-sync": "2.26.12", 7 | "chalk": "2.4.2", 8 | "del": "3.0.0", 9 | "gulp": "3.9.1", 10 | "gulp-angular-filesort": "1.2.1", 11 | "gulp-angular-templatecache": "2.2.7", 12 | "gulp-autoprefixer": "6.0.0", 13 | "gulp-consolidate": "0.2.0", 14 | "gulp-csso": "3.0.1", 15 | "gulp-filter": "5.1.0", 16 | "gulp-flatten": "0.4.0", 17 | "gulp-gh-pages": "0.5.4", 18 | "gulp-inject": "4.3.2", 19 | "gulp-jshint": "2.1.0", 20 | "gulp-karma": "0.0.5", 21 | "gulp-load-plugins": "1.5.0", 22 | "gulp-minify-html": "1.0.6", 23 | "gulp-ng-annotate": "2.1.0", 24 | "gulp-protractor": "4.1.1", 25 | "gulp-rename": "1.4.0", 26 | "gulp-replace": "1.0.0", 27 | "gulp-rev": "8.1.1", 28 | "gulp-rev-replace": "0.4.4", 29 | "gulp-sass": "3.0.0", 30 | "gulp-size": "3.0.0", 31 | "gulp-uglify": "3.0.2", 32 | "gulp-useref": "3.1.6", 33 | "http-proxy": "1.17.0", 34 | "jasmine-core": "3.2.1", 35 | "jshint-stylish": "2.2.1", 36 | "karma": "3.0.0", 37 | "karma-jasmine": "1.1.2", 38 | "karma-phantomjs-launcher": "1.0.4", 39 | "main-bower-files": "2.13.3", 40 | "protractor": "5.4.4", 41 | "require-dir": "1.1.0", 42 | "uglify-save-license": "0.4.1", 43 | "wiredep": "4.0.0" 44 | }, 45 | "engines": { 46 | "node": ">=6.5", 47 | "npm": ">=3.10" 48 | }, 49 | "scripts": { 50 | "init": "npm install", 51 | "install": "bower install" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var util = require('util'); 8 | 9 | var browserSync = require('browser-sync'); 10 | 11 | var middleware = require('./proxy'); 12 | 13 | function browserSyncInit(baseDir, files, browser) { 14 | browser = browser === undefined ? 'default' : browser; 15 | 16 | var routes = null; 17 | if(baseDir === paths.src || (util.isArray(baseDir) && baseDir.indexOf(paths.src) !== -1)) { 18 | routes = { 19 | '/bower_components': 'bower_components' 20 | }; 21 | } 22 | 23 | browserSync.instance = browserSync.init(files, { 24 | startPath: '/', 25 | server: { 26 | baseDir: baseDir, 27 | middleware: middleware, 28 | routes: routes 29 | }, 30 | browser: browser 31 | }); 32 | } 33 | 34 | gulp.task('serve', ['watch'], function () { 35 | browserSyncInit([ 36 | paths.tmp + '/serve', 37 | paths.src 38 | ], [ 39 | paths.tmp + '/serve/{app,components}/**/*.css', 40 | paths.src + '/{app,components}/**/*.js', 41 | paths.src + 'src/assets/images/**/*', 42 | paths.tmp + '/serve/*.html', 43 | paths.tmp + '/serve/{app,components}/**/*.html', 44 | paths.src + '/{app,components}/**/*.html' 45 | ]); 46 | }); 47 | 48 | gulp.task('serve:dist', ['build'], function () { 49 | browserSyncInit(paths.dist); 50 | }); 51 | 52 | gulp.task('serve:e2e', ['inject'], function () { 53 | browserSyncInit([paths.tmp + '/serve', paths.src], null, []); 54 | }); 55 | 56 | gulp.task('serve:e2e-dist', ['build'], function () { 57 | browserSyncInit(paths.dist, null, []); 58 | }); 59 | -------------------------------------------------------------------------------- /src/app/controllers/PerformanceController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | angular 3 | .module('app') 4 | .controller('PerformanceController', [ 5 | 'performanceService', '$q', 6 | PerformanceController 7 | ]); 8 | 9 | function PerformanceController(performanceService, $q) { 10 | var vm = this; 11 | 12 | vm.chartOptions = { 13 | chart: { 14 | type: 'stackedAreaChart', 15 | height: 350, 16 | margin: { left: -15, right: -15 }, 17 | x: function (d) { return d[0] }, 18 | y: function (d) { return d[1] }, 19 | showLabels: false, 20 | showLegend: false, 21 | title: 'Over 9K', 22 | showYAxis: false, 23 | showXAxis: false, 24 | color: ['rgb(0, 150, 136)', 'rgb(204, 203, 203)', 'rgb(149, 149, 149)', 'rgb(44, 44, 44)'], 25 | tooltip: { contentGenerator: function (d) { return '
' + d.point.y + '%
' + '
' + d.series[0].key + '
' } }, 26 | showControls: false 27 | } 28 | }; 29 | 30 | vm.performanceChartData = []; 31 | vm.performancePeriod = 'week'; 32 | vm.changePeriod = changePeriod; 33 | 34 | activate(); 35 | 36 | function activate() { 37 | var queries = [loadData()]; 38 | $q.all(queries); 39 | } 40 | 41 | 42 | function loadData() { 43 | vm.performanceChartData = performanceService.getPerformanceData(vm.performancePeriod); 44 | } 45 | 46 | function changePeriod() { 47 | loadData(); 48 | } 49 | } 50 | })(); 51 | -------------------------------------------------------------------------------- /src/app/controllers/TodoController.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | angular 3 | .module('app') 4 | .controller('TodoController', [ 5 | 'todoListService', 6 | TodoController 7 | ]); 8 | 9 | function TodoController(todoListService) { 10 | var vm = this; 11 | 12 | vm.addTodo = addTodo; 13 | vm.remaining = remaining; 14 | vm.archive = archive; 15 | vm.toggleAll = toggleAll; 16 | vm.todos = []; 17 | 18 | todoListService 19 | .loadAllItems() 20 | .then(function (todos) { 21 | vm.todos = [].concat(todos); 22 | }); 23 | 24 | function addTodo() { 25 | if (!vm.todoText) return; 26 | vm.todos.push({text: vm.todoText, done: false}); 27 | vm.todoText = ''; 28 | } 29 | 30 | function remaining() { 31 | var count = 0; 32 | angular.forEach(vm.todos, function (todo) { 33 | count += todo.done ? 0 : 1; 34 | }); 35 | return count; 36 | } 37 | 38 | function archive(e) { 39 | // Prevent from submitting 40 | e.preventDefault(); 41 | var oldTodos = vm.todos; 42 | vm.todos = []; 43 | angular.forEach(oldTodos, function (todo) { 44 | if (!todo.done) vm.todos.push(todo); 45 | }); 46 | } 47 | 48 | function toggleAll() { 49 | if (remaining() == 0) { 50 | angular.forEach(vm.todos, function (todo) { 51 | todo.done = false; 52 | }); 53 | } else { 54 | angular.forEach(vm.todos, function (todo) { 55 | todo.done = true; 56 | }); 57 | } 58 | } 59 | } 60 | })(); 61 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular Material Dashboard 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/app/views/data-table.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | Nutrition 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 |
IDDessert (100g serving)CaloriesFat (g)Carbs (g)
{{item.id}}{{item.issue}}{{item.progress}}{{item.status}} 29 | 32 | 33 |
40 |
41 | 42 | 43 |
-------------------------------------------------------------------------------- /gulp/proxy.js: -------------------------------------------------------------------------------- 1 | /*jshint unused:false */ 2 | 3 | /*************** 4 | 5 | This file allow to configure a proxy system plugged into BrowserSync 6 | in order to redirect backend requests while still serving and watching 7 | files from the web project 8 | 9 | IMPORTANT: The proxy is disabled by default. 10 | 11 | If you want to enable it, watch at the configuration options and finally 12 | change the `module.exports` at the end of the file 13 | 14 | ***************/ 15 | 16 | 'use strict'; 17 | 18 | var httpProxy = require('http-proxy'); 19 | var chalk = require('chalk'); 20 | 21 | /* 22 | * Location of your backend server 23 | */ 24 | var proxyTarget = 'http://server/context/'; 25 | 26 | var proxy = httpProxy.createProxyServer({ 27 | target: proxyTarget 28 | }); 29 | 30 | proxy.on('error', function(error, req, res) { 31 | res.writeHead(500, { 32 | 'Content-Type': 'text/plain' 33 | }); 34 | 35 | console.error(chalk.red('[Proxy]'), error); 36 | }); 37 | 38 | /* 39 | * The proxy middleware is an Express middleware added to BrowserSync to 40 | * handle backend request and proxy them to your backend. 41 | */ 42 | function proxyMiddleware(req, res, next) { 43 | /* 44 | * This test is the switch of each request to determine if the request is 45 | * for a static file to be handled by BrowserSync or a backend request to proxy. 46 | * 47 | * The existing test is a standard check on the files extensions but it may fail 48 | * for your needs. If you can, you could also check on a context in the url which 49 | * may be more reliable but can't be generic. 50 | */ 51 | if (/\.(html|css|js|png|jpg|jpeg|gif|ico|xml|rss|txt|eot|svg|ttf|woff|cur)(\?((r|v|rel|rev)=[\-\.\w]*)?)?$/.test(req.url)) { 52 | next(); 53 | } else { 54 | proxy.web(req, res); 55 | } 56 | } 57 | 58 | /* 59 | * This is where you activate or not your proxy. 60 | * 61 | * The first line activate if and the second one ignored it 62 | */ 63 | 64 | //module.exports = [proxyMiddleware]; 65 | module.exports = []; 66 | -------------------------------------------------------------------------------- /src/app/components/services/MessagesService.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('app') 5 | .service('messagesService', [ 6 | '$q', 7 | messagesService 8 | ]); 9 | 10 | function messagesService($q){ 11 | var messages = [ 12 | { 13 | userPhoto : '/assets/images/user.svg', 14 | subject: 'Electromagnetic radiation', 15 | userName: 'Wilhelm Conrad Röntgen', 16 | date: '1901', 17 | text: 'In recognition of the extraordinary services he has rendered by the discovery of the remarkable rays subsequently named after him' 18 | }, 19 | { 20 | userPhoto : '/assets/images/user.svg', 21 | subject: 'Quantum theory', 22 | userName: 'Max Planck', 23 | date: '1918', 24 | text: 'For the services he rendered to the advancement of physics by his discovery of energy quanta.' 25 | }, 26 | { 27 | userPhoto : '/assets/images/user.svg', 28 | subject: 'Photoelectric effect', 29 | userName: 'Albert Einstein', 30 | date: '1921', 31 | text: 'For his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect' 32 | }, 33 | { 34 | userPhoto : '/assets/images/user.svg', 35 | subject: 'Atomic structure', 36 | userName: 'Niels Bohr', 37 | date: '1922', 38 | text: 'For his services in the investigation of the structure of atoms and of the radiation emanating from them' 39 | }, 40 | { 41 | userPhoto : '/assets/images/user.svg', 42 | subject: 'Wave equation', 43 | userName: 'Erwin Schrödinger', 44 | date: '1933', 45 | text: 'For the discovery of new productive forms of atomic theory' 46 | }, 47 | { 48 | userPhoto : '/assets/images/user.svg', 49 | subject: 'Spin theory', 50 | userName: 'Wolfgang Pauli', 51 | date: '1945', 52 | text: 'For the discovery of the Exclusion Principle, also called the Pauli principle' 53 | } 54 | ]; 55 | 56 | return { 57 | loadAllItems : function() { 58 | return $q.when(messages); 59 | } 60 | }; 61 | } 62 | 63 | })(); 64 | -------------------------------------------------------------------------------- /src/app/components/services/TableService.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('app') 5 | .service('tableService', [ 6 | '$q', 7 | tableService 8 | ]); 9 | 10 | function tableService($q){ 11 | var tableData = [ 12 | { 13 | issue: 'Nested views', 14 | progress: 100, 15 | status: 'Done', 16 | class: 'md-accent' 17 | }, 18 | { 19 | issue: 'Table component', 20 | progress: 40, 21 | status: 'Feedback', 22 | class: '' 23 | }, 24 | { 25 | issue: 'Dashboard tiles', 26 | progress: 100, 27 | status: 'Done', 28 | class: 'md-accent' 29 | }, 30 | { 31 | issue: 'Panel widget', 32 | progress: 84, 33 | status: 'In progress', 34 | class: 'orange' 35 | }, 36 | { 37 | issue: 'Form', 38 | progress: 100, 39 | status: 'Done', 40 | class: 'md-accent' 41 | }, 42 | { 43 | issue: 'Custom CSS', 44 | progress: 20, 45 | status: 'Feedback', 46 | class: '' 47 | }, 48 | { 49 | issue: 'Add backend', 50 | progress: 1, 51 | status: 'To do', 52 | class: 'md-warn' 53 | }, 54 | { 55 | issue: 'Layout with sidebar', 56 | progress: 100, 57 | status: 'Done', 58 | class: 'md-accent' 59 | } 60 | ]; 61 | 62 | function PickRandom() { 63 | return Object.assign({}, tableData[Math.floor(Math.random()*tableData.length)]); 64 | } 65 | 66 | return { 67 | loadAllItems : function() { 68 | return $q.when(tableData); 69 | }, 70 | /** 71 | * Query expects that `limit`,`page`, and `order` fields be present 72 | */ 73 | loadByPagination: function (query) { 74 | query = query || {limit:10,page:1}; 75 | 76 | var list = []; 77 | var start = (query.page-1)*query.limit; 78 | var end = start + query.limit; 79 | for (var i = start; i < end; i++) { 80 | var f = PickRandom(); 81 | f.id = i+1; 82 | list.push(f); 83 | } 84 | return $q.when({items:list,count:800}); 85 | } 86 | }; 87 | } 88 | })(); 89 | -------------------------------------------------------------------------------- /src/app/views/profile.html: -------------------------------------------------------------------------------- 1 | 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 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 | 57 | 58 |
59 |
60 | -------------------------------------------------------------------------------- /gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')({ 8 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 9 | }); 10 | 11 | gulp.task('partials', function () { 12 | return gulp.src([ 13 | paths.src + '/{app,components}/**/*.html', 14 | paths.tmp + '/{app,components}/**/*.html' 15 | ]) 16 | .pipe($.minifyHtml({ 17 | empty: true, 18 | spare: true, 19 | quotes: true 20 | })) 21 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 22 | module: 'angularMaterialAdmin' 23 | })) 24 | .pipe(gulp.dest(paths.tmp + '/partials/')); 25 | }); 26 | 27 | gulp.task('html', ['inject', 'partials'], function () { 28 | var partialsInjectFile = gulp.src(paths.tmp + '/partials/templateCacheHtml.js', { read: false }); 29 | var partialsInjectOptions = { 30 | starttag: '', 31 | ignorePath: paths.tmp + '/partials', 32 | addRootSlash: false 33 | }; 34 | 35 | var htmlFilter = $.filter('*.html'); 36 | var jsFilter = $.filter('**/*.js'); 37 | var cssFilter = $.filter('**/*.css'); 38 | var assets; 39 | 40 | return gulp.src(paths.tmp + '/serve/*.html') 41 | .pipe($.inject(partialsInjectFile, partialsInjectOptions)) 42 | .pipe(assets = $.useref.assets()) 43 | .pipe($.rev()) 44 | .pipe(jsFilter) 45 | .pipe($.ngAnnotate()) 46 | .pipe($.uglify({preserveComments: $.uglifySaveLicense})) 47 | .pipe(jsFilter.restore()) 48 | .pipe(cssFilter) 49 | .pipe($.csso()) 50 | .pipe(cssFilter.restore()) 51 | .pipe(assets.restore()) 52 | .pipe($.useref()) 53 | .pipe($.revReplace()) 54 | .pipe(htmlFilter) 55 | .pipe($.minifyHtml({ 56 | empty: true, 57 | spare: true, 58 | quotes: true 59 | })) 60 | .pipe(htmlFilter.restore()) 61 | .pipe(gulp.dest(paths.dist + '/')) 62 | .pipe($.size({ title: paths.dist + '/', showFiles: true })); 63 | }); 64 | 65 | gulp.task('images', function () { 66 | return gulp.src(paths.src + '/assets/images/**/*') 67 | .pipe(gulp.dest(paths.dist + '/assets/images/')); 68 | }); 69 | 70 | gulp.task('fonts', function () { 71 | return gulp.src($.mainBowerFiles()) 72 | .pipe($.filter('**/*.{eot,svg,ttf,woff}')) 73 | .pipe($.flatten()) 74 | .pipe(gulp.dest(paths.dist + '/fonts/')); 75 | }); 76 | 77 | gulp.task('misc', function () { 78 | return gulp.src(paths.src + '/**/*.ico') 79 | .pipe(gulp.dest(paths.dist + '/')); 80 | }); 81 | 82 | gulp.task('clean', function (done) { 83 | $.del([paths.dist + '/', paths.tmp + '/'], done); 84 | }); 85 | 86 | gulp.task('build', ['html', 'images', 'fonts', 'misc']); 87 | -------------------------------------------------------------------------------- /src/app/controllers/MainController.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | angular 4 | .module('app') 5 | .controller('MainController', [ 6 | 'navService', '$mdSidenav', '$mdBottomSheet', '$log', '$q', '$state', '$mdToast', 7 | MainController 8 | ]); 9 | 10 | function MainController(navService, $mdSidenav, $mdBottomSheet, $log, $q, $state, $mdToast) { 11 | var vm = this; 12 | 13 | vm.menuItems = [ ]; 14 | vm.selectItem = selectItem; 15 | vm.toggleItemsList = toggleItemsList; 16 | vm.showActions = showActions; 17 | vm.title = $state.current.data.title; 18 | vm.showSimpleToast = showSimpleToast; 19 | vm.toggleRightSidebar = toggleRightSidebar; 20 | 21 | navService 22 | .loadAllItems() 23 | .then(function(menuItems) { 24 | vm.menuItems = [].concat(menuItems); 25 | }); 26 | 27 | function toggleRightSidebar() { 28 | $mdSidenav('right').toggle(); 29 | } 30 | 31 | function toggleItemsList() { 32 | var pending = $mdBottomSheet.hide() || $q.when(true); 33 | 34 | pending.then(function(){ 35 | $mdSidenav('left').toggle(); 36 | }); 37 | } 38 | 39 | function selectItem (item) { 40 | vm.title = item.name; 41 | vm.toggleItemsList(); 42 | vm.showSimpleToast(vm.title); 43 | } 44 | 45 | function showActions($event) { 46 | $mdBottomSheet.show({ 47 | parent: angular.element(document.getElementById('content')), 48 | templateUrl: 'app/views/partials/bottomSheet.html', 49 | controller: [ '$mdBottomSheet', SheetController], 50 | controllerAs: "vm", 51 | bindToController : true, 52 | targetEvent: $event 53 | }).then(function(clickedItem) { 54 | clickedItem && $log.debug( clickedItem.name + ' clicked!'); 55 | }); 56 | 57 | function SheetController( $mdBottomSheet ) { 58 | var vm = this; 59 | 60 | vm.actions = [ 61 | { name: 'Share', icon: 'share', url: 'https://twitter.com/intent/tweet?text=Angular%20Material%20Dashboard%20https://github.com/flatlogic/angular-material-dashboard%20via%20@flatlogicinc' }, 62 | { name: 'Star', icon: 'star', url: 'https://github.com/flatlogic/angular-material-dashboard/stargazers' } 63 | ]; 64 | 65 | vm.performAction = function(action) { 66 | $mdBottomSheet.hide(action); 67 | }; 68 | } 69 | } 70 | 71 | function showSimpleToast(title) { 72 | $mdToast.show( 73 | $mdToast.simple() 74 | .content(title) 75 | .hideDelay(2000) 76 | .position('bottom right') 77 | ); 78 | } 79 | } 80 | 81 | })(); 82 | -------------------------------------------------------------------------------- /src/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularMaterialAdmin', ['ngAnimate', 'ngCookies', 4 | 'ngSanitize', 'ui.router', 'ngMaterial', 'nvd3', 'app' , 'md.data.table']) 5 | 6 | .config(function ($stateProvider, $urlRouterProvider, $mdThemingProvider, 7 | $mdIconProvider) { 8 | $stateProvider 9 | .state('home', { 10 | url: '', 11 | templateUrl: 'app/views/main.html', 12 | controller: 'MainController', 13 | controllerAs: 'vm', 14 | abstract: true 15 | }) 16 | .state('home.dashboard', { 17 | url: '/dashboard', 18 | templateUrl: 'app/views/dashboard.html', 19 | data: { 20 | title: 'Dashboard' 21 | } 22 | }) 23 | .state('home.profile', { 24 | url: '/profile', 25 | templateUrl: 'app/views/profile.html', 26 | controller: 'ProfileController', 27 | controllerAs: 'vm', 28 | data: { 29 | title: 'Profile' 30 | } 31 | }) 32 | .state('home.table', { 33 | url: '/table', 34 | controller: 'TableController', 35 | controllerAs: 'vm', 36 | templateUrl: 'app/views/table.html', 37 | data: { 38 | title: 'Table' 39 | } 40 | }) 41 | .state('home.data-table', { 42 | url: '/data-table', 43 | controller: 'DataTableController', 44 | controllerAs: 'vm', 45 | templateUrl: 'app/views/data-table.html', 46 | data: { 47 | title: 'Table' 48 | } 49 | }); 50 | 51 | $urlRouterProvider.otherwise('/dashboard'); 52 | 53 | $mdThemingProvider 54 | .theme('default') 55 | .primaryPalette('grey', { 56 | 'default': '600' 57 | }) 58 | .accentPalette('teal', { 59 | 'default': '500' 60 | }) 61 | .warnPalette('defaultPrimary'); 62 | 63 | $mdThemingProvider.theme('dark', 'default') 64 | .primaryPalette('defaultPrimary') 65 | .dark(); 66 | 67 | $mdThemingProvider.theme('grey', 'default') 68 | .primaryPalette('grey'); 69 | 70 | $mdThemingProvider.theme('custom', 'default') 71 | .primaryPalette('defaultPrimary', { 72 | 'hue-1': '50' 73 | }); 74 | 75 | $mdThemingProvider.definePalette('defaultPrimary', { 76 | '50': '#FFFFFF', 77 | '100': 'rgb(255, 198, 197)', 78 | '200': '#E75753', 79 | '300': '#E75753', 80 | '400': '#E75753', 81 | '500': '#E75753', 82 | '600': '#E75753', 83 | '700': '#E75753', 84 | '800': '#E75753', 85 | '900': '#E75753', 86 | 'A100': '#E75753', 87 | 'A200': '#E75753', 88 | 'A400': '#E75753', 89 | 'A700': '#E75753' 90 | }); 91 | 92 | $mdIconProvider.icon('user', 'assets/images/user.svg', 64); 93 | }); 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Material Dashboard 2 | 3 | [![Join the chat at https://gitter.im/flatlogic/angular-material-dashboard](https://badges.gitter.im/flatlogic/angular-material-dashboard.svg)](https://gitter.im/flatlogic/angular-material-dashboard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | [View Demo](https://flatlogic.com/admin-dashboards/angular-material-dashboard/demo) | [Download](https://github.com/flatlogic/angular-material-dashboard.git) | [More templates](https://flatlogic.com/templates) | [Support forum](https://flatlogic.com/forum) 6 | 7 | The Angular Material Dashboard provides a responsive admin interface that leverages [Angular Material](https://github.com/angular/material). for its design principles. It embodies the principles of material design, ensuring a cohesive and intuitive user experience, ideal for developing sophisticated [business software](https://flatlogic.com/) dashboards. 8 | 9 | ![promo-amd](src/assets/images/promo-amd.png) 10 | 11 | ## Getting started 12 | 13 | Clone project: 14 | 15 | $ git clone https://github.com/flatlogic/angular-material-dashboard.git 16 | 17 | Install dependencies: 18 | 19 | $ cd angular-material-dashboard 20 | $ yarn install 21 | 22 | Run development web-server: 23 | 24 | $ gulp serve 25 | 26 | ## Features 27 | 28 | * AngularJS 29 | * Angular UI Router 30 | * Angular Material 31 | * Sass styles 32 | * Gulp build 33 | * Stylish, clean, responsive layout with original design 34 | * BrowserSync for the ease of development 35 | 36 | ## Project structure and credits 37 | 38 | Project structure based on [gulp-angular yeoman generator](https://github.com/Swiip/generator-gulp-angular). 39 | If you have any questions about the build or project structure please check out their documentation. 40 | 41 | UI components built with [Angular Material](https://material.angularjs.org/). 42 | 43 | Design by [flatlogic.com](http://flatlogic.com/) 44 | 45 | ## Deploy to Github pages 46 | 47 | $ gulp build 48 | $ gulp deploy 49 | 50 | ## Support 51 | For any additional information please go to our [**support forum**](https://flatlogic.com/forum) and raise your questions or feedback provide there. We highly appreciate your participation! 52 | 53 | ## Community 54 | - [Tweet about it](https://twitter.com/intent/tweet?text=Angular%20Material%20Dashboard%20https://github.com/flatlogic/angular-material-dashboard%20via%20@flatlogicinc) to support revolution in classic paid templates market. 55 | - Follow [@flatlogicinc on Twitter](https://twitter.com/flatlogicinc). 56 | - Subscribe to Flatlogic newsletter at [flatlogic.com](http://flatlogic.com/) 57 | 58 | ## More from Flatlogic 59 | - [💥Sing App Dashboard](https://github.com/flatlogic/sing-app) - Free and open-source admin dashboard template built with Bootstrap 4 60 | - [React Native Starter](https://github.com/flatlogic/react-native-starter) - 🚀 A powerful react native starter template that bootstraps development of your mobile application 61 | 62 | ## Premium themes 63 | Looking for premium themes and templates? Check out our other template at [flatlogic.com](https://flatlogic.com/templates). 64 | -------------------------------------------------------------------------------- /src/app/stylesheets/_custom.scss: -------------------------------------------------------------------------------- 1 | // COLORS 2 | $main-bg-color: #ECECEC; 3 | $text-color: #7A7A7A; 4 | $accent-color: rgb(0, 150, 136); 5 | $warning-color: #E75753; 6 | 7 | 8 | // VARIABLES 9 | $left-sidenav-width: 110px; 10 | $widget-height: 310px; 11 | $font-weight-bold: 600; 12 | $font-size-large: 22px; 13 | 14 | 15 | // LAYOUT 16 | body { 17 | color: $text-color; 18 | } 19 | 20 | .toolbar-button { 21 | min-width: 20px; 22 | } 23 | 24 | .share-label { 25 | vert-align: middle; 26 | margin-left: 10px; 27 | } 28 | 29 | .page-content { 30 | background-color: $main-bg-color; 31 | } 32 | 33 | .widget-progress { 34 | width: 95% !important; 35 | margin-left: 10px; 36 | } 37 | 38 | 39 | // UTILS 40 | .capitalize { 41 | text-transform: capitalize; 42 | } 43 | 44 | .img-circle { 45 | height: 50px; 46 | border-radius: 50%; 47 | margin: 0 10px; 48 | } 49 | 50 | 51 | // COMPONENTS 52 | .messages { 53 | position: relative; 54 | 55 | &-content { 56 | height: 100vh; 57 | } 58 | } 59 | 60 | .notifications-label { 61 | width: 16px; 62 | height: 16px; 63 | line-height: 16px; 64 | text-align: center; 65 | border-radius: 50%; 66 | position: absolute; 67 | font-size: 12px; 68 | top: 2px; 69 | right: 2px; 70 | background-color: $warning-color; 71 | } 72 | 73 | // panel-widget 74 | .panel-widget { 75 | background-color: white; 76 | 77 | &-toolbar { 78 | box-shadow: none; 79 | margin: 0; 80 | } 81 | 82 | &-tittle { 83 | color: $text-color; 84 | } 85 | } 86 | 87 | .options { 88 | -webkit-transition:all linear 0.5s; 89 | transition:all linear 0.5s; 90 | } 91 | 92 | .options.ng-hide { 93 | opacity:0; 94 | } 95 | 96 | .fixed-height-widget { 97 | height: $widget-height; 98 | } 99 | 100 | // charts 101 | .donut-chart-title{ 102 | text-align: center; 103 | } 104 | 105 | .custom-tooltip { 106 | font-size: $font-size-large; 107 | color: $text-color; 108 | text-align: center; 109 | } 110 | 111 | 112 | // OVERRIDES 113 | // angular material overrides 114 | md-radio-group { 115 | border: none; 116 | } 117 | 118 | md-icon { 119 | height: auto; 120 | } 121 | 122 | md-sidenav.md-locked-open.md-sidenav-left { 123 | width: $left-sidenav-width; 124 | min-width: $left-sidenav-width; 125 | max-width: $left-sidenav-width; 126 | } 127 | 128 | a.md-button.md-warn.md-raised, a.md-button.md-warn.md-fab, .md-button.md-warn.md-raised, .md-button.md-warn.md-fab { 129 | color: white; 130 | } 131 | 132 | md-radio-button.md-accent.md-checked .md-label span { 133 | color: $accent-color; 134 | } 135 | 136 | .md-toolbar-tools h1 { 137 | font-size: $font-size-large; 138 | } 139 | 140 | 141 | md-backdrop.md-sidenav-backdrop { 142 | position: fixed; 143 | } 144 | 145 | // libs overrides 146 | .material-icons { 147 | vertical-align: middle; 148 | } 149 | 150 | .material-icons.md-18 { font-size: 18px; } 151 | .material-icons.md-24 { font-size: 24px; } 152 | .material-icons.md-36 { font-size: 36px; } 153 | .material-icons.md-48 { font-size: 48px; } 154 | 155 | .nvd3.nv-pie .nv-pie-title { 156 | fill: rgb(68, 68, 68); 157 | font-weight: $font-weight-bold; 158 | font-size: $font-size-large !important; 159 | } 160 | 161 | .nvtooltip { 162 | background-color: transparent; 163 | border: none; 164 | font-weight: $font-weight-bold; 165 | } 166 | 167 | .orange .md-bar2 { 168 | background-color: orange; 169 | } 170 | 171 | .orange .md-container { 172 | background-color: rgb(255, 236, 201) 173 | } -------------------------------------------------------------------------------- /src/app/views/main.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 |

AMD

7 |
8 |
9 | 12 |
13 | {{item.icon}} 14 |
15 |
16 | {{item.name}} 17 |
18 |
19 | 20 | 21 |
22 | Actions 23 |
24 |
25 |
26 | 27 |
28 | 29 |
30 | 31 | menu 32 | 33 |
34 |
35 | 36 | search 37 | 38 | 39 | notifications 40 | 7 41 | 42 | 43 | menu 44 | 45 |
46 |
47 | 48 | 49 |
50 |
51 |
52 | 53 | 55 | 56 | 57 | 58 | 59 | 60 | Richard Feynman 61 | keyboard_arrow_down 62 | 63 | 64 | Profile 65 | Log out 66 | 67 | 68 | 69 | 70 | 71 |
72 | 73 |
74 |

Messages

75 |
76 |
77 |
78 |
79 |
80 | -------------------------------------------------------------------------------- /src/app/components/services/PerformanceService.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('app') 5 | .service('performanceService', [ 6 | performanceService 7 | ]); 8 | 9 | function performanceService() { 10 | 11 | var service = { 12 | getPerformanceData: getPerformanceData 13 | }; 14 | 15 | return service; 16 | 17 | function getPerformanceData(performancePeriod) { 18 | if (performancePeriod === 'week') { 19 | return [ 20 | { 21 | "key": 'Middleware', 22 | "values": [[1, 11], [2, 10], [3, 14], [4, 21], [5, 13], [6, 21], [7, 21], [8, 18], [9, 11], [10, 11], [11, 18], [12, 14], [13, 10], [14, 20], [15, 21], [16, 28], [17, 12], [18, 16], [19, 22], [20, 18], [21, 21], [22, 10], [23, 11], [24, 14], [25, 9], [26, 14], [27, 10], [28, 21], [29, 11]] 23 | }, 24 | 25 | { 26 | "key": 'Ruby', 27 | "values": [[1, 29], [2, 36], [3, 42], [4, 25], [5, 22], [6, 34], [7, 41], [8, 19], [9, 45], [10, 31], [11, 28], [12, 36], [13, 54], [14, 41], [15, 36], [16, 39], [17, 21], [18, 20], [19, 22], [20, 44], [21, 32], [22, 20], [23, 28], [24, 24], [25, 29], [26, 19], [27, 20], [28, 31], [29, 49]] 28 | }, 29 | 30 | { 31 | "key": 'Web External', 32 | "values": [[1, 54], [2, 74], [3, 64], [4, 68], [5, 56], [6, 44], [7, 61], [8, 63], [9, 45], [10, 51], [11, 68], [12, 46], [13, 64], [14, 51], [15, 42], [16, 63], [17, 72], [18, 60], [19, 52], [20, 58], [21, 41], [22, 40], [23, 58], [24, 30], [25, 49], [26, 54], [27, 60], [28, 41], [29, 66]] 33 | }, 34 | { 35 | "key": 'Database', 36 | "values": [[1, 64], [2, 84], [3, 64], [4, 68], [5, 86], [6, 74], [7, 81], [8, 83], [9, 65], [10, 61], [11, 88], [12, 76], [13, 84], [14, 71], [15, 82], [16, 73], [17, 92], [18, 80], [19, 62], [20, 68], [21, 71], [22, 50], [23, 78], [24, 60], [25, 59], [26, 74], [27, 80], [28, 51], [29, 97]] 37 | } 38 | ] 39 | } else { 40 | return [ 41 | { 42 | "key": 'Middleware', 43 | "values": [[1, 13], [2, 14], [3, 24], [4, 18], [5, 16], [6, 14], [7, 11], [8, 13], [9, 15], [10, 11], [11, 18], [12, 16], [13, 28], [14, 11], [15, 12], [16, 13], [17, 12], [18, 20], [19, 22], [20, 18], [21, 11], [22, 10], [23, 18], [24, 20], [25, 9], [26, 14], [27, 10], [28, 11], [29, 17]] 44 | }, 45 | 46 | { 47 | "key": 'Ruby', 48 | "values": [[1, 29], [2, 36], [3, 42], [4, 25], [5, 22], [6, 34], [7, 41], [8, 19], [9, 45], [10, 31], [11, 28], [12, 36], [13, 54], [14, 41], [15, 36], [16, 39], [17, 21], [18, 20], [19, 22], [20, 44], [21, 32], [22, 20], [23, 28], [24, 24], [25, 29], [26, 19], [27, 20], [28, 31], [29, 49]] 49 | }, 50 | 51 | { 52 | "key": 'Web External', 53 | "values": [[1, 54], [2, 74], [3, 64], [4, 68], [5, 56], [6, 44], [7, 61], [8, 63], [9, 45], [10, 51], [11, 68], [12, 46], [13, 64], [14, 51], [15, 42], [16, 63], [17, 72], [18, 60], [19, 52], [20, 58], [21, 41], [22, 40], [23, 58], [24, 30], [25, 49], [26, 54], [27, 60], [28, 41], [29, 66]] 54 | }, 55 | { 56 | "key": 'Database', 57 | "values": [[1, 74], [2, 64], [3, 84], [4, 78], [5, 66], [6, 64], [7, 71], [8, 83], [9, 55], [10, 81], [11, 88], [12, 76], [13, 84], [14, 71], [15, 62], [16, 73], [17, 82], [18, 80], [19, 92], [20, 68], [21, 71], [22, 70], [23, 78], [24, 80], [25, 59], [26, 74], [27, 80], [28, 51], [29, 67]] 58 | } 59 | ] 60 | } 61 | } 62 | } 63 | })(); 64 | -------------------------------------------------------------------------------- /src/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 | 151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /src/app/stylesheets/_table.scss: -------------------------------------------------------------------------------- 1 | // This file based on http://codepen.io/zavoloklom/pen/IGkDz 2 | 3 | // VARIABLES 4 | $table-header-font-weight: 400; 5 | $table-header-font-color: #757575; 6 | 7 | $table-cell-padding: 1.2rem; 8 | 9 | $table-bg: #fff; 10 | $table-bg-accent: #f5f5f5; 11 | $table-bg-hover: rgba(0,0,0,.12); 12 | $table-bg-active: $table-bg-hover; 13 | $table-border-color: #e0e0e0; 14 | 15 | 16 | // MIXINS 17 | @mixin transition($transition-property, $transition-time, $method) { 18 | -webkit-transition: $transition-property $transition-time $method; 19 | -moz-transition: $transition-property $transition-time $method; 20 | -ms-transition: $transition-property $transition-time $method; 21 | -o-transition: $transition-property $transition-time $method; 22 | transition: $transition-property $transition-time $method; 23 | } 24 | 25 | 26 | //TABLES 27 | .table { 28 | border-spacing: 0; 29 | width: 100%; 30 | max-width: 100%; 31 | margin-bottom: 2rem; 32 | background-color: $table-bg; 33 | > thead, 34 | > tbody, 35 | > tfoot { 36 | > tr { 37 | @include transition(all, 0.3s, ease); 38 | > th, 39 | > td { 40 | text-align: left; 41 | padding: $table-cell-padding; 42 | vertical-align: top; 43 | border-top: 0; 44 | @include transition(all, 0.3s, ease); 45 | } 46 | } 47 | } 48 | > thead > tr > th { 49 | font-weight: $table-header-font-weight; 50 | color: $table-header-font-color; 51 | vertical-align: bottom; 52 | border-bottom: 1px solid rgba(0,0,0,.12); 53 | } 54 | > caption + thead, 55 | > colgroup + thead, 56 | > thead:first-child { 57 | > tr:first-child { 58 | > th, 59 | > td { 60 | border-top: 0; 61 | } 62 | } 63 | } 64 | > tbody + tbody { 65 | border-top: 1px solid rgba(0,0,0,.12); 66 | } 67 | 68 | // Nesting 69 | .table { 70 | background-color: $table-bg; 71 | } 72 | 73 | // Remove border 74 | .no-border { 75 | border: 0; 76 | } 77 | } 78 | 79 | // Bordered version 80 | // 81 | // Add horizontal borders between columns. 82 | .table-bordered { 83 | border: 0; 84 | > thead, 85 | > tbody, 86 | > tfoot { 87 | > tr { 88 | > th, 89 | > td { 90 | border: 0; 91 | border-bottom: 1px solid $table-border-color; 92 | } 93 | } 94 | } 95 | > thead > tr { 96 | > th, 97 | > td { 98 | border-bottom-width: 2px; 99 | } 100 | } 101 | } 102 | 103 | 104 | // Hover effect 105 | // 106 | .table-hover { 107 | > tbody > tr:hover { 108 | > td, 109 | > th { 110 | background-color: $table-bg-hover; 111 | } 112 | } 113 | } 114 | 115 | // Responsive tables (vertical) 116 | // 117 | // Wrap your tables in `.table-responsive-vertical` and we'll make them mobile friendly 118 | // by vertical table-cell display. Only applies <768px. Everything above that will display normally. 119 | // For correct display you must add 'data-title' to each 'td' 120 | .table-responsive-vertical { 121 | 122 | @media screen and (max-width: 768px) { 123 | 124 | // Tighten up spacing 125 | > .table { 126 | margin-bottom: 0; 127 | background-color: transparent; 128 | > thead, 129 | > tfoot { 130 | display: none; 131 | } 132 | 133 | > tbody { 134 | display: block; 135 | 136 | > tr { 137 | display: block; 138 | border: 1px solid $table-border-color; 139 | border-radius: 2px; 140 | margin-bottom: $table-cell-padding; 141 | 142 | > td { 143 | background-color: $table-bg; 144 | display: block; 145 | vertical-align: middle; 146 | text-align: right; 147 | } 148 | > td[data-title]:before { 149 | content: attr(data-title); 150 | float: left; 151 | font-size: inherit; 152 | font-weight: $table-header-font-weight; 153 | color: $table-header-font-color; 154 | padding-right: 10px; 155 | } 156 | } 157 | } 158 | } 159 | 160 | // Special overrides for shadows 161 | &.shadow-z-1 { 162 | -webkit-box-shadow: none; 163 | -moz-box-shadow: none; 164 | box-shadow: none; 165 | > .table > tbody > tr { 166 | border: none; 167 | } 168 | } 169 | 170 | // Special overrides for the bordered tables 171 | > .table-bordered { 172 | border: 0; 173 | 174 | // Nuke the appropriate borders so that the parent can handle them 175 | > tbody { 176 | > tr { 177 | > td { 178 | border: 0; 179 | border-bottom: 1px solid $table-border-color; 180 | } 181 | > td:last-child { 182 | border-bottom: 0; 183 | } 184 | } 185 | } 186 | } 187 | 188 | // Special overrides for the striped tables 189 | > .table-striped { 190 | > tbody > tr > td, 191 | > tbody > tr:nth-child(odd) { 192 | background-color: $table-bg; 193 | } 194 | > tbody > tr > td:nth-child(odd) { 195 | background-color: $table-bg-accent; 196 | } 197 | } 198 | 199 | // Special overrides for hover tables 200 | > .table-hover { 201 | > tbody { 202 | > tr:hover > td, 203 | > tr:hover { 204 | background-color: $table-bg; 205 | } 206 | > tr > td:hover { 207 | background-color: $table-bg-hover; 208 | } 209 | } 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/app/components/services/CountriesService.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('app') 5 | .service('countriesService', [ 6 | countriesService 7 | ]); 8 | 9 | function countriesService(){ 10 | var allCountries = [ 11 | {name: 'Afghanistan', code: 'AF'}, 12 | {name: 'Åland Islands', code: 'AX'}, 13 | {name: 'Albania', code: 'AL'}, 14 | {name: 'Algeria', code: 'DZ'}, 15 | {name: 'American Samoa', code: 'AS'}, 16 | {name: 'AndorrA', code: 'AD'}, 17 | {name: 'Angola', code: 'AO'}, 18 | {name: 'Anguilla', code: 'AI'}, 19 | {name: 'Antarctica', code: 'AQ'}, 20 | {name: 'Antigua and Barbuda', code: 'AG'}, 21 | {name: 'Argentina', code: 'AR'}, 22 | {name: 'Armenia', code: 'AM'}, 23 | {name: 'Aruba', code: 'AW'}, 24 | {name: 'Australia', code: 'AU'}, 25 | {name: 'Austria', code: 'AT'}, 26 | {name: 'Azerbaijan', code: 'AZ'}, 27 | {name: 'Bahamas', code: 'BS'}, 28 | {name: 'Bahrain', code: 'BH'}, 29 | {name: 'Bangladesh', code: 'BD'}, 30 | {name: 'Barbados', code: 'BB'}, 31 | {name: 'Belarus', code: 'BY'}, 32 | {name: 'Belgium', code: 'BE'}, 33 | {name: 'Belize', code: 'BZ'}, 34 | {name: 'Benin', code: 'BJ'}, 35 | {name: 'Bermuda', code: 'BM'}, 36 | {name: 'Bhutan', code: 'BT'}, 37 | {name: 'Bolivia', code: 'BO'}, 38 | {name: 'Bosnia and Herzegovina', code: 'BA'}, 39 | {name: 'Botswana', code: 'BW'}, 40 | {name: 'Bouvet Island', code: 'BV'}, 41 | {name: 'Brazil', code: 'BR'}, 42 | {name: 'British Indian Ocean Territory', code: 'IO'}, 43 | {name: 'Brunei Darussalam', code: 'BN'}, 44 | {name: 'Bulgaria', code: 'BG'}, 45 | {name: 'Burkina Faso', code: 'BF'}, 46 | {name: 'Burundi', code: 'BI'}, 47 | {name: 'Cambodia', code: 'KH'}, 48 | {name: 'Cameroon', code: 'CM'}, 49 | {name: 'Canada', code: 'CA'}, 50 | {name: 'Cape Verde', code: 'CV'}, 51 | {name: 'Cayman Islands', code: 'KY'}, 52 | {name: 'Central African Republic', code: 'CF'}, 53 | {name: 'Chad', code: 'TD'}, 54 | {name: 'Chile', code: 'CL'}, 55 | {name: 'China', code: 'CN'}, 56 | {name: 'Christmas Island', code: 'CX'}, 57 | {name: 'Cocos (Keeling) Islands', code: 'CC'}, 58 | {name: 'Colombia', code: 'CO'}, 59 | {name: 'Comoros', code: 'KM'}, 60 | {name: 'Congo', code: 'CG'}, 61 | {name: 'Congo, The Democratic Republic of the', code: 'CD'}, 62 | {name: 'Cook Islands', code: 'CK'}, 63 | {name: 'Costa Rica', code: 'CR'}, 64 | {name: 'Cote D\'Ivoire', code: 'CI'}, 65 | {name: 'Croatia', code: 'HR'}, 66 | {name: 'Cuba', code: 'CU'}, 67 | {name: 'Cyprus', code: 'CY'}, 68 | {name: 'Czech Republic', code: 'CZ'}, 69 | {name: 'Denmark', code: 'DK'}, 70 | {name: 'Djibouti', code: 'DJ'}, 71 | {name: 'Dominica', code: 'DM'}, 72 | {name: 'Dominican Republic', code: 'DO'}, 73 | {name: 'Ecuador', code: 'EC'}, 74 | {name: 'Egypt', code: 'EG'}, 75 | {name: 'El Salvador', code: 'SV'}, 76 | {name: 'Equatorial Guinea', code: 'GQ'}, 77 | {name: 'Eritrea', code: 'ER'}, 78 | {name: 'Estonia', code: 'EE'}, 79 | {name: 'Ethiopia', code: 'ET'}, 80 | {name: 'Falkland Islands (Malvinas)', code: 'FK'}, 81 | {name: 'Faroe Islands', code: 'FO'}, 82 | {name: 'Fiji', code: 'FJ'}, 83 | {name: 'Finland', code: 'FI'}, 84 | {name: 'France', code: 'FR'}, 85 | {name: 'French Guiana', code: 'GF'}, 86 | {name: 'French Polynesia', code: 'PF'}, 87 | {name: 'French Southern Territories', code: 'TF'}, 88 | {name: 'Gabon', code: 'GA'}, 89 | {name: 'Gambia', code: 'GM'}, 90 | {name: 'Georgia', code: 'GE'}, 91 | {name: 'Germany', code: 'DE'}, 92 | {name: 'Ghana', code: 'GH'}, 93 | {name: 'Gibraltar', code: 'GI'}, 94 | {name: 'Greece', code: 'GR'}, 95 | {name: 'Greenland', code: 'GL'}, 96 | {name: 'Grenada', code: 'GD'}, 97 | {name: 'Guadeloupe', code: 'GP'}, 98 | {name: 'Guam', code: 'GU'}, 99 | {name: 'Guatemala', code: 'GT'}, 100 | {name: 'Guernsey', code: 'GG'}, 101 | {name: 'Guinea', code: 'GN'}, 102 | {name: 'Guinea-Bissau', code: 'GW'}, 103 | {name: 'Guyana', code: 'GY'}, 104 | {name: 'Haiti', code: 'HT'}, 105 | {name: 'Heard Island and Mcdonald Islands', code: 'HM'}, 106 | {name: 'Holy See (Vatican City State)', code: 'VA'}, 107 | {name: 'Honduras', code: 'HN'}, 108 | {name: 'Hong Kong', code: 'HK'}, 109 | {name: 'Hungary', code: 'HU'}, 110 | {name: 'Iceland', code: 'IS'}, 111 | {name: 'India', code: 'IN'}, 112 | {name: 'Indonesia', code: 'ID'}, 113 | {name: 'Iran, Islamic Republic Of', code: 'IR'}, 114 | {name: 'Iraq', code: 'IQ'}, 115 | {name: 'Ireland', code: 'IE'}, 116 | {name: 'Isle of Man', code: 'IM'}, 117 | {name: 'Israel', code: 'IL'}, 118 | {name: 'Italy', code: 'IT'}, 119 | {name: 'Jamaica', code: 'JM'}, 120 | {name: 'Japan', code: 'JP'}, 121 | {name: 'Jersey', code: 'JE'}, 122 | {name: 'Jordan', code: 'JO'}, 123 | {name: 'Kazakhstan', code: 'KZ'}, 124 | {name: 'Kenya', code: 'KE'}, 125 | {name: 'Kiribati', code: 'KI'}, 126 | {name: 'Korea, Democratic People\'S Republic of', code: 'KP'}, 127 | {name: 'Korea, Republic of', code: 'KR'}, 128 | {name: 'Kuwait', code: 'KW'}, 129 | {name: 'Kyrgyzstan', code: 'KG'}, 130 | {name: 'Lao People\'S Democratic Republic', code: 'LA'}, 131 | {name: 'Latvia', code: 'LV'}, 132 | {name: 'Lebanon', code: 'LB'}, 133 | {name: 'Lesotho', code: 'LS'}, 134 | {name: 'Liberia', code: 'LR'}, 135 | {name: 'Libyan Arab Jamahiriya', code: 'LY'}, 136 | {name: 'Liechtenstein', code: 'LI'}, 137 | {name: 'Lithuania', code: 'LT'}, 138 | {name: 'Luxembourg', code: 'LU'}, 139 | {name: 'Macao', code: 'MO'}, 140 | {name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK'}, 141 | {name: 'Madagascar', code: 'MG'}, 142 | {name: 'Malawi', code: 'MW'}, 143 | {name: 'Malaysia', code: 'MY'}, 144 | {name: 'Maldives', code: 'MV'}, 145 | {name: 'Mali', code: 'ML'}, 146 | {name: 'Malta', code: 'MT'}, 147 | {name: 'Marshall Islands', code: 'MH'}, 148 | {name: 'Martinique', code: 'MQ'}, 149 | {name: 'Mauritania', code: 'MR'}, 150 | {name: 'Mauritius', code: 'MU'}, 151 | {name: 'Mayotte', code: 'YT'}, 152 | {name: 'Mexico', code: 'MX'}, 153 | {name: 'Micronesia, Federated States of', code: 'FM'}, 154 | {name: 'Moldova, Republic of', code: 'MD'}, 155 | {name: 'Monaco', code: 'MC'}, 156 | {name: 'Mongolia', code: 'MN'}, 157 | {name: 'Montserrat', code: 'MS'}, 158 | {name: 'Morocco', code: 'MA'}, 159 | {name: 'Mozambique', code: 'MZ'}, 160 | {name: 'Myanmar', code: 'MM'}, 161 | {name: 'Namibia', code: 'NA'}, 162 | {name: 'Nauru', code: 'NR'}, 163 | {name: 'Nepal', code: 'NP'}, 164 | {name: 'Netherlands', code: 'NL'}, 165 | {name: 'Netherlands Antilles', code: 'AN'}, 166 | {name: 'New Caledonia', code: 'NC'}, 167 | {name: 'New Zealand', code: 'NZ'}, 168 | {name: 'Nicaragua', code: 'NI'}, 169 | {name: 'Niger', code: 'NE'}, 170 | {name: 'Nigeria', code: 'NG'}, 171 | {name: 'Niue', code: 'NU'}, 172 | {name: 'Norfolk Island', code: 'NF'}, 173 | {name: 'Northern Mariana Islands', code: 'MP'}, 174 | {name: 'Norway', code: 'NO'}, 175 | {name: 'Oman', code: 'OM'}, 176 | {name: 'Pakistan', code: 'PK'}, 177 | {name: 'Palau', code: 'PW'}, 178 | {name: 'Palestinian Territory, Occupied', code: 'PS'}, 179 | {name: 'Panama', code: 'PA'}, 180 | {name: 'Papua New Guinea', code: 'PG'}, 181 | {name: 'Paraguay', code: 'PY'}, 182 | {name: 'Peru', code: 'PE'}, 183 | {name: 'Philippines', code: 'PH'}, 184 | {name: 'Pitcairn', code: 'PN'}, 185 | {name: 'Poland', code: 'PL'}, 186 | {name: 'Portugal', code: 'PT'}, 187 | {name: 'Puerto Rico', code: 'PR'}, 188 | {name: 'Qatar', code: 'QA'}, 189 | {name: 'Reunion', code: 'RE'}, 190 | {name: 'Romania', code: 'RO'}, 191 | {name: 'Russian Federation', code: 'RU'}, 192 | {name: 'RWANDA', code: 'RW'}, 193 | {name: 'Saint Helena', code: 'SH'}, 194 | {name: 'Saint Kitts and Nevis', code: 'KN'}, 195 | {name: 'Saint Lucia', code: 'LC'}, 196 | {name: 'Saint Pierre and Miquelon', code: 'PM'}, 197 | {name: 'Saint Vincent and the Grenadines', code: 'VC'}, 198 | {name: 'Samoa', code: 'WS'}, 199 | {name: 'San Marino', code: 'SM'}, 200 | {name: 'Sao Tome and Principe', code: 'ST'}, 201 | {name: 'Saudi Arabia', code: 'SA'}, 202 | {name: 'Senegal', code: 'SN'}, 203 | {name: 'Serbia and Montenegro', code: 'CS'}, 204 | {name: 'Seychelles', code: 'SC'}, 205 | {name: 'Sierra Leone', code: 'SL'}, 206 | {name: 'Singapore', code: 'SG'}, 207 | {name: 'Slovakia', code: 'SK'}, 208 | {name: 'Slovenia', code: 'SI'}, 209 | {name: 'Solomon Islands', code: 'SB'}, 210 | {name: 'Somalia', code: 'SO'}, 211 | {name: 'South Africa', code: 'ZA'}, 212 | {name: 'South Georgia and the South Sandwich Islands', code: 'GS'}, 213 | {name: 'Spain', code: 'ES'}, 214 | {name: 'Sri Lanka', code: 'LK'}, 215 | {name: 'Sudan', code: 'SD'}, 216 | {name: 'Suriname', code: 'SR'}, 217 | {name: 'Svalbard and Jan Mayen', code: 'SJ'}, 218 | {name: 'Swaziland', code: 'SZ'}, 219 | {name: 'Sweden', code: 'SE'}, 220 | {name: 'Switzerland', code: 'CH'}, 221 | {name: 'Syrian Arab Republic', code: 'SY'}, 222 | {name: 'Taiwan, Province of China', code: 'TW'}, 223 | {name: 'Tajikistan', code: 'TJ'}, 224 | {name: 'Tanzania, United Republic of', code: 'TZ'}, 225 | {name: 'Thailand', code: 'TH'}, 226 | {name: 'Timor-Leste', code: 'TL'}, 227 | {name: 'Togo', code: 'TG'}, 228 | {name: 'Tokelau', code: 'TK'}, 229 | {name: 'Tonga', code: 'TO'}, 230 | {name: 'Trinidad and Tobago', code: 'TT'}, 231 | {name: 'Tunisia', code: 'TN'}, 232 | {name: 'Turkey', code: 'TR'}, 233 | {name: 'Turkmenistan', code: 'TM'}, 234 | {name: 'Turks and Caicos Islands', code: 'TC'}, 235 | {name: 'Tuvalu', code: 'TV'}, 236 | {name: 'Uganda', code: 'UG'}, 237 | {name: 'Ukraine', code: 'UA'}, 238 | {name: 'United Arab Emirates', code: 'AE'}, 239 | {name: 'United Kingdom', code: 'GB'}, 240 | {name: 'United States', code: 'US'}, 241 | {name: 'United States Minor Outlying Islands', code: 'UM'}, 242 | {name: 'Uruguay', code: 'UY'}, 243 | {name: 'Uzbekistan', code: 'UZ'}, 244 | {name: 'Vanuatu', code: 'VU'}, 245 | {name: 'Venezuela', code: 'VE'}, 246 | {name: 'Viet Nam', code: 'VN'}, 247 | {name: 'Virgin Islands, British', code: 'VG'}, 248 | {name: 'Virgin Islands, U.S.', code: 'VI'}, 249 | {name: 'Wallis and Futuna', code: 'WF'}, 250 | {name: 'Western Sahara', code: 'EH'}, 251 | {name: 'Yemen', code: 'YE'}, 252 | {name: 'Zambia', code: 'ZM'}, 253 | {name: 'Zimbabwe', code: 'ZW'} 254 | ]; 255 | 256 | return { 257 | loadAll : function() { 258 | return allCountries.map(function(country) { 259 | return { 260 | value: country.name.toLowerCase(), 261 | display: country.name, 262 | code: country.code 263 | }; 264 | }); 265 | } 266 | }; 267 | } 268 | 269 | })(); 270 | --------------------------------------------------------------------------------