├── .gitattributes
├── app
├── .buildignore
├── robots.txt
├── styles
│ ├── nv.d3.less
│ ├── widgets.less
│ ├── main.less
│ ├── bootstrap.less
│ └── themes
│ │ ├── cyborg.less
│ │ ├── default.less
│ │ ├── simplex.less
│ │ └── amelia.less
├── favicon.ico
├── images
│ ├── main_banner.png
│ ├── glyphicons-halflings.png
│ └── glyphicons-halflings-white.png
├── template
│ ├── percentage.html
│ ├── topics.html
│ └── widgetOptions.html
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── views
│ ├── main.html
│ ├── simple.html
│ └── apps.html
├── settings.js
├── scripts
│ ├── controllers
│ │ ├── simple.js
│ │ ├── meteor.js
│ │ ├── topics.js
│ │ ├── widgetOptions.js
│ │ ├── apps.js
│ │ ├── serverdata.js
│ │ ├── rest.js
│ │ ├── main.js
│ │ └── discovery.js
│ ├── app.js
│ ├── services
│ │ ├── gateway.js
│ │ ├── widgets.js
│ │ ├── service.js
│ │ └── datamodel.js
│ └── vendor
│ │ ├── visibly.js
│ │ └── meteor-ddp.js
├── index.html
└── 404.html
├── start_dist.sh
├── start_dev.sh
├── dist
├── robots.txt
├── favicon.ico
├── images
│ ├── 570fe1a1.main_banner.png
│ ├── 5aa9bc32.glyphicons-halflings.png
│ └── 0220d123.glyphicons-halflings-white.png
├── template
│ ├── percentage.html
│ ├── topics.html
│ └── widgetOptions.html
├── views
│ ├── main.html
│ └── apps.html
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── settings.js
├── index.html
└── 404.html
├── .bowerrc
├── forever_dev.js
├── .gitignore
├── docs
├── AngularJSDashboard.png
└── ProjectDependencies.png
├── dev_start.sh
├── .travis.yml
├── test
├── runner.html
├── spec
│ └── controllers
│ │ └── main.js
└── .jshintrc
├── .editorconfig
├── .jshintrc
├── config.js
├── app.js
├── bower.json
├── CONTRIBUTING.md
├── karma-e2e.conf.js
├── package.json
├── karma.conf.js
├── README.md
├── Gruntfile.js
└── LICENSE
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/app/.buildignore:
--------------------------------------------------------------------------------
1 | *.coffee
--------------------------------------------------------------------------------
/start_dist.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | node app.js
--------------------------------------------------------------------------------
/start_dev.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | STATIC_DIR=/app node app.js
--------------------------------------------------------------------------------
/app/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/dist/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "app/bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/forever_dev.js:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | export STATIC_DIR=/app
3 | forever start app.js
--------------------------------------------------------------------------------
/app/styles/nv.d3.less:
--------------------------------------------------------------------------------
1 | svg {
2 | width: auto;
3 | height: auto;
4 | }
5 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/favicon.ico
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .tmp
3 | .sass-cache
4 | .idea
5 | .DS_Store
6 | app/bower_components
7 |
--------------------------------------------------------------------------------
/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/favicon.ico
--------------------------------------------------------------------------------
/app/images/main_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/images/main_banner.png
--------------------------------------------------------------------------------
/docs/AngularJSDashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/docs/AngularJSDashboard.png
--------------------------------------------------------------------------------
/docs/ProjectDependencies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/docs/ProjectDependencies.png
--------------------------------------------------------------------------------
/app/images/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/images/glyphicons-halflings.png
--------------------------------------------------------------------------------
/app/template/percentage.html:
--------------------------------------------------------------------------------
1 |
2 | Template from templateUrl
3 |
{{percentage}}
4 |
--------------------------------------------------------------------------------
/dev_start.sh:
--------------------------------------------------------------------------------
1 | export PORT=3005
2 | export STATIC_DIR=/app
3 | export GATEWAY_HOST=localhost:3390
4 |
5 | #forever start app.js
6 | node app.js
--------------------------------------------------------------------------------
/dist/images/570fe1a1.main_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/images/570fe1a1.main_banner.png
--------------------------------------------------------------------------------
/dist/template/percentage.html:
--------------------------------------------------------------------------------
1 |
2 | Template from templateUrl
3 |
{{percentage}}
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.10'
4 | before_script:
5 | - 'npm install -g bower grunt-cli'
6 | - 'bower install'
7 |
--------------------------------------------------------------------------------
/dist/views/main.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/app/images/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/images/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/app/views/main.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/app/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/dist/images/5aa9bc32.glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/images/5aa9bc32.glyphicons-halflings.png
--------------------------------------------------------------------------------
/dist/images/0220d123.glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dtpublic/malhar-dashboard-webapp/HEAD/dist/images/0220d123.glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/app/styles/widgets.less:
--------------------------------------------------------------------------------
1 | .widget {
2 | .alert {
3 | margin: 0;
4 | }
5 |
6 | .top-n .grid {
7 | width: 100%;
8 | height: 350px;
9 | border: 1px solid rgb(212, 212, 212);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/views/simple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Option Selected: {{value}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/views/apps.html:
--------------------------------------------------------------------------------
1 |
2 |
Select Application to Load
3 |
Loading Applications...
4 |
5 |
6 |
--------------------------------------------------------------------------------
/dist/views/apps.html:
--------------------------------------------------------------------------------
1 |
2 |
Select Application to Load
3 |
Loading Applications...
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/runner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | End2end Test Runner
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true,
21 | "globals": {
22 | "angular": false,
23 | "jQuery": false,
24 | "_": false,
25 | "d3": false
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/test/spec/controllers/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: MainCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('app'));
7 |
8 | var MainCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | MainCtrl = $controller('MainCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should be defined', function () {
20 | expect(MainCtrl).toBeDefined();
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true,
21 | "globals": {
22 | "after": false,
23 | "afterEach": false,
24 | "angular": false,
25 | "before": false,
26 | "beforeEach": false,
27 | "browser": false,
28 | "describe": false,
29 | "expect": false,
30 | "inject": false,
31 | "it": false,
32 | "spyOn": false
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/app/settings.js:
--------------------------------------------------------------------------------
1 | // client-side settings (for dev only)
2 | window.settings = {};
3 |
4 | settings.gatewayHost = 'localhost:9090';
5 | settings.meteorHost = 'localhost:5000';
6 |
7 | settings.webSocketURL = 'ws://' + settings.gatewayHost + '/pubsub';
8 | settings.restBaseURL = 'http://' + settings.gatewayHost + '/ws/v1/';
9 | settings.meteorURL = 'ws://' + settings.meteorHost + '/websocket';
10 |
11 | settings.topic = {};
12 | settings.topic.visualdata = {};
13 |
14 | settings.topic.visualdata.piValue = 'piValue';
15 | settings.topic.visualdata.percentage = 'percentage';
16 | settings.topic.visualdata.progress = 'progress';
17 | settings.topic.visualdata.chartValue = 'chartValue';
18 | settings.topic.visualdata.chartValue2 = 'chartValue2';
19 | settings.topic.visualdata.topn = 'topn';
20 | settings.topic.visualdata.pieChart = 'piechart';
--------------------------------------------------------------------------------
/dist/settings.js:
--------------------------------------------------------------------------------
1 | // client-side settings (for dev only)
2 | window.settings = {};
3 |
4 | settings.gatewayHost = 'localhost:9090';
5 | settings.meteorHost = 'localhost:5000';
6 |
7 | settings.webSocketURL = 'ws://' + settings.gatewayHost + '/pubsub';
8 | settings.restBaseURL = 'http://' + settings.gatewayHost + '/ws/v1/';
9 | settings.meteorURL = 'ws://' + settings.meteorHost + '/websocket';
10 |
11 | settings.topic = {};
12 | settings.topic.visualdata = {};
13 |
14 | settings.topic.visualdata.piValue = 'piValue';
15 | settings.topic.visualdata.percentage = 'percentage';
16 | settings.topic.visualdata.progress = 'progress';
17 | settings.topic.visualdata.chartValue = 'chartValue';
18 | settings.topic.visualdata.chartValue2 = 'chartValue2';
19 | settings.topic.visualdata.topn = 'topn';
20 | settings.topic.visualdata.pieChart = 'piechart';
--------------------------------------------------------------------------------
/app/scripts/controllers/simple.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 DataTorrent, Inc. ALL Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | 'use strict';
18 |
19 | angular.module('app')
20 | .controller('SimpleCtrl', function ($scope) {
21 | $scope.values = ['option1', 'option2', 'option3'];
22 | $scope.value = $scope.values[0];
23 | });
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | var config = {};
2 |
3 | config.port = process.env.PORT || 3000;
4 | config.staticDir = process.env.STATIC_DIR || '/dist';
5 |
6 | // client settings (passed to the browser)
7 | config.settings = {};
8 | var settings = config.settings;
9 |
10 | settings.gatewayHost = process.env.GATEWAY_HOST || 'localhost:9090';
11 | settings.meteorHost = process.env.METEOR_HOST || 'localhost:5000';
12 |
13 | settings.webSocketURL = 'ws://' + settings.gatewayHost + '/pubsub';
14 | settings.restBaseURL = 'http://' + settings.gatewayHost + '/ws/v1/';
15 | settings.meteorURL = 'ws://' + settings.meteorHost + '/websocket';
16 |
17 | settings.topic = {};
18 | settings.topic.visualdata = {};
19 |
20 | settings.topic.visualdata.piValue = 'piValue';
21 | settings.topic.visualdata.percentage = 'percentage';
22 | settings.topic.visualdata.progress = 'progress';
23 | settings.topic.visualdata.chartValue = 'chartValue';
24 | settings.topic.visualdata.chartValue2 = 'chartValue2';
25 | settings.topic.visualdata.topn = 'topn';
26 | settings.topic.visualdata.pieChart = 'piechart';
27 |
28 | module.exports = config;
29 |
--------------------------------------------------------------------------------
/app/template/topics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
{{topicSchema}}
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/dist/template/topics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
{{topicSchema}}
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/app/styles/main.less:
--------------------------------------------------------------------------------
1 | // path to fonts
2 | @icon-font-path: "../fonts/";
3 | @import "bootstrap";
4 | @import "../bower_components/pines-notify/pnotify.core.css";
5 | @import "../bower_components/nvd3/nv.d3.css";
6 | @import "../bower_components/ng-grid/ng-grid.css";
7 | @import "nv.d3";
8 | @import "../bower_components/malhar-angular-dashboard/dist/angular-ui-dashboard.css";
9 |
10 | // app-specific styles
11 | @import "widgets";
12 |
13 | body {
14 | padding-top: 50px;
15 | }
16 |
17 | .main-view {
18 | margin: 15px;
19 | }
20 |
21 | .navbar-inverse {
22 | background: #11506d;
23 |
24 | .navbar-brand {
25 | color: #ffffff;
26 |
27 | sup {
28 | vertical-align: middle;
29 | font-size: 50%;
30 | font-weight: normal;
31 | }
32 | }
33 | }
34 |
35 | .ngGrid {
36 | border: 1px solid rgb(212,212,212);
37 | }
38 |
39 | .applist {
40 | .ngGrid {
41 | width: 800px;
42 | height: 500px;
43 | }
44 |
45 | .alert {
46 | display: inline-block;
47 | }
48 | }
49 |
50 | fieldset.overview-group {
51 | border: 1px solid black;
52 | padding: 10px;
53 |
54 | legend {
55 | width: auto;
56 | border: 0;
57 | }
58 | }
--------------------------------------------------------------------------------
/app/scripts/controllers/meteor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('MeteorCtrl', function ($scope, MeteorDataModel, MeteorTimeSeriesDataModel) {
5 | var widgetDefs = [
6 | {
7 | name: 'Line Chart',
8 | directive: 'wt-line-chart',
9 | dataAttrName: 'chart',
10 | dataModelType: MeteorTimeSeriesDataModel,
11 | dataModelOptions: {
12 | collection: 'history'
13 | },
14 | style: {
15 | width: '50%'
16 | }
17 | },
18 | {
19 | name: 'JSON',
20 | directive: 'wt-json',
21 | dataAttrName: 'value',
22 | dataModelType: MeteorDataModel,
23 | dataModelOptions: {
24 | collection: 'history'
25 | }
26 | }
27 | ];
28 |
29 | var defaultWidgets = [
30 | {
31 | name: 'Line Chart',
32 | title: 'Meteor MongoDB Historical Data'
33 | },
34 | {
35 | name: 'JSON',
36 | title: 'Collection Changes'
37 | }
38 | ];
39 |
40 | $scope.dashboardOptions = {
41 | widgetButtons: true,
42 | widgetDefinitions: widgetDefs,
43 | defaultWidgets: defaultWidgets,
44 | optionsTemplateUrl: 'template/widgetOptions.html'
45 | };
46 | });
47 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var http = require('http');
3 | var config = require('./config');
4 |
5 | var app = express();
6 |
7 | var allowCrossDomain = function(req, res, next) {
8 | res.header('Access-Control-Allow-Origin', '*');
9 | res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
10 | res.header('Access-Control-Allow-Headers', 'Content-Type');
11 | next();
12 | };
13 |
14 | // all environments
15 | app.use(express.favicon());
16 | app.use(express.logger('dev'));
17 | app.use(express.bodyParser());
18 | app.use(express.methodOverride());
19 | app.use(allowCrossDomain);
20 | app.use(app.router);
21 |
22 | console.log('environment: ' + app.get('env'));
23 |
24 | app.use(express.static(__dirname + config.staticDir));
25 |
26 | if ('development' === app.get('env')) {
27 | app.use(express.errorHandler());
28 | }
29 |
30 | app.get('/settings.js', function(req, res) {
31 | res.setHeader('Content-Type', 'application/javascript');
32 | res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
33 | res.setHeader('Pragma', 'no-cache');
34 | res.setHeader('Expires', 0);
35 |
36 | res.send('window.settings = ' + JSON.stringify(config.settings) + ';');
37 | });
38 |
39 | http.createServer(app).listen(config.port, function(){
40 | console.log('Express server listening on port ' + config.port);
41 | });
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard-webapp",
3 | "version": "0.0.1",
4 | "dependencies": {
5 | "angular": "~1.3",
6 | "json3": "~3.2.4",
7 | "jquery": "~1.9.1",
8 | "es5-shim": "~2.0.8",
9 | "angular-resource": "~1.3",
10 | "angular-cookies": "~1.3",
11 | "angular-sanitize": "~1.3",
12 | "gridster": "~0.2.1",
13 | "bootstrap": "~3.0.3",
14 | "angular-bootstrap": "0.9.0",
15 | "angular-route": "~1.3",
16 | "jquery-ui": "~1.10.3",
17 | "underscore": "~1.5.2",
18 | "ng-grid": "2.0.11",
19 | "d3": "3.4.4",
20 | "nvd3": "~1.1.15-beta",
21 | "angularjs-nvd3-directives": "~0.0.7",
22 | "angular-pines-notify": "~0.1",
23 | "pines-notify": "~1.3",
24 | "angular-ui-sortable": "0.12.5",
25 | "malhar-angular-widgets": "https://github.com/DataTorrent/malhar-angular-widgets.git#master",
26 | "malhar-angular-dashboard": "https://github.com/DataTorrent/malhar-angular-dashboard.git#master"
27 | },
28 | "devDependencies": {
29 | "angular-mocks": "~1.3",
30 | "angular-scenario": "~1.3"
31 | },
32 | "resolutions": {
33 | "angular-ui-sortable": "0.12.5",
34 | "d3": "3.4.4",
35 | "jquery": "~2.0.3",
36 | "angular-bootstrap": "~0.11.0",
37 | "jquery-ui": "~1.11.0",
38 | "pines-notify": "~2.0.1",
39 | "angular": "~1.2.22",
40 | "angular-pines-notify": "~1.0.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing Guidelines
2 | =======================
3 | This project welcomes new contributors.
4 |
5 | Licensing
6 | ---------
7 | You acknowledge that your submissions to DataTorrent on this repository are made pursuant the terms of the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html) and constitute "Contributions," as defined therein, and you represent and warrant that you have the right and authority to do so.
8 |
9 | When adding **new javascript files**, please include the following Apache v2.0 license header at the top of the file, with the fields enclosed by brackets "[]" replaced with your own identifying information. **(Don't include the brackets!)**:
10 |
11 | ```JavaScript
12 | /*
13 | * Copyright (c) [XXXX] [NAME OF COPYRIGHT OWNER]
14 | *
15 | * Licensed under the Apache License, Version 2.0 (the "License");
16 | * you may not use this file except in compliance with the License.
17 | * You may obtain a copy of the License at
18 | *
19 | * http://www.apache.org/licenses/LICENSE-2.0
20 | *
21 | * Unless required by applicable law or agreed to in writing, software
22 | * distributed under the License is distributed on an "AS IS" BASIS,
23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 | * See the License for the specific language governing permissions and
25 | * limitations under the License.
26 | */
27 | ```
--------------------------------------------------------------------------------
/app/scripts/controllers/topics.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('TopicCtrl', function ($scope, webSocket, Gateway) {
5 | $scope.prevTopic = function () {
6 | var index = $scope.topics.indexOf($scope.topic);
7 | var prev = ($scope.topics.length + index - 1) % $scope.topics.length;
8 | $scope.topic = $scope.topics[prev];
9 | };
10 |
11 | $scope.nextTopic = function () {
12 | var index = $scope.topics.indexOf($scope.topic);
13 | var next = (index + 1) % $scope.topics.length;
14 | $scope.topic = $scope.topics[next];
15 | };
16 |
17 | $scope.selectTopic = function (topic) {
18 | $scope.topic = topic;
19 | };
20 |
21 | var callback = function (message) {
22 | $scope.topicData = JSON.stringify(message, null, ' ');
23 | $scope.$apply();
24 | };
25 |
26 | $scope.$watch('topic', function (newTopic, oldTopic) {
27 | if (oldTopic && callback) {
28 | webSocket.unsubscribe(oldTopic.topic, callback);
29 | }
30 |
31 | if (newTopic) {
32 | $scope.topicData = 'Loading...';
33 | $scope.topicSchema = JSON.stringify(newTopic.schema, null, ' ');
34 | webSocket.subscribe(newTopic.topic, callback, $scope);
35 | }
36 | });
37 |
38 | $scope.topics = [];
39 |
40 | Gateway.getTopics().then(function (topics) {
41 | $scope.topics = topics;
42 | if (topics.length) {
43 | $scope.topic = $scope.topics[0];
44 | }
45 | });
46 | });
--------------------------------------------------------------------------------
/karma-e2e.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // http://karma-runner.github.io/0.10/config/configuration-file.html
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | // base path, that will be used to resolve files and exclude
7 | basePath: '',
8 |
9 | // testing framework to use (jasmine/mocha/qunit/...)
10 | frameworks: ['ng-scenario'],
11 |
12 | // list of files / patterns to load in the browser
13 | files: [
14 | 'test/e2e/**/*.js'
15 | ],
16 |
17 | // list of files / patterns to exclude
18 | exclude: [],
19 |
20 | // web server port
21 | port: 8080,
22 |
23 | // level of logging
24 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
25 | logLevel: config.LOG_INFO,
26 |
27 |
28 | // enable / disable watching file and executing tests whenever any file changes
29 | autoWatch: false,
30 |
31 |
32 | // Start these browsers, currently available:
33 | // - Chrome
34 | // - ChromeCanary
35 | // - Firefox
36 | // - Opera
37 | // - Safari (only Mac)
38 | // - PhantomJS
39 | // - IE (only Windows)
40 | browsers: ['Chrome'],
41 |
42 |
43 | // Continuous Integration mode
44 | // if true, it capture browsers, run tests and exit
45 | singleRun: false
46 |
47 | // Uncomment the following lines if you are using grunt's server to run the tests
48 | // proxies: {
49 | // '/': 'http://localhost:9000/'
50 | // },
51 | // URL root prevent conflicts with the site root
52 | // urlRoot: '_karma_'
53 | });
54 | };
55 |
--------------------------------------------------------------------------------
/app/scripts/controllers/widgetOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('WidgetOptionsCtrl', function ($scope, webSocket, Gateway, settings) {
5 | $scope.dataSourceName = 'Gateway (' + settings.gatewayHost + ')'; //TODO
6 |
7 | $scope.prevTopic = function () {
8 | var index = $scope.topics.indexOf($scope.topic);
9 | var prev = ($scope.topics.length + index - 1) % $scope.topics.length;
10 | $scope.topic = $scope.topics[prev];
11 | };
12 |
13 | $scope.nextTopic = function () {
14 | var index = $scope.topics.indexOf($scope.topic);
15 | var next = (index + 1) % $scope.topics.length;
16 | $scope.topic = $scope.topics[next];
17 | };
18 |
19 | var widget = $scope.widget;
20 |
21 | if (widget && widget.dataModel) {
22 | $scope.topics = [];
23 | if (widget.dataTypes) {
24 | $scope.dataTypes = widget.dataTypes.join(', ');
25 | }
26 |
27 | Gateway.getTopics().then(function (topics) {
28 | if (widget.dataTypes) {
29 | topics = _.reject(topics, function (topic) {
30 | return !topic.schema || !_.contains(widget.dataTypes, topic.schema.type);
31 | });
32 | }
33 |
34 | $scope.topics = topics;
35 | $scope.topic = _.findWhere($scope.topics, {topic: widget.dataModel.topic});
36 | });
37 |
38 | $scope.$watch('topic', function (newTopic) {
39 | if (newTopic && (newTopic.topic !== widget.dataModel.topic)) {
40 | widget.dataModel.update(newTopic.topic);
41 | }
42 | });
43 |
44 | $scope.selectTopic = function (topic) {
45 | $scope.topic = topic;
46 | };
47 | }
48 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-dashboard",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "express": "~3.4.8",
6 | "mongodb": "^1.4.0",
7 | "lodash": "^2.4.1"
8 | },
9 | "devDependencies": {
10 | "grunt": "~0.4.1",
11 | "grunt-contrib-copy": "~0.4.1",
12 | "grunt-contrib-concat": "~0.3.0",
13 | "grunt-contrib-coffee": "~0.7.0",
14 | "grunt-contrib-uglify": "~0.2.0",
15 | "grunt-contrib-compass": "~0.5.0",
16 | "grunt-contrib-jshint": "~0.6.0",
17 | "grunt-contrib-cssmin": "~0.6.0",
18 | "grunt-contrib-connect": "~0.5.0",
19 | "grunt-contrib-clean": "~0.5.0",
20 | "grunt-contrib-htmlmin": "~0.1.3",
21 | "grunt-contrib-watch": "~0.5.2",
22 | "grunt-autoprefixer": "~0.2.0",
23 | "grunt-usemin": "~0.1.11",
24 | "grunt-svgmin": "~0.2.0",
25 | "grunt-rev": "~0.1.0",
26 | "grunt-concurrent": "~0.3.0",
27 | "load-grunt-tasks": "~0.1.0",
28 | "grunt-google-cdn": "~0.2.0",
29 | "grunt-ngmin": "~0.0.2",
30 | "time-grunt": "~0.1.0",
31 | "karma-ng-scenario": "~0.1.0",
32 | "grunt-karma": "~0.6.2",
33 | "karma-script-launcher": "~0.1.0",
34 | "karma-chrome-launcher": "~0.1.2",
35 | "karma-firefox-launcher": "~0.1.3",
36 | "karma-html2js-preprocessor": "~0.1.0",
37 | "karma-jasmine": "~0.1.5",
38 | "karma-coffee-preprocessor": "~0.1.2",
39 | "requirejs": "~2.1.9",
40 | "karma-requirejs": "~0.2.1",
41 | "karma-phantomjs-launcher": "~0.1.1",
42 | "karma": "~0.10.9",
43 | "karma-ng-html2js-preprocessor": "~0.1.0",
44 | "grunt-contrib-less": "~0.9.0"
45 | },
46 | "engines": {
47 | "node": ">=0.8.0"
48 | },
49 | "scripts": {
50 | "test": "grunt test"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/scripts/controllers/apps.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('AppsCtrl', function ($scope, Gateway) {
5 | $scope.showLoading = true;
6 |
7 | var topicsPromise = Gateway.getTopics();
8 |
9 | topicsPromise.then(function (topics) {
10 | var appIdMap = {};
11 |
12 | _.each(topics, function (topic) {
13 | var appId = topic.appId;
14 |
15 | if (appIdMap.hasOwnProperty(appId)) {
16 | var app = appIdMap[appId];
17 | app.topicCount++;
18 | } else {
19 | var newApp = {
20 | id: appId,
21 | name: topic.appName,
22 | startedTime: topic.appStartedTime,
23 | topicCount: 1
24 | };
25 | appIdMap[appId] = newApp;
26 | }
27 | });
28 |
29 | $scope.apps = _.sortBy(_.values(appIdMap), function (app) {
30 | return (-app.startedTime);
31 | });
32 | $scope.showLoading = false;
33 | }, function () {
34 | $scope.showLoading = false;
35 | });
36 |
37 | var linkTemplate = '';
38 |
39 | $scope.gridOptions = {
40 | data: 'apps',
41 | enableRowSelection: false,
42 | enableColumnResize: true,
43 | showFilter: true,
44 | columnDefs: [
45 | { field: 'id', displayName: 'Id', cellTemplate: linkTemplate, width: 250 },
46 | { field: 'name', displayName: 'Name' },
47 | { field: 'startedTime', displayName: 'Start Time', cellFilter: 'date:\'yyyy-MM-dd HH:mm:ss\'', width: 200 },
48 | { field: 'topicCount', displayName: 'Topic Count', width: 150 }
49 | ]
50 | };
51 | });
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
--------------------------------------------------------------------------------
/app/template/widgetOptions.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
35 |
36 |
50 |
--------------------------------------------------------------------------------
/dist/template/widgetOptions.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
35 |
36 |
50 |
--------------------------------------------------------------------------------
/app/scripts/controllers/serverdata.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('ServerDataCtrl', function ($scope, webSocket, Gateway, settings, widgetDefs) {
5 | var defaultWidgets = [
6 | {
7 | name: 'Value',
8 | title: 'Value 1'
9 | },
10 | {
11 | name: 'Value',
12 | title: 'Value 2',
13 | dataModelOptions: {
14 | defaultTopic: settings.topic.visualdata.percentage
15 | }
16 | },
17 | {
18 | name: 'Progressbar',
19 | title: 'Progressbar'
20 | },
21 | {
22 | name: 'Line Chart',
23 | title: 'Line Chart 1'
24 | },
25 | {
26 | name: 'Line Chart',
27 | title: 'Line Chart 2',
28 | dataModelOptions: {
29 | defaultTopic: settings.topic.visualdata.chartValue2
30 | }
31 | },
32 | {
33 | name: 'TopN',
34 | title: 'Top N'
35 | },
36 | {
37 | name: 'Pie Chart',
38 | title: 'Pie Chart'
39 | },
40 | {
41 | name: 'JSON',
42 | title: 'JSON'
43 | },
44 | {
45 | name: 'WebSocket Debugger',
46 | title: 'WebSocket Debugger'
47 | }
48 | ];
49 |
50 | $scope.dashboardOptions = {
51 | //useLocalStorage: true, //TODO enable by default
52 | widgetButtons: true,
53 | widgetDefinitions: widgetDefs,
54 | defaultWidgets: defaultWidgets,
55 | optionsTemplateUrl: 'template/widgetOptions.html'
56 | };
57 |
58 | // initialize widgets with default topics
59 | var topicsPromise = Gateway.getTopics();
60 |
61 | $scope.$on('widgetAdded', function (event, widget) {
62 | event.stopPropagation();
63 |
64 | if (widget.dataModel && widget.dataModelOptions && widget.dataModelOptions.defaultTopic) {
65 | topicsPromise.then(function (topics) {
66 | var defaultTopic = widget.dataModelOptions.defaultTopic;
67 |
68 | var topic = _.find(topics, function (topic) {
69 | return topic.name.indexOf(defaultTopic) >= 0;
70 | });
71 |
72 | if (topic) {
73 | widget.dataModel.update(topic.topic);
74 | }
75 | });
76 | }
77 | });
78 | });
--------------------------------------------------------------------------------
/app/scripts/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 DataTorrent, Inc. ALL Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | 'use strict';
18 |
19 | angular.module('app', [
20 | 'app.service',
21 | 'ngRoute',
22 | 'ngCookies',
23 | 'ngResource',
24 | 'ngSanitize',
25 | 'nvd3ChartDirectives',
26 | 'ui.dashboard',
27 | 'ui.widgets',
28 | 'ui.models'
29 | ])
30 | .constant('settings', window.settings)
31 | .config(function ($routeProvider, webSocketProvider, settings) {
32 | if (settings) {
33 | webSocketProvider.setWebSocketURL(settings.webSocketURL);
34 | }
35 |
36 | $routeProvider
37 | .when('/', {
38 | templateUrl: 'views/main.html',
39 | controller: 'MainCtrl'
40 | })
41 | .when('/simple', {
42 | templateUrl: 'views/simple.html',
43 | controller: 'SimpleCtrl'
44 | })
45 | .when('/rest', {
46 | templateUrl: 'views/main.html',
47 | controller: 'RestDataCtrl'
48 | })
49 | .when('/meteor', {
50 | templateUrl: 'views/main.html',
51 | controller: 'MeteorCtrl'
52 | })
53 | .when('/discovery', {
54 | templateUrl: 'views/main.html',
55 | controller: 'DiscoveryCtrl'
56 | })
57 | .when('/apps', {
58 | templateUrl: 'views/apps.html',
59 | controller: 'AppsCtrl'
60 | })
61 | .when('/apps/:appId', {
62 | templateUrl: 'views/main.html',
63 | controller: 'DiscoveryCtrl'
64 | })
65 | .when('/clientdata', {
66 | templateUrl: 'views/main.html',
67 | controller: 'MainCtrl'
68 | })
69 | .when('/serverdata', {
70 | templateUrl: 'views/main.html',
71 | controller: 'ServerDataCtrl'
72 | })
73 | .otherwise({
74 | redirectTo: '/'
75 | });
76 | });
--------------------------------------------------------------------------------
/app/styles/bootstrap.less:
--------------------------------------------------------------------------------
1 | @import "../bower_components/bootstrap/less/mixins.less";
2 |
3 | // Reset
4 | @import "../bower_components/bootstrap/less/normalize.less";
5 | @import "../bower_components/bootstrap/less/print.less";
6 |
7 | // Core CSS
8 | @import "../bower_components/bootstrap/less/scaffolding.less";
9 | @import "../bower_components/bootstrap/less/type.less";
10 | @import "../bower_components/bootstrap/less/code.less";
11 | @import "../bower_components/bootstrap/less/grid.less";
12 | @import "../bower_components/bootstrap/less/tables.less";
13 | @import "../bower_components/bootstrap/less/forms.less";
14 | @import "../bower_components/bootstrap/less/buttons.less";
15 |
16 | // Components
17 | @import "../bower_components/bootstrap/less/component-animations.less";
18 | @import "../bower_components/bootstrap/less/glyphicons.less";
19 | @import "../bower_components/bootstrap/less/dropdowns.less";
20 | @import "../bower_components/bootstrap/less/button-groups.less";
21 | @import "../bower_components/bootstrap/less/input-groups.less";
22 | @import "../bower_components/bootstrap/less/navs.less";
23 | @import "../bower_components/bootstrap/less/navbar.less";
24 | @import "../bower_components/bootstrap/less/breadcrumbs.less";
25 | @import "../bower_components/bootstrap/less/pagination.less";
26 | @import "../bower_components/bootstrap/less/pager.less";
27 | @import "../bower_components/bootstrap/less/labels.less";
28 | @import "../bower_components/bootstrap/less/badges.less";
29 | @import "../bower_components/bootstrap/less/jumbotron.less";
30 | @import "../bower_components/bootstrap/less/thumbnails.less";
31 | @import "../bower_components/bootstrap/less/alerts.less";
32 | @import "../bower_components/bootstrap/less/progress-bars.less";
33 | @import "../bower_components/bootstrap/less/media.less";
34 | @import "../bower_components/bootstrap/less/list-group.less";
35 | @import "../bower_components/bootstrap/less/panels.less";
36 | @import "../bower_components/bootstrap/less/wells.less";
37 | @import "../bower_components/bootstrap/less/close.less";
38 |
39 | // Components w/ JavaScript
40 | @import "../bower_components/bootstrap/less/modals.less";
41 | @import "../bower_components/bootstrap/less/tooltip.less";
42 | @import "../bower_components/bootstrap/less/popovers.less";
43 | @import "../bower_components/bootstrap/less/carousel.less";
44 |
45 | // Utility classes
46 | @import "../bower_components/bootstrap/less/utilities.less";
47 | @import "../bower_components/bootstrap/less/responsive-utilities.less";
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // http://karma-runner.github.io/0.10/config/configuration-file.html
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | // base path, that will be used to resolve files and exclude
7 | basePath: '',
8 |
9 | // testing framework to use (jasmine/mocha/qunit/...)
10 | frameworks: ['jasmine'],
11 |
12 | // list of files / patterns to load in the browser
13 | files: [
14 | 'app/bower_components/jquery/jquery.js',
15 | 'app/bower_components/underscore/underscore.js',
16 | 'app/bower_components/angular/angular.js',
17 | 'app/bower_components/angular-route/angular-route.js',
18 | 'app/bower_components/angular-mocks/angular-mocks.js',
19 | 'app/bower_components/angular-resource/angular-resource.js',
20 | 'app/bower_components/angular-cookies/angular-cookies.js',
21 | 'app/bower_components/angular-sanitize/angular-sanitize.js',
22 | 'app/bower_components/angular-ui-sortable/sortable.js',
23 | 'app/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
24 | 'app/bower_components/malhar-angular-dashboard/dist/angular-ui-dashboard.js',
25 | 'app/bower_components/malhar-angular-table/dist/mlhr-table.js',
26 | 'app/bower_components/malhar-angular-widgets/dist/malhar-angular-widgets.js',
27 | 'app/bower_components/ng-grid/ng-grid-2.0.11.debug.js',
28 | 'app/bower_components/angularjs-nvd3-directives/dist/angularjs-nvd3-directives.js',
29 | 'app/bower_components/pines-notify/jquery.pnotify.js',
30 | 'app/bower_components/angular-pines-notify/src/pnotify.js',
31 | 'app/scripts/*.js',
32 | 'app/scripts/**/*.js',
33 | 'test/mock/**/*.js',
34 | 'test/spec/**/*.js'
35 | ],
36 |
37 | // list of files / patterns to exclude
38 | exclude: [],
39 |
40 | // web server port
41 | port: 8080,
42 |
43 | // level of logging
44 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
45 | logLevel: config.LOG_INFO,
46 |
47 |
48 | // enable / disable watching file and executing tests whenever any file changes
49 | autoWatch: false,
50 |
51 |
52 | // Start these browsers, currently available:
53 | // - Chrome
54 | // - ChromeCanary
55 | // - Firefox
56 | // - Opera
57 | // - Safari (only Mac)
58 | // - PhantomJS
59 | // - IE (only Windows)
60 | browsers: ['PhantomJS'],
61 |
62 |
63 | // Continuous Integration mode
64 | // if true, it capture browsers, run tests and exit
65 | singleRun: false
66 | });
67 | };
68 |
--------------------------------------------------------------------------------
/app/scripts/controllers/rest.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('RestDataCtrl', function ($scope, settings, RestTimeSeriesDataModel, RestTopNDataModel) {
5 | var widgetDefs = [
6 | {
7 | name: 'Line Chart Visits',
8 | directive: 'wt-historical-chart',
9 | dataAttrName: 'chart',
10 | dataModelType: RestTimeSeriesDataModel,
11 | dataModelOptions: {
12 | metric: 'count'
13 | },
14 | style: {
15 | width: '50%'
16 | }
17 | },
18 | {
19 | name: 'Line Chart Bandwidth',
20 | directive: 'wt-historical-chart',
21 | dataAttrName: 'chart',
22 | dataModelType: RestTimeSeriesDataModel,
23 | dataModelOptions: {
24 | metric: 'bandwidth'
25 | },
26 | style: {
27 | width: '50%'
28 | }
29 | },
30 | {
31 | name: 'Countries',
32 | directive: 'wt-top-n',
33 | dataAttrName: 'data',
34 | dataModelType: RestTopNDataModel,
35 | dataModelOptions: {
36 | dimension: 'geoip_country_name',
37 | limit: 20
38 | },
39 | style: {
40 | width: '33%'
41 | }
42 | },
43 | {
44 | name: 'Cities',
45 | directive: 'wt-top-n',
46 | dataAttrName: 'data',
47 | dataModelType: RestTopNDataModel,
48 | dataModelOptions: {
49 | dimension: 'geoip_city_name',
50 | limit: 20
51 | },
52 | style: {
53 | width: '33%'
54 | }
55 | },
56 | {
57 | name: 'Browsers',
58 | directive: 'wt-top-n',
59 | dataAttrName: 'data',
60 | dataModelType: RestTopNDataModel,
61 | dataModelOptions: {
62 | dimension: 'agentinfo_name',
63 | limit: 20
64 | },
65 | style: {
66 | width: '33%'
67 | }
68 | }
69 | ];
70 |
71 | var defaultWidgets = [
72 | {
73 | name: 'Line Chart Visits',
74 | title: 'Visits'
75 | },
76 | {
77 | name: 'Line Chart Bandwidth',
78 | title: 'Bandwidth'
79 | },
80 | {
81 | name: 'Countries',
82 | title: 'Countries'
83 | },
84 | {
85 | name: 'Cities',
86 | title: 'Cities'
87 | },
88 | {
89 | name: 'Browsers',
90 | title: 'Browsers'
91 | }
92 | ];
93 |
94 | $scope.dashboardOptions = {
95 | widgetButtons: true,
96 | widgetDefinitions: widgetDefs,
97 | defaultWidgets: defaultWidgets
98 | };
99 | });
--------------------------------------------------------------------------------
/app/scripts/services/gateway.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app.service')
4 | .factory('Gateway', function ($rootScope, $q, $http, webSocket, settings) {
5 | return {
6 | getDataTopics: function () {
7 | var deferred = $q.defer();
8 |
9 | webSocket.subscribe('_latestTopics', function (message) {
10 | var list = _.reject(message, function (topic) {
11 | return topic.indexOf('AppData{\"schema\"') !== 0;
12 | });
13 |
14 | var topics = _.map(list, function (topic) {
15 | var jsonInd = topic.indexOf('{');
16 |
17 | var jsonString = topic.substr(jsonInd);
18 |
19 | var topicData = JSON.parse(jsonString);
20 |
21 | return {
22 | topic: topic,
23 | appId: topicData.appId,
24 | name: topicData.topicName,
25 | schema: topicData.schema,
26 | type: topicData.schema.type
27 | };
28 | });
29 |
30 | deferred.resolve(topics);
31 | //$rootScope.$apply();
32 | }, $rootScope);
33 | webSocket.send({ type: 'getLatestTopics' });
34 | //TODO unsubscribe
35 |
36 | return deferred.promise;
37 | },
38 |
39 | getRunningApps: function () {
40 | var deferred = $q.defer();
41 |
42 | var url = settings.restBaseURL + 'applications?states=running&jsonp=JSON_CALLBACK';
43 | $http.jsonp(url)
44 | .success(function (data) {
45 | if (data && data.apps && data.apps.length > 0) {
46 | var apps = _.reject(data.apps, function (app) {
47 | return app.state !== 'RUNNING';
48 | });
49 | apps = _.sortBy(apps, function (app) {
50 | return (-app.startedTime);
51 | });
52 |
53 | deferred.resolve(apps);
54 | }
55 | });
56 |
57 | return deferred.promise;
58 | },
59 |
60 | getTopics: function () {
61 | var deferred = $q.defer();
62 |
63 | var topicsPromise = this.getDataTopics();
64 | var appsPromise = this.getRunningApps();
65 |
66 | $q.all({ topics: topicsPromise, apps: appsPromise }).then(function (resolutions) {
67 | var topics = resolutions.topics;
68 | var apps = resolutions.apps;
69 |
70 | var appIdMap = {};
71 | _.each(apps, function (app) {
72 | appIdMap[app.id] = app;
73 | });
74 |
75 | topics = _.reject(topics, function (topic) {
76 | return !appIdMap.hasOwnProperty(topic.appId);
77 | });
78 |
79 | _.each(topics, function (topic) {
80 | var app = appIdMap[topic.appId];
81 | topic.appName = app.name;
82 | topic.appStartedTime = app.startedTime;
83 | });
84 |
85 | topics = _.sortBy(topics, function (topic) {
86 | return topic.name;
87 | });
88 |
89 | deferred.resolve(topics);
90 | });
91 |
92 | return deferred.promise;
93 | }
94 | };
95 | });
96 |
--------------------------------------------------------------------------------
/app/scripts/services/widgets.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app.service')
4 | .factory('widgetDefs', function (settings, WebSocketWidgetDataModel, TimeSeriesDataModel, PieChartDataModel) {
5 | return [
6 | {
7 | name: 'Value',
8 | directive: 'wt-scope-watch',
9 | dataAttrName: 'value',
10 | attrs: {
11 | 'value-class': 'alert-info'
12 | },
13 | dataTypes: ['percentage', 'simple'],
14 | dataModelType: WebSocketWidgetDataModel,
15 | dataModelOptions: {
16 | defaultTopic: settings.topic.visualdata.piValue
17 | }
18 | },
19 | {
20 | name: 'Progressbar',
21 | directive: 'progressbar',
22 | attrs: {
23 | class: 'progress-striped',
24 | type: 'success'
25 | },
26 | dataAttrName: 'value',
27 | dataTypes: ['percentage', 'simple'],
28 | dataModelType: WebSocketWidgetDataModel,
29 | dataModelOptions: {
30 | defaultTopic: settings.topic.visualdata.progress
31 | }
32 | },
33 | {
34 | name: 'Line Chart',
35 | directive: 'wt-line-chart',
36 | dataAttrName: 'chart',
37 | dataTypes: ['timeseries'],
38 | dataModelType: TimeSeriesDataModel,
39 | dataModelOptions: {
40 | defaultTopic: settings.topic.visualdata.chartValue
41 | },
42 | style: {
43 | width: '50%'
44 | }
45 | },
46 | {
47 | name: 'TopN',
48 | directive: 'wt-top-n',
49 | attrs: {
50 | data: 'serverTopTen'
51 | },
52 | dataAttrName: 'data',
53 | dataTypes: ['topN'],
54 | dataModelType: WebSocketWidgetDataModel,
55 | dataModelOptions: {
56 | defaultTopic: settings.topic.visualdata.topn
57 | }
58 | },
59 | {
60 | name: 'Pie Chart',
61 | directive: 'wt-pie-chart',
62 | style: {
63 | width: '350px',
64 | height: '350px'
65 | },
66 | dataAttrName: 'data',
67 | dataTypes: ['piechart'],
68 | dataModelType: PieChartDataModel,
69 | dataModelOptions: {
70 | defaultTopic: settings.topic.visualdata.pieChart
71 | }
72 | },
73 | {
74 | name: 'Gauge',
75 | directive: 'wt-gauge',
76 | dataAttrName: 'value',
77 | dataTypes: ['percentage', 'simple'],
78 | dataModelType: WebSocketWidgetDataModel,
79 | dataModelOptions: {
80 | defaultTopic: settings.topic.visualdata.percentage
81 | },
82 | style: {
83 | width: '250px'
84 | }
85 | },
86 | {
87 | name: 'JSON',
88 | directive: 'wt-json',
89 | dataAttrName: 'value',
90 | dataModelType: WebSocketWidgetDataModel,
91 | dataModelOptions: {
92 | defaultTopic: settings.topic.visualdata.topn
93 | }
94 | },
95 | {
96 | name: 'WebSocket Debugger',
97 | templateUrl: 'template/topics.html'
98 | }
99 | ];
100 | });
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | malhar-dashboard-webapp
2 | =================
3 |
4 | [](https://travis-ci.org/DataTorrent/malhar-dashboard-webapp)
5 |
6 | Dashboard Web Application
7 |
8 | [Online Demo](http://datatorrent.github.io/malhar-dashboard-webapp/#/)
9 |
10 | 
11 |
12 | ## Dependencies
13 |
14 | [Dashboard Directive](https://github.com/DataTorrent/malhar-angular-dashboard)
15 |
16 | [Widget Library](https://github.com/DataTorrent/malhar-angular-widgets)
17 |
18 | 
19 |
20 | ## Running Application (minimum dependencies)
21 |
22 | 1. Node.js way
23 |
24 | Install express
25 |
26 | ``` bash
27 | $ npm install express
28 | ```
29 | Run Node.js server
30 |
31 | ``` bash
32 | $ node app.js
33 | ```
34 | Application will be available at http://localhost:3000.
35 |
36 | 2. Simple web server way
37 |
38 | Start any web server in "dist" directory, e.g. with Python
39 | ``` bash
40 | $ python -m SimpleHTTPServer 8080
41 | ```
42 | Application will be available at http://localhost:8080
43 |
44 | In both cases static files (including bundled JS/CSS) will be served from "dist" directory.
45 |
46 | ## Running Application (development mode)
47 | Install dependencies:
48 |
49 | ``` bash
50 | $ npm install
51 | ```
52 |
53 | Install Bower dependencies:
54 |
55 | ``` bash
56 | $ bower install
57 | ```
58 |
59 | Run Grunt server task:
60 |
61 | ``` bash
62 | $ grunt server
63 | ```
64 |
65 | Application will be available at http://localhost:9000
66 |
67 | ## Building Application
68 |
69 | Application is built with Grunt.
70 |
71 | ``` bash
72 | $ npm install -g grunt-cli
73 | $ grunt
74 | ```
75 |
76 | ## Contributing
77 |
78 | This project welcomes new contributors.
79 |
80 | You acknowledge that your submissions to DataTorrent on this repository are made pursuant the terms of the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html) and constitute "Contributions," as defined therein, and you represent and warrant that you have the right and authority to do so.
81 |
82 | When **adding new javascript files**, please prepend the Apache v2.0 license header, which can be found in [CONTRIBUTING.md file](https://github.com/DataTorrent/malhar-dashboard-webapp/blob/master/CONTRIBUTING.md).
83 |
84 |
85 | ## Links
86 |
87 | [malhar-angular-dashboard](https://github.com/DataTorrent/malhar-angular-dashboard) AngularJS Dashboard directive.
88 |
89 | [malhar-angular-widgets](https://github.com/DataTorrent/malhar-angular-widgets) Widget library.
90 |
91 | [Node.js](http://nodejs.org/) Software platform built on JavaScript runtime
92 |
93 | [AngularJS](http://angularjs.org/) JavaScript framework
94 |
95 | [ui-sortable](https://github.com/angular-ui/ui-sortable) AngularJS UI Sortable
96 |
97 | [jQuery UI Sortable](http://jqueryui.com/sortable/) jQuery UI Sortable plugin (reordering with drag and drop)
98 |
99 | [Bower](http://bower.io/) Package manager for the web
100 |
101 | [Grunt](http://gruntjs.com/) JavaScript Task Runner
102 |
103 | [Yeoman](http://yeoman.io/) Webapp generator
104 |
105 | [DDP](https://github.com/meteor/meteor/blob/master/packages/livedata/DDP.md) Meteor Distributed Data Protocol
106 |
107 | [Meteor-DDP](https://github.com/eddflrs/meteor-ddp) Meteor DDP Javascript client
--------------------------------------------------------------------------------
/app/scripts/controllers/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('MainCtrl', function ($scope, $interval, stackedAreaChartSampleData, pieChartSampleData, RandomTimeSeriesDataModel, RandomTopNDataModel) {
5 | var widgetDefinitions = [
6 | {
7 | name: 'wt-time',
8 | style: {
9 | width: '33%'
10 | }
11 | },
12 | {
13 | name: 'wt-random',
14 | style: {
15 | width: '33%'
16 | }
17 | },
18 | {
19 | name: 'wt-scope-watch',
20 | attrs: {
21 | value: 'randomValue'
22 | },
23 | style: {
24 | width: '34%'
25 | }
26 | },
27 | {
28 | name: 'wt-line-chart',
29 | dataAttrName: 'chart',
30 | dataModelType: RandomTimeSeriesDataModel,
31 | style: {
32 | width: '50%'
33 | }
34 | },
35 | {
36 | name: 'wt-gauge',
37 | attrs: {
38 | value: 'percentage'
39 | },
40 | style: {
41 | width: '250px'
42 | }
43 | },
44 | {
45 | name: 'wt-top-n',
46 | dataAttrName: 'data',
47 | dataModelType: RandomTopNDataModel,
48 | style: {
49 | width: '30%'
50 | }
51 | },
52 | {
53 | name: 'progressbar',
54 | attrs: {
55 | class: 'progress-striped',
56 | type: 'success',
57 | value: 'percentage'
58 | },
59 | style: {
60 | width: '30%'
61 | }
62 | },
63 | {
64 | name: 'progressbar2',
65 | template: '{{percentage}}%
',
66 | style: {
67 | width: '30%'
68 | }
69 | },
70 | {
71 | name: 'URLtemplate',
72 | templateUrl: 'template/percentage.html'
73 | },
74 | {
75 | name: 'wt-pie-chart',
76 | style: {
77 | width: '350px',
78 | height: '350px'
79 | },
80 | attrs: {
81 | data: 'pieChartData'
82 | }
83 | }
84 | ];
85 |
86 |
87 | var defaultWidgets = _.map(widgetDefinitions, function (widgetDef) {
88 | return {
89 | name: widgetDef.name
90 | };
91 | });
92 |
93 | $scope.dashboardOptions = {
94 | widgetButtons: true,
95 | widgetDefinitions: widgetDefinitions,
96 | defaultWidgets: defaultWidgets
97 | };
98 |
99 | // random scope value (scope-watch widget)
100 | $interval(function () {
101 | $scope.randomValue = Math.random();
102 | }, 500);
103 |
104 | // percentage (gauge widget, progressbar widget)
105 | $scope.percentage = 5;
106 | $interval(function () {
107 | $scope.percentage = ($scope.percentage + 10) % 100;
108 | }, 1000);
109 |
110 | // nvd3-stacked-area-chart
111 | $scope.stackedAreaChartData = stackedAreaChartSampleData;
112 |
113 | $scope.xAxisTickFormat = function () {
114 | return function (d) {
115 | return d3.time.format('%x')(new Date(d));
116 | };
117 | };
118 |
119 | // pie chart
120 | $scope.pieChartData = pieChartSampleData;
121 |
122 | /*
123 | var pieChart = angular.copy(pieChartSampleData);
124 |
125 | $interval(function () { //TODO
126 | var a = pieChart[0];
127 | var b = pieChart[1];
128 | var sum = a.y + b.y;
129 | a.y = (a.y + 1) % sum;
130 | b.y = sum - a.y;
131 | $scope.pieChartData = angular.copy(pieChart);
132 | }, 500);
133 | */
134 |
135 | // external controls
136 | $scope.addWidget = function (directive) {
137 | $scope.dashboardOptions.addWidget({
138 | name: directive
139 | });
140 | };
141 |
142 | $scope.addWidgetScopeWatch = function () {
143 | $scope.dashboardOptions.addWidget({
144 | name: 'scope-watch',
145 | attrs: {
146 | value: 'randomValue'
147 | }
148 | });
149 | };
150 | });
--------------------------------------------------------------------------------
/app/scripts/controllers/discovery.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app')
4 | .controller('DiscoveryCtrl', function ($scope, $routeParams, webSocket, Gateway, settings,
5 | widgetDefs, notificationService) {
6 |
7 | $scope.dashboardOptions = {
8 | useLocalStorage: false, //TODO enable by default
9 | widgetButtons: true,
10 | widgetDefinitions: widgetDefs,
11 | settingsModalOptions: {
12 | optionsTemplateUrl: 'template/widgetOptions.html'
13 | }
14 | };
15 |
16 | Gateway.getTopics().then(function (topics) {
17 | if (!topics.length) { //TODO
18 | return;
19 | }
20 |
21 | topics = _.sortBy(topics, function (topic) {
22 | return (-topic.appStartedTime);
23 | });
24 |
25 | var appId;
26 |
27 | if ($routeParams.appId) {
28 | appId = $routeParams.appId;
29 | } else {
30 | appId = topics[0].appId;
31 | }
32 |
33 | var selTopic = _.findWhere(topics, { appId: appId });
34 |
35 | var appTopics = _.where(topics, { appId: appId });
36 |
37 | var widgets = [];
38 | function addWidget(widget) {
39 | widgets.push(widget);
40 | }
41 |
42 | var gaugeUsed = false;
43 |
44 | _.each(appTopics, function (topic) {
45 | var type = topic.schema.type;
46 |
47 | if (type === 'timeseries') {
48 | addWidget({
49 | name: 'Line Chart',
50 | title: 'Line Chart',
51 | dataModelOptions: {
52 | topic: topic.topic
53 | }
54 | });
55 | } else if (type === 'topN') {
56 | addWidget({
57 | name: 'TopN',
58 | title: 'Top N',
59 | dataModelOptions: {
60 | topic: topic.topic
61 | }
62 | });
63 | } else if (type === 'percentage') {
64 | if (!gaugeUsed) {
65 | addWidget({
66 | name: 'Gauge',
67 | title: 'Gauge',
68 | dataModelOptions: {
69 | topic: topic.topic
70 | }
71 | });
72 | gaugeUsed = true;
73 | } else {
74 | addWidget({
75 | name: 'Progressbar',
76 | title: 'Progressbar',
77 | dataModelOptions: {
78 | topic: topic.topic
79 | }
80 | });
81 | }
82 | } else if (type === 'piechart') {
83 | addWidget({
84 | name: 'Pie Chart',
85 | title: 'Pie Chart',
86 | dataModelOptions: {
87 | topic: topic.topic
88 | }
89 | });
90 | }
91 | });
92 |
93 | $scope.dashboardOptions.loadWidgets(widgets);
94 |
95 | notificationService.notify({
96 | title: 'Dashboard Loaded',
97 | text: 'Dashboard for application {name} ({id}) has been loaded.'
98 | .replace('{name}', selTopic.appName)
99 | .replace('{id}', selTopic.appId),
100 | type: 'success',
101 | delay: 5000,
102 | icon: false,
103 | history: false
104 | });
105 | });
106 |
107 | // initialize widgets with default topics
108 | var topicsPromise = Gateway.getTopics();
109 |
110 | $scope.$on('widgetAdded', function (event, widget) {
111 | event.stopPropagation();
112 |
113 | if (widget.dataModel && widget.dataModelOptions && widget.dataModelOptions.topic) {
114 | topicsPromise.then(function (topics) {
115 | var selTopic = widget.dataModelOptions.topic;
116 |
117 | var topic = null;
118 |
119 | if (selTopic) {
120 | topic = _.find(topics, function (topic) {
121 | return topic.topic === selTopic;
122 | });
123 | } else {
124 | var defaultTopic = widget.dataModelOptions.defaultTopic;
125 |
126 | topic = _.find(topics, function (topic) {
127 | return topic.name.indexOf(defaultTopic) >= 0;
128 | });
129 | }
130 |
131 | if (topic) {
132 | widget.dataModel.update(topic.topic);
133 | }
134 | });
135 | }
136 | });
137 | });
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/scripts/vendor/visibly.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * visibly - v0.6 Aug 2011 - Page Visibility API Polyfill
3 | * http://github.com/addyosmani
4 | * Copyright (c) 2011 Addy Osmani
5 | * Dual licensed under the MIT and GPL licenses.
6 | *
7 | * Methods supported:
8 | * visibly.onVisible(callback)
9 | * visibly.onHidden(callback)
10 | * visibly.hidden()
11 | * visibly.visibilityState()
12 | * visibly.visibilitychange(callback(state));
13 | */
14 |
15 | ;(function () {
16 |
17 | window.visibly = {
18 | q: document,
19 | p: undefined,
20 | prefixes: ['webkit', 'ms','o','moz','khtml'],
21 | props: ['VisibilityState', 'visibilitychange', 'Hidden'],
22 | m: ['focus', 'blur'],
23 | visibleCallbacks: [],
24 | hiddenCallbacks: [],
25 | genericCallbacks:[],
26 | _callbacks: [],
27 | cachedPrefix:"",
28 | fn:null,
29 |
30 | onVisible: function (_callback) {
31 | if(typeof _callback == 'function' ){
32 | this.visibleCallbacks.push(_callback);
33 | }
34 | },
35 | onHidden: function (_callback) {
36 | if(typeof _callback == 'function' ){
37 | this.hiddenCallbacks.push(_callback);
38 | }
39 | },
40 | getPrefix:function(){
41 | if(!this.cachedPrefix){
42 | for(var l=0;b=this.prefixes[l++];){
43 | if(b + this.props[2] in this.q){
44 | this.cachedPrefix = b;
45 | return this.cachedPrefix;
46 | }
47 | }
48 | }
49 | },
50 |
51 | visibilityState:function(){
52 | return this._getProp(0);
53 | },
54 | hidden:function(){
55 | return this._getProp(2);
56 | },
57 | visibilitychange:function(fn){
58 | if(typeof fn == 'function' ){
59 | this.genericCallbacks.push(fn);
60 | }
61 |
62 | var n = this.genericCallbacks.length;
63 | if(n){
64 | if(this.cachedPrefix){
65 | while(n--){
66 | this.genericCallbacks[n].call(this, this.visibilityState());
67 | }
68 | }else{
69 | while(n--){
70 | this.genericCallbacks[n].call(this, arguments[0]);
71 | }
72 | }
73 | }
74 |
75 | },
76 | isSupported: function (index) {
77 | return ((this.cachedPrefix + this.props[2]) in this.q);
78 | },
79 | _getProp:function(index){
80 | return this.q[this.cachedPrefix + this.props[index]];
81 | },
82 | _execute: function (index) {
83 | if (index) {
84 | this._callbacks = (index == 1) ? this.visibleCallbacks : this.hiddenCallbacks;
85 | var n = this._callbacks.length;
86 | while(n--){
87 | this._callbacks[n]();
88 | }
89 | }
90 | },
91 | _visible: function () {
92 | window.visibly._execute(1);
93 | window.visibly.visibilitychange.call(window.visibly, 'visible');
94 | },
95 | _hidden: function () {
96 | window.visibly._execute(2);
97 | window.visibly.visibilitychange.call(window.visibly, 'hidden');
98 | },
99 | _nativeSwitch: function () {
100 | this[this._getProp(2) ? '_hidden' : '_visible']();
101 | },
102 | _listen: function () {
103 | try { /*if no native page visibility support found..*/
104 | if (!(this.isSupported())) {
105 | if (this.q.addEventListener) { /*for browsers without focusin/out support eg. firefox, opera use focus/blur*/
106 | window.addEventListener(this.m[0], this._visible, 1);
107 | window.addEventListener(this.m[1], this._hidden, 1);
108 | } else { /*IE <10s most reliable focus events are onfocusin/onfocusout*/
109 | if (this.q.attachEvent) {
110 | this.q.attachEvent('onfocusin', this._visible);
111 | this.q.attachEvent('onfocusout', this._hidden);
112 | }
113 | }
114 | } else { /*switch support based on prefix detected earlier*/
115 | this.q.addEventListener(this.cachedPrefix + this.props[1], function () {
116 | window.visibly._nativeSwitch.apply(window.visibly, arguments);
117 | }, 1);
118 | }
119 | } catch (e) {}
120 | },
121 | init: function () {
122 | this.getPrefix();
123 | this._listen();
124 | }
125 | };
126 |
127 | this.visibly.init();
128 | })();
129 |
--------------------------------------------------------------------------------
/dist/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 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
151 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/app/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 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
151 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/scripts/services/service.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app.service')
4 | .constant('pieChartSampleData', [
5 | {
6 | key: 'One',
7 | y: 5
8 | },
9 | {
10 | key: 'Two',
11 | y: 2
12 | },
13 | {
14 | key: 'Three',
15 | y: 9
16 | },
17 | {
18 | key: 'Four',
19 | y: 7
20 | },
21 | {
22 | key: 'Five',
23 | y: 4
24 | },
25 | {
26 | key: 'Six',
27 | y: 3
28 | },
29 | {
30 | key: 'Seven',
31 | y: 7
32 | },
33 | {
34 | key: 'Eight',
35 | y: 4
36 | },
37 | {
38 | key: 'Nine',
39 | y: 3
40 | }
41 | ])
42 | .constant('stackedAreaChartSampleData', [
43 | {
44 | key: 'Series 1',
45 | values: [
46 | [ 1051675200000 , 0] ,
47 | [ 1054353600000 , 7.2481659343222] ,
48 | [ 1056945600000 , 9.2512381306992] ,
49 | [ 1059624000000 , 11.341210982529] ,
50 | [ 1062302400000 , 14.734820409020] ,
51 | [ 1064894400000 , 12.387148007542] ,
52 | [ 1067576400000 , 18.436471461827] ,
53 | [ 1070168400000 , 19.830742266977] ,
54 | [ 1072846800000 , 22.643205829887] ,
55 | [ 1075525200000 , 26.743156781239] ,
56 | [ 1078030800000 , 29.597478802228] ,
57 | [ 1080709200000 , 30.831697585341] ,
58 | [ 1083297600000 , 28.054068024708] ,
59 | [ 1085976000000 , 29.294079423832] ,
60 | [ 1088568000000 , 30.269264061274] ,
61 | [ 1091246400000 , 24.934526898906] ,
62 | [ 1093924800000 , 24.265982759406] ,
63 | [ 1096516800000 , 27.217794897473] ,
64 | [ 1099195200000 , 30.802601992077] ,
65 | [ 1101790800000 , 36.331003758254] ,
66 | [ 1104469200000 , 43.142498700060] ,
67 | [ 1107147600000 , 40.558263931958] ,
68 | [ 1109566800000 , 42.543622385800] ,
69 | [ 1112245200000 , 41.683584710331] ,
70 | [ 1114833600000 , 36.375367302328] ,
71 | [ 1117512000000 , 40.719688980730] ,
72 | [ 1120104000000 , 43.897963036919] ,
73 | [ 1122782400000 , 49.797033975368] ,
74 | [ 1125460800000 , 47.085993935989] ,
75 | [ 1128052800000 , 46.601972859745] ,
76 | [ 1130734800000 , 41.567784572762] ,
77 | [ 1133326800000 , 47.296923737245] ,
78 | [ 1136005200000 , 47.642969612080] ,
79 | [ 1138683600000 , 50.781515820954] ,
80 | [ 1141102800000 , 52.600229204305] ,
81 | [ 1143781200000 , 55.599684490628] ,
82 | [ 1146369600000 , 57.920388436633] ,
83 | [ 1149048000000 , 53.503593218971] ,
84 | [ 1151640000000 , 53.522973979964] ,
85 | [ 1154318400000 , 49.846822298548] ,
86 | [ 1156996800000 , 54.721341614650] ,
87 | [ 1159588800000 , 58.186236223191] ,
88 | [ 1162270800000 , 63.908065540997] ,
89 | [ 1164862800000 , 69.767285129367] ,
90 | [ 1167541200000 , 72.534013373592] ,
91 | [ 1170219600000 , 77.991819436573] ,
92 | [ 1172638800000 , 78.143584404990] ,
93 | [ 1175313600000 , 83.702398665233] ,
94 | [ 1177905600000 , 91.140859312418] ,
95 | [ 1180584000000 , 98.590960607028] ,
96 | [ 1183176000000 , 96.245634754228] ,
97 | [ 1185854400000 , 92.326364432615] ,
98 | [ 1188532800000 , 97.068765332230] ,
99 | [ 1191124800000 , 105.81025556260] ,
100 | [ 1193803200000 , 114.38348777791] ,
101 | [ 1196398800000 , 103.59604949810] ,
102 | [ 1199077200000 , 101.72488429307] ,
103 | [ 1201755600000 , 89.840147735028] ,
104 | [ 1204261200000 , 86.963597532664] ,
105 | [ 1206936000000 , 84.075505208491] ,
106 | [ 1209528000000 , 93.170105645831] ,
107 | [ 1212206400000 , 103.62838083121] ,
108 | [ 1214798400000 , 87.458241365091] ,
109 | [ 1217476800000 , 85.808374141319] ,
110 | [ 1220155200000 , 93.158054469193] ,
111 | [ 1222747200000 , 65.973252382360] ,
112 | [ 1225425600000 , 44.580686638224] ,
113 | [ 1228021200000 , 36.418977140128] ,
114 | [ 1230699600000 , 38.727678144761] ,
115 | [ 1233378000000 , 36.692674173387] ,
116 | [ 1235797200000 , 30.033022809480] ,
117 | [ 1238472000000 , 36.707532162718] ,
118 | [ 1241064000000 , 52.191457688389] ,
119 | [ 1243742400000 , 56.357883979735] ,
120 | [ 1246334400000 , 57.629002180305] ,
121 | [ 1249012800000 , 66.650985790166] ,
122 | [ 1251691200000 , 70.839243432186] ,
123 | [ 1254283200000 , 78.731998491499] ,
124 | [ 1256961600000 , 72.375528540349] ,
125 | [ 1259557200000 , 81.738387881630] ,
126 | [ 1262235600000 , 87.539792394232] ,
127 | [ 1264914000000 , 84.320762662273] ,
128 | [ 1267333200000 , 90.621278391889] ,
129 | [ 1270008000000 , 102.47144881651] ,
130 | [ 1272600000000 , 102.79320353429] ,
131 | [ 1275278400000 , 90.529736050479] ,
132 | [ 1277870400000 , 76.580859994531] ,
133 | [ 1280548800000 , 86.548979376972] ,
134 | [ 1283227200000 , 81.879653334089] ,
135 | [ 1285819200000 , 101.72550015956] ,
136 | [ 1288497600000 , 107.97964852260] ,
137 | [ 1291093200000 , 106.16240630785] ,
138 | [ 1293771600000 , 114.84268599533] ,
139 | [ 1296450000000 , 121.60793322282] ,
140 | [ 1298869200000 , 133.41437346605] ,
141 | [ 1301544000000 , 125.46646042904] ,
142 | [ 1304136000000 , 129.76784954301] ,
143 | [ 1306814400000 , 128.15798861044] ,
144 | [ 1309406400000 , 121.92388706072] ,
145 | [ 1312084800000 , 116.70036100870] ,
146 | [ 1314763200000 , 88.367701837033] ,
147 | [ 1317355200000 , 59.159665765725] ,
148 | [ 1320033600000 , 79.793568139753] ,
149 | [ 1322629200000 , 75.903834028417] ,
150 | [ 1325307600000 , 72.704218209157] ,
151 | [ 1327986000000 , 84.936990804097] ,
152 | [ 1330491600000 , 93.388148670744]
153 | ]
154 | }
155 | ]);
156 |
--------------------------------------------------------------------------------
/app/scripts/vendor/meteor-ddp.js:
--------------------------------------------------------------------------------
1 | /* MeteorDdp - a client for DDP version pre1 */
2 | /* Copied from https://github.com/eddflrs/meteor-ddp and wrapped into AngularJS factory */
3 |
4 | angular.module('app.service').factory('MeteorDdp', function () {
5 |
6 | var MeteorDdp = function(wsUri) {
7 | this.VERSIONS = ["pre1"];
8 |
9 | this.wsUri = wsUri;
10 | this.sock;
11 | this.defs = {}; // { deferred_id => deferred_object }
12 | this.subs = {}; // { pub_name => deferred_id }
13 | this.watchers = {}; // { coll_name => [cb1, cb2, ...] }
14 | this.collections = {}; // { coll_name => {docId => {doc}, docId => {doc}, ...} }
15 | };
16 |
17 | MeteorDdp.prototype._Ids = function() {
18 | var count = 0;
19 | return {
20 | next: function() {
21 | return ++count + '';
22 | }
23 | }
24 | }();
25 |
26 | MeteorDdp.prototype.connect = function() {
27 | var self = this;
28 | var conn = new $.Deferred();
29 |
30 | self.sock = new WebSocket(self.wsUri);
31 |
32 | self.sock.onopen = function() {
33 | self.send({
34 | msg: 'connect',
35 | version: self.VERSIONS[0],
36 | support: self.VERSIONS
37 | });
38 | };
39 |
40 | self.sock.onerror = function(err) {
41 | conn.reject(err);
42 | };
43 |
44 | self.sock.onmessage = function(msg) {
45 | var data = JSON.parse(msg.data);
46 |
47 | console.log(msg);
48 |
49 | switch (data.msg) {
50 | case 'connected':
51 | conn.resolve(data);
52 | break;
53 | case 'result':
54 | self._resolveCall(data);
55 | break;
56 | case 'updated':
57 | // TODO method call was acked
58 | break;
59 | case 'changed':
60 | self._changeDoc(data);
61 | break;
62 | case 'added':
63 | self._addDoc(data);
64 | break;
65 | case 'removed':
66 | self._removeDoc(data);
67 | break;
68 | case 'ready':
69 | self._resolveSubs(data);
70 | break;
71 | case 'nosub':
72 | self._resolveNoSub(data);
73 | break;
74 | case 'addedBefore':
75 | self._addDoc(data);
76 | break;
77 | case 'movedBefore':
78 | // TODO
79 | break;
80 | }
81 | };
82 | return conn.promise();
83 | };
84 |
85 | MeteorDdp.prototype._resolveNoSub = function(data) {
86 | if (data.error) {
87 | var error = data.error;
88 | this.defs[data.id].reject(error.reason || 'Subscription not found');
89 | } else {
90 | this.defs[data.id].resolve();
91 | }
92 | };
93 |
94 | MeteorDdp.prototype._resolveCall = function(data) {
95 | if (data.error) {
96 | this.defs[data.id].reject(data.error.reason);
97 | } else if (typeof data.result !== 'undefined') {
98 | this.defs[data.id].resolve(data.result);
99 | }
100 | };
101 |
102 | MeteorDdp.prototype._resolveSubs = function(data) {
103 | var subIds = data.subs;
104 | for (var i = 0; i < subIds.length; i++) {
105 | this.defs[subIds[i]].resolve();
106 | }
107 | };
108 |
109 | MeteorDdp.prototype._changeDoc = function(msg) {
110 | var collName = msg.collection;
111 | var id = msg.id;
112 | var fields = msg.fields;
113 | var cleared = msg.cleared;
114 | var coll = this.collections[collName];
115 |
116 | if (fields) {
117 | for (var k in fields) {
118 | coll[id][k] = fields[k];
119 | }
120 | } else if (cleared) {
121 | for (var i = 0; i < cleared.length; i++) {
122 | var fieldName = cleared[i];
123 | delete coll[id][fieldName];
124 | }
125 | }
126 |
127 | var changedDoc = coll[id];
128 | this._notifyWatchers(collName, changedDoc, id, msg.msg);
129 | };
130 |
131 | MeteorDdp.prototype._addDoc = function(msg) {
132 | var collName = msg.collection;
133 | var id = msg.id;
134 | if (!this.collections[collName]) {
135 | this.collections[collName] = {};
136 | }
137 | /* NOTE: Ordered docs will have a 'before' field containing the id of
138 | * the doc after it. If it is the last doc, it will be null.
139 | */
140 | this.collections[collName][id] = msg.fields;
141 |
142 | var changedDoc = this.collections[collName][id];
143 | this._notifyWatchers(collName, changedDoc, id, msg.msg);
144 | };
145 |
146 | MeteorDdp.prototype._removeDoc = function(msg) {
147 | var collName = msg.collection;
148 | var id = msg.id;
149 | var doc = this.collections[collName][id];
150 |
151 | var docCopy = JSON.parse(JSON.stringify(doc));
152 | delete this.collections[collName][id];
153 | this._notifyWatchers(collName, docCopy, id, msg.msg);
154 | };
155 |
156 | MeteorDdp.prototype._notifyWatchers = function(collName, changedDoc, docId, message) {
157 | changedDoc = JSON.parse(JSON.stringify(changedDoc)); // make a copy
158 | changedDoc._id = docId; // id might be useful to watchers, attach it.
159 |
160 | if (!this.watchers[collName]) {
161 | this.watchers[collName] = [];
162 | } else {
163 | for (var i = 0; i < this.watchers[collName].length; i++) {
164 | this.watchers[collName][i](changedDoc, message);
165 | }
166 | }
167 | };
168 |
169 | MeteorDdp.prototype._deferredSend = function(actionType, name, params) {
170 | var id = this._Ids.next();
171 | this.defs[id] = new $.Deferred();
172 |
173 | var args = params || [];
174 |
175 | var o = {
176 | msg: actionType,
177 | params: args,
178 | id: id
179 | };
180 |
181 | if (actionType === 'method') {
182 | o.method = name;
183 | } else if (actionType === 'sub') {
184 | o.name = name;
185 | this.subs[name] = id;
186 | }
187 |
188 | this.send(o);
189 | return this.defs[id].promise();
190 | };
191 |
192 | MeteorDdp.prototype.call = function(methodName, params) {
193 | return this._deferredSend('method', methodName, params);
194 | };
195 |
196 | MeteorDdp.prototype.subscribe = function(pubName, params) {
197 | return this._deferredSend('sub', pubName, params);
198 | };
199 |
200 | MeteorDdp.prototype.unsubscribe = function(pubName) {
201 | this.defs[id] = new $.Deferred();
202 | if (!this.subs[pubName]) {
203 | this.defs[id].reject(pubName + " was never subscribed");
204 | } else {
205 | var id = this.subs[pubName];
206 | var o = {
207 | msg: 'unsub',
208 | id: id
209 | };
210 | this.send(o);
211 | }
212 | return this.defs[id].promise();
213 | };
214 |
215 | MeteorDdp.prototype.watch = function(collectionName, cb) {
216 | if (!this.watchers[collectionName]) {
217 | this.watchers[collectionName] = [];
218 | }
219 | this.watchers[collectionName].push(cb);
220 | };
221 |
222 | MeteorDdp.prototype.getCollection = function(collectionName) {
223 | return this.collections[collectionName] || null;
224 | }
225 |
226 | MeteorDdp.prototype.getDocument = function(collectionName, docId) {
227 | return this.collections[collectionName][docId] || null;
228 | }
229 |
230 | MeteorDdp.prototype.send = function(msg) {
231 | console.log('send ' + JSON.stringify(msg));
232 | this.sock.send(JSON.stringify(msg));
233 | };
234 |
235 | MeteorDdp.prototype.close = function() {
236 | this.sock.close();
237 | };
238 |
239 | return MeteorDdp;
240 |
241 | });
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | // Generated on 2014-01-06 using generator-angular 0.5.1
2 | 'use strict';
3 |
4 | // # Globbing
5 | // for performance reasons we're only matching one level down:
6 | // 'test/spec/{,*/}*.js'
7 | // use this if you want to recursively match all subfolders:
8 | // 'test/spec/**/*.js'
9 |
10 | module.exports = function (grunt) {
11 | require('load-grunt-tasks')(grunt);
12 | require('time-grunt')(grunt);
13 |
14 | grunt.initConfig({
15 | yeoman: {
16 | // configurable paths
17 | app: require('./bower.json').appPath || 'app',
18 | dist: 'dist'
19 | },
20 | watch: {
21 | coffee: {
22 | files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
23 | tasks: ['coffee:dist']
24 | },
25 | coffeeTest: {
26 | files: ['test/spec/{,*/}*.coffee'],
27 | tasks: ['coffee:test']
28 | },
29 | less: {
30 | files: ['<%= yeoman.app %>/styles/{,*/}*.less'],
31 | tasks: ['concat:less','less:development']
32 | },
33 | livereload: {
34 | options: {
35 | livereload: '<%= connect.options.livereload %>'
36 | },
37 | files: [
38 | '<%= yeoman.app %>/{,*/}*.html',
39 | '.tmp/styles/{,*/}*.css',
40 | '{.tmp,<%= yeoman.app %>}/scripts/**/*.js',
41 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
42 | '<%= yeoman.app %>/bower_components/malhar-angular-dashboard/dist/{,*/}*.js',
43 | '<%= yeoman.app %>/bower_components/malhar-angular-dashboard/dist/{,*/}*.css',
44 | '<%= yeoman.app %>/bower_components/malhar-angular-widgets/dist/{,*/}*.js'
45 | ]
46 | }
47 | },
48 | autoprefixer: {
49 | options: ['last 1 version'],
50 | dist: {
51 | files: [{
52 | expand: true,
53 | cwd: '.tmp/styles/',
54 | src: '{,*/}*.css',
55 | dest: '.tmp/styles/'
56 | }]
57 | }
58 | },
59 | connect: {
60 | options: {
61 | port: 9000,
62 | // Change this to '0.0.0.0' to access the server from outside.
63 | hostname: 'localhost',
64 | livereload: 35729
65 | },
66 | livereload: {
67 | options: {
68 | open: true,
69 | base: [
70 | '.tmp',
71 | '<%= yeoman.app %>'
72 | ]
73 | }
74 | },
75 | test: {
76 | options: {
77 | port: 9000,
78 | base: [
79 | '.tmp',
80 | 'test',
81 | '<%= yeoman.app %>'
82 | ]
83 | }
84 | },
85 | dist: {
86 | options: {
87 | base: '<%= yeoman.dist %>'
88 | }
89 | }
90 | },
91 | clean: {
92 | dist: {
93 | files: [{
94 | dot: true,
95 | src: [
96 | '.tmp',
97 | '<%= yeoman.dist %>/*',
98 | '!<%= yeoman.dist %>/.git*'
99 | ]
100 | }]
101 | },
102 | server: '.tmp',
103 | distBower: 'dist/bower_components'
104 | },
105 | jshint: {
106 | options: {
107 | jshintrc: '.jshintrc',
108 | ignores: [
109 | '<%= yeoman.app %>/scripts/vendor/{,*/}*.js'
110 | ]
111 | },
112 | all: [
113 | 'Gruntfile.js',
114 | '<%= yeoman.app %>/scripts/{,*/}*.js'
115 | ]
116 | },
117 | coffee: {
118 | options: {
119 | sourceMap: true,
120 | sourceRoot: ''
121 | },
122 | dist: {
123 | files: [{
124 | expand: true,
125 | cwd: '<%= yeoman.app %>/scripts',
126 | src: '{,*/}*.coffee',
127 | dest: '.tmp/scripts',
128 | ext: '.js'
129 | }]
130 | },
131 | test: {
132 | files: [{
133 | expand: true,
134 | cwd: 'test/spec',
135 | src: '{,*/}*.coffee',
136 | dest: '.tmp/spec',
137 | ext: '.js'
138 | }]
139 | }
140 | },
141 | // not used since Uglify task does concat,
142 | // but still available if needed
143 | concat: {
144 | less: {
145 | src: ['<%= yeoman.app %>/styles/themes/<%= less.theme %>.less','<%= yeoman.app %>/styles/main.less'],
146 | dest: '.tmp/styles/main.less'
147 | }
148 | },
149 | rev: {
150 | dist: {
151 | files: {
152 | src: [
153 | '<%= yeoman.dist %>/scripts/{,*/}*.js',
154 | '<%= yeoman.dist %>/styles/{,*/}*.css',
155 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
156 | '<%= yeoman.dist %>/styles/fonts/*'
157 | ]
158 | }
159 | }
160 | },
161 | useminPrepare: {
162 | html: '<%= yeoman.app %>/index.html',
163 | options: {
164 | dest: '<%= yeoman.dist %>'
165 | }
166 | },
167 | usemin: {
168 | html: ['<%= yeoman.dist %>/index.html'],
169 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
170 | options: {
171 | dirs: ['<%= yeoman.dist %>']
172 | }
173 | },
174 | svgmin: {
175 | dist: {
176 | files: [{
177 | expand: true,
178 | cwd: '<%= yeoman.app %>/images',
179 | src: '{,*/}*.svg',
180 | dest: '<%= yeoman.dist %>/images'
181 | }]
182 | }
183 | },
184 | cssmin: {
185 | // By default, your `index.html` will take care of
186 | // minification. This option is pre-configured if you do not wish to use
187 | // Usemin blocks.
188 | // dist: {
189 | // files: {
190 | // '<%= yeoman.dist %>/styles/main.css': [
191 | // '.tmp/styles/{,*/}*.css',
192 | // '<%= yeoman.app %>/styles/{,*/}*.css'
193 | // ]
194 | // }
195 | // }
196 | },
197 | htmlmin: {
198 | dist: {
199 | options: {
200 | /*removeCommentsFromCDATA: true,
201 | // https://github.com/yeoman/grunt-usemin/issues/44
202 | //collapseWhitespace: true,
203 | collapseBooleanAttributes: true,
204 | removeAttributeQuotes: true,
205 | removeRedundantAttributes: true,
206 | useShortDoctype: true,
207 | removeEmptyAttributes: true,
208 | removeOptionalTags: true*/
209 | },
210 | files: [{
211 | expand: true,
212 | cwd: '<%= yeoman.app %>',
213 | src: ['*.html', 'views/*.html'],
214 | dest: '<%= yeoman.dist %>'
215 | }]
216 | }
217 | },
218 | // Put files not handled in other tasks here
219 | copy: {
220 | dist: {
221 | files: [{
222 | expand: true,
223 | dot: true,
224 | cwd: '<%= yeoman.app %>',
225 | dest: '<%= yeoman.dist %>',
226 | src: [
227 | '*.{ico,png,txt}',
228 | '.htaccess',
229 | 'bower_components/**/*',
230 | 'images/{,*/}*.{gif,webp}',
231 | 'styles/fonts/*'
232 | ]
233 | }, {
234 | expand: true,
235 | cwd: '.tmp/images',
236 | dest: '<%= yeoman.dist %>/images',
237 | src: [
238 | 'generated/*'
239 | ]
240 | }, {
241 | expand: true,
242 | cwd: '.tmp/styles',
243 | dest: '<%= yeoman.dist %>/styles',
244 | src: '{,*/}*.css'
245 | }, {
246 | expand: true,
247 | cwd: '<%= yeoman.app %>/fonts',
248 | dest: '<%= yeoman.dist %>/fonts',
249 | src: '**/*.*'
250 | }, {
251 | expand: true,
252 | cwd: '<%= yeoman.app %>/scripts',
253 | dest: '<%= yeoman.dist %>/scripts',
254 | src: '**/*.html'
255 | }, {
256 | expand: true,
257 | cwd: '<%= yeoman.app %>/template',
258 | dest: '<%= yeoman.dist %>/template',
259 | src: '**/*.html'
260 | }, {
261 | expand: true,
262 | cwd: '<%= yeoman.app %>',
263 | dest: '<%= yeoman.dist %>',
264 | src: 'settings.js'
265 | }]
266 | },
267 | styles: {
268 | expand: true,
269 | cwd: '<%= yeoman.app %>/styles',
270 | dest: '.tmp/styles/',
271 | src: '{,*/}*.css'
272 | }
273 | },
274 | concurrent: {
275 | server: [
276 | 'coffee:dist',
277 | 'copy:styles',
278 | 'concat:less'
279 | ],
280 | test: [
281 | 'coffee',
282 | 'copy:styles'
283 | ],
284 | dist: [
285 | 'coffee',
286 | 'copy:styles',
287 | 'svgmin',
288 | 'htmlmin'
289 | ]
290 | },
291 | karma: {
292 | unit: {
293 | configFile: 'karma.conf.js',
294 | singleRun: true
295 | }
296 | },
297 | cdnify: {
298 | dist: {
299 | html: ['<%= yeoman.dist %>/*.html']
300 | }
301 | },
302 | ngmin: {
303 | dist: {
304 | files: [{
305 | expand: true,
306 | cwd: '<%= yeoman.dist %>/scripts',
307 | src: '*.js',
308 | dest: '<%= yeoman.dist %>/scripts'
309 | }]
310 | }
311 | },
312 | uglify: {
313 | dist: {
314 | files: {
315 | '<%= yeoman.dist %>/scripts/scripts.js': [
316 | '<%= yeoman.dist %>/scripts/scripts.js'
317 | ]
318 | }
319 | }
320 | },
321 | less: {
322 | theme: 'default',
323 | local: {
324 | options: {
325 | paths: ['<%= yeoman.app %>/styles'],
326 | sourceMap: true
327 | },
328 | files: {
329 | '<%= yeoman.app %>/styles/main.css': ['.tmp/styles/main.less']
330 | }
331 | },
332 | development: {
333 | options: {
334 | paths: ['<%= yeoman.app %>/styles'],
335 | sourceMap: true
336 | },
337 | files: {
338 | '.tmp/styles/main.css': ['.tmp/styles/main.less']
339 | }
340 | },
341 | production: {
342 | options: {
343 | paths: ['<%= yeoman.app %>/styles']
344 | },
345 | files: {
346 | '.tmp/styles/main.css': ['.tmp/styles/main.less']
347 | }
348 | }
349 | }
350 | });
351 |
352 | grunt.registerTask('server', function (target) {
353 | if (target === 'dist') {
354 | return grunt.task.run(['build', 'connect:dist:keepalive']);
355 | }
356 |
357 | grunt.task.run([
358 | 'clean:server',
359 | 'concurrent:server',
360 | 'less:development',
361 | 'autoprefixer',
362 | 'connect:livereload',
363 | 'watch'
364 | ]);
365 | });
366 |
367 | grunt.registerTask('run', ['connect:dist:keepalive']);
368 |
369 | grunt.registerTask('test', [
370 | 'clean:server',
371 | 'concurrent:test',
372 | 'autoprefixer',
373 | 'connect:test',
374 | 'karma'
375 | ]);
376 |
377 | grunt.registerTask('build', [
378 | 'clean:dist',
379 | 'useminPrepare',
380 | 'concurrent:dist',
381 | 'concat',
382 | 'less:production',
383 | 'autoprefixer',
384 | 'copy:dist',
385 | 'cdnify',
386 | 'ngmin',
387 | 'cssmin',
388 | 'uglify',
389 | 'rev',
390 | 'usemin',
391 | 'clean:distBower'
392 | ]);
393 |
394 | grunt.registerTask('default', [
395 | 'jshint',
396 | 'test',
397 | 'build'
398 | ]);
399 | };
400 |
--------------------------------------------------------------------------------
/app/scripts/services/datamodel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('app.service', []);
4 |
5 | angular.module('app.service')
6 | .factory('RestTimeSeriesDataModel', function (settings, WidgetDataModel, $http) {
7 | function RestTimeSeriesDataModel() {
8 | }
9 |
10 | RestTimeSeriesDataModel.prototype = Object.create(WidgetDataModel.prototype);
11 |
12 | RestTimeSeriesDataModel.prototype.init = function () {
13 | WidgetDataModel.prototype.init.call(this);
14 | this.mode = this.dataModelOptions ? this.dataModelOptions.mode : 'MINUTES';
15 |
16 | this.widgetScope.$on('modeChanged', function (event, mode) {
17 | this.mode = mode;
18 | this.load();
19 | }.bind(this));
20 |
21 | this.load();
22 | };
23 |
24 | RestTimeSeriesDataModel.prototype.load = function () {
25 | var params = {
26 | bucket: this.mode,
27 | metric: this.dataModelOptions.metric
28 | };
29 |
30 | $http.get('/data', {
31 | params: params
32 | }).success(function (data) {
33 | var chart = {
34 | data: data,
35 | chartOptions: {
36 | vAxis: {}
37 | }
38 | };
39 |
40 | this.updateScope(chart);
41 | }.bind(this));
42 | };
43 |
44 | return RestTimeSeriesDataModel;
45 | })
46 | .factory('RestTopNDataModel', function (settings, WidgetDataModel, $http) {
47 | function RestTopNDataModel() {
48 | }
49 |
50 | RestTopNDataModel.prototype = Object.create(WidgetDataModel.prototype);
51 |
52 | RestTopNDataModel.prototype.init = function () {
53 | WidgetDataModel.prototype.init.call(this);
54 |
55 | this.load();
56 | };
57 |
58 | RestTopNDataModel.prototype.load = function () {
59 | $http.get('/topn', {
60 | params: {
61 | limit: this.dataModelOptions.limit,
62 | dimension: this.dataModelOptions.dimension
63 | }
64 | }).success(function (data) {
65 | this.updateScope(data);
66 | }.bind(this));
67 | };
68 |
69 | return RestTopNDataModel;
70 | })
71 | .factory('MeteorTimeSeriesDataModel', function (settings, MeteorDdp, WidgetDataModel) {
72 | function MeteorTimeSeriesDataModel() {
73 | var ddp = new MeteorDdp(settings.meteorURL); //TODO
74 | this.ddp = ddp;
75 |
76 | var that = this;
77 |
78 | ddp.connect().done(function() {
79 | console.log('Meteor connected');
80 | that.update();
81 | });
82 | }
83 |
84 | MeteorTimeSeriesDataModel.prototype = Object.create(WidgetDataModel.prototype);
85 |
86 | MeteorTimeSeriesDataModel.prototype.init = function () {
87 | WidgetDataModel.prototype.init.call(this);
88 | };
89 |
90 | //TODO
91 | MeteorTimeSeriesDataModel.prototype.update = function (collection) {
92 | this.items = [];
93 | collection = collection ? collection : this.dataModelOptions.collection;
94 |
95 | this.ddp.subscribe(collection); //TODO
96 |
97 | var that = this;
98 |
99 | this.ddp.watch(collection, function(doc, msg) {
100 | if (msg === 'added') {
101 | that.updateScope(doc);
102 | that.widgetScope.$apply();
103 | }
104 | });
105 | };
106 |
107 | MeteorTimeSeriesDataModel.prototype.updateScope = function (value) {
108 | if (value.hasOwnProperty('history')) {
109 | //console.log(_.pluck(value.history, 'timestamp'));
110 | this.items.push.apply(this.items, value.history);
111 | } else {
112 | this.items.push(value);
113 | }
114 |
115 | if (this.items.length > 100) { //TODO
116 | this.items.splice(0, this.items.length - 100);
117 | }
118 |
119 | var chart = {
120 | data: this.items,
121 | max: 30
122 | };
123 |
124 | WidgetDataModel.prototype.updateScope.call(this, chart);
125 | this.data = [];
126 | };
127 |
128 | return MeteorTimeSeriesDataModel;
129 | })
130 | .factory('MeteorDataModel', function (settings, MeteorDdp, WidgetDataModel) {
131 | function MeteorTimeSeriesDataModel() {
132 | var ddp = new MeteorDdp(settings.meteorURL); //TODO
133 | this.ddp = ddp;
134 |
135 | var that = this;
136 |
137 | ddp.connect().done(function() {
138 | console.log('Meteor connected');
139 | that.update();
140 | });
141 | }
142 |
143 | MeteorTimeSeriesDataModel.prototype = Object.create(WidgetDataModel.prototype);
144 |
145 | MeteorTimeSeriesDataModel.prototype.init = function () {
146 | WidgetDataModel.prototype.init.call(this);
147 | };
148 |
149 | //TODO
150 | MeteorTimeSeriesDataModel.prototype.update = function (collection) {
151 | this.items = [];
152 | collection = collection ? collection : this.dataModelOptions.collection;
153 |
154 | this.ddp.subscribe(collection); //TODO get whole collection instead of 'added' events
155 |
156 | var that = this;
157 |
158 | this.ddp.watch(collection, function(value) {
159 | //console.log(value);
160 | that.updateScope(value);
161 | that.widgetScope.$apply();
162 | });
163 | };
164 |
165 | return MeteorTimeSeriesDataModel;
166 | })
167 | .factory('WebSocketWidgetDataModel', function (WidgetDataModel, webSocket) {
168 | function WebSocketDataModel() {
169 | }
170 |
171 | WebSocketDataModel.prototype = Object.create(WidgetDataModel.prototype);
172 |
173 | WebSocketDataModel.prototype.init = function () {
174 | this.topic = null;
175 | this.callback = null;
176 | if (this.dataModelOptions && this.dataModelOptions.defaultTopic) {
177 | this.update(this.dataModelOptions.defaultTopic);
178 | }
179 | };
180 |
181 | WebSocketDataModel.prototype.update = function (newTopic) {
182 | var that = this;
183 |
184 | if (this.topic && this.callback) {
185 | webSocket.unsubscribe(this.topic, this.callback);
186 | }
187 |
188 | var callback = function (message) {
189 | that.updateScope(message);
190 | that.widgetScope.$apply();
191 | };
192 |
193 | this.topic = newTopic;
194 | this.callback = webSocket.subscribe(this.topic, callback, this.widgetScope);
195 | };
196 |
197 | WebSocketDataModel.prototype.destroy = function () {
198 | WidgetDataModel.prototype.destroy.call(this);
199 |
200 | if (this.topic && this.callback) {
201 | webSocket.unsubscribe(this.topic, this.callback);
202 | }
203 | };
204 |
205 | return WebSocketDataModel;
206 | })
207 | .factory('RandomValueDataModel', function (WidgetDataModel, $interval) {
208 | function RandomValueDataModel() {
209 | }
210 |
211 | RandomValueDataModel.prototype = Object.create(WidgetDataModel.prototype);
212 |
213 | RandomValueDataModel.prototype.init = function () {
214 | var base = Math.floor(Math.random() * 10) * 10;
215 |
216 | this.updateScope(base);
217 |
218 | var that = this;
219 |
220 | this.intervalPromise = $interval(function () {
221 | var random = base + Math.random();
222 | that.updateScope(random);
223 | }, 500);
224 | };
225 |
226 | RandomValueDataModel.prototype.destroy = function () {
227 | WidgetDataModel.prototype.destroy.call(this);
228 | $interval.cancel(this.intervalPromise);
229 | };
230 |
231 | return RandomValueDataModel;
232 | })
233 | .factory('RandomTopNDataModel', function (WidgetDataModel, $interval) {
234 | function RandomTopNDataModel() {
235 | }
236 |
237 | RandomTopNDataModel.prototype = Object.create(WidgetDataModel.prototype);
238 |
239 | RandomTopNDataModel.prototype.init = function () {
240 | this.intervalPromise = $interval(function () {
241 | var topTen = _.map(_.range(0, 10), function (index) {
242 | return {
243 | name: 'item' + index,
244 | value: Math.floor(Math.random() * 100)
245 | };
246 | });
247 | this.updateScope(topTen);
248 | }.bind(this), 500);
249 | };
250 |
251 | RandomTopNDataModel.prototype.destroy = function () {
252 | WidgetDataModel.prototype.destroy.call(this);
253 | $interval.cancel(this.intervalPromise);
254 | };
255 |
256 | return RandomTopNDataModel;
257 | })
258 | .factory('RandomTimeSeriesDataModel', function (WidgetDataModel, $interval) {
259 | function RandomTimeSeriesDataModel() {
260 | }
261 |
262 | RandomTimeSeriesDataModel.prototype = Object.create(WidgetDataModel.prototype);
263 |
264 | RandomTimeSeriesDataModel.prototype.init = function () {
265 | var max = 30;
266 | var data = [];
267 | var chartValue = 50;
268 |
269 | function nextValue() {
270 | chartValue += Math.random() * 40 - 20;
271 | chartValue = chartValue < 0 ? 0 : chartValue > 100 ? 100 : chartValue;
272 | return chartValue;
273 | }
274 |
275 | var now = Date.now();
276 | for (var i = max - 1; i >= 0; i--) {
277 | data.push({
278 | timestamp: now - i * 1000,
279 | value: nextValue()
280 | });
281 | }
282 | var chart = {
283 | data: data,
284 | max: max,
285 | chartOptions: {
286 | vAxis: {}
287 | }
288 | };
289 | this.updateScope(chart);
290 |
291 | this.intervalPromise = $interval(function () {
292 | data.shift();
293 | data.push({
294 | timestamp: Date.now(),
295 | value: nextValue()
296 | });
297 |
298 | var chart = {
299 | data: data,
300 | max: max
301 | };
302 |
303 | this.updateScope(chart);
304 | }.bind(this), 1000);
305 | };
306 |
307 | RandomTimeSeriesDataModel.prototype.destroy = function () {
308 | WidgetDataModel.prototype.destroy.call(this);
309 | $interval.cancel(this.intervalPromise);
310 | };
311 |
312 | return RandomTimeSeriesDataModel;
313 | })
314 | .factory('RandomD3TimeSeriesDataModel', function (WidgetDataModel, $interval) {
315 | function RandomTimeSeriesDataModel() {
316 | }
317 |
318 | RandomTimeSeriesDataModel.prototype = Object.create(WidgetDataModel.prototype);
319 |
320 | RandomTimeSeriesDataModel.prototype.init = function () {
321 | var max = 30;
322 | var data = [];
323 | var chartValue = 50;
324 |
325 | function nextValue() {
326 | chartValue += Math.round(Math.random() * 40 - 20);
327 | chartValue = chartValue < 0 ? 0 : chartValue > 100 ? 100 : chartValue;
328 | return chartValue;
329 | }
330 |
331 | var now = Date.now();
332 | for (var i = max - 1; i >= 0; i--) {
333 | data.push({
334 | timestamp: now - i * 1000,
335 | value: nextValue()
336 | });
337 | }
338 | var chart = [
339 | {
340 | 'key': 'Series',
341 | values: data
342 | }
343 | ];
344 |
345 | this.updateScope(chart);
346 |
347 | this.intervalPromise = $interval(function () {
348 | data.shift();
349 | data.push({
350 | timestamp: Date.now(),
351 | value: nextValue()
352 | });
353 |
354 | var chart = [
355 | {
356 | 'key': 'Series',
357 | values: data
358 | }
359 | ];
360 |
361 | this.updateScope(chart);
362 | }.bind(this), 1000);
363 | };
364 |
365 | RandomTimeSeriesDataModel.prototype.destroy = function () {
366 | WidgetDataModel.prototype.destroy.call(this);
367 | $interval.cancel(this.intervalPromise);
368 | };
369 |
370 | return RandomTimeSeriesDataModel;
371 | });
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2014 DataTorrent, Inc.
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/app/styles/themes/cyborg.less:
--------------------------------------------------------------------------------
1 | // Cyborg 3.0.3
2 | // Variables
3 | // --------------------------------------------------
4 |
5 |
6 | // Global values
7 | // --------------------------------------------------
8 |
9 | // Grays
10 | // -------------------------
11 |
12 | @gray-darker: #222;
13 | @gray-dark: #282828;
14 | @gray: #555;
15 | @gray-light: #888;
16 | @gray-lighter: #ADAFAE; // #eee
17 |
18 | // Brand colors
19 | // -------------------------
20 |
21 | @brand-primary: #2A9FD6;
22 | @brand-success: #77B300;
23 | @brand-warning: #FF8800;
24 | @brand-danger: #CC0000;
25 | @brand-info: #9933CC;
26 |
27 | // Scaffolding
28 | // -------------------------
29 |
30 | @body-bg: #060606;
31 | @text-color: @gray-light;
32 |
33 | // Links
34 | // -------------------------
35 |
36 | @link-color: @brand-primary;
37 | @link-hover-color: @link-color;
38 |
39 | // Typography
40 | // -------------------------
41 |
42 | @font-family-sans-serif: "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
43 | @font-family-serif: Georgia, "Times New Roman", Times, serif;
44 | @font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
45 | @font-family-base: @font-family-sans-serif;
46 |
47 | @font-size-base: 14px;
48 | @font-size-large: ceil(@font-size-base * 1.25); // ~18px
49 | @font-size-small: ceil(@font-size-base * 0.85); // ~12px
50 |
51 | @font-size-h1: floor(@font-size-base * 2.6); // ~36px
52 | @font-size-h2: floor(@font-size-base * 2.15); // ~30px
53 | @font-size-h3: ceil(@font-size-base * 1.7); // ~24px
54 | @font-size-h4: ceil(@font-size-base * 1.25); // ~18px
55 | @font-size-h5: @font-size-base;
56 | @font-size-h6: ceil(@font-size-base * 0.85); // ~12px
57 |
58 | @line-height-base: 1.428571429; // 20/14
59 | @line-height-computed: floor(@font-size-base * @line-height-base); // ~20px
60 |
61 | @headings-font-family: @font-family-base;
62 | @headings-font-weight: 500;
63 | @headings-line-height: 1.1;
64 | @headings-color: #fff;
65 |
66 |
67 | // Iconography
68 | // -------------------------
69 |
70 | @icon-font-path: "../fonts/";
71 | @icon-font-name: "glyphicons-halflings-regular";
72 |
73 |
74 | // Components
75 | // -------------------------
76 | // Based on 14px font-size and 1.428 line-height (~20px to start)
77 |
78 | @padding-base-vertical: 8px;
79 | @padding-base-horizontal: 12px;
80 |
81 | @padding-large-vertical: 14px;
82 | @padding-large-horizontal: 16px;
83 |
84 | @padding-small-vertical: 5px;
85 | @padding-small-horizontal: 10px;
86 |
87 | @padding-xs-vertical: 1px;
88 | @padding-xs-horizontal: 5px;
89 |
90 | @line-height-large: 1.33;
91 | @line-height-small: 1.5;
92 |
93 | @border-radius-base: 4px;
94 | @border-radius-large: 6px;
95 | @border-radius-small: 3px;
96 |
97 | @component-active-color: #fff;
98 | @component-active-bg: @brand-primary;
99 |
100 | @caret-width-base: 4px;
101 | @caret-width-large: 5px;
102 |
103 | // Tables
104 | // -------------------------
105 |
106 | @table-cell-padding: 8px;
107 | @table-condensed-cell-padding: 5px;
108 |
109 | @table-bg: darken(@gray-darker, 4%); // overall background-color
110 | @table-bg-accent: darken(@table-bg, 6%); // for striping
111 | @table-bg-hover: @gray-dark;
112 | @table-bg-active: @table-bg-hover;
113 |
114 | @table-border-color: @gray-dark; // table and cell border
115 |
116 |
117 | // Buttons
118 | // -------------------------
119 |
120 | @btn-font-weight: normal;
121 |
122 | @btn-default-color: #fff;
123 | @btn-default-bg: lighten(@gray-dark, 10%);
124 | @btn-default-border: @btn-default-bg;
125 |
126 | @btn-primary-color: @btn-default-color;
127 | @btn-primary-bg: @brand-primary;
128 | @btn-primary-border: @btn-primary-bg;
129 |
130 | @btn-success-color: @btn-default-color;
131 | @btn-success-bg: @brand-success;
132 | @btn-success-border: @btn-success-bg;
133 |
134 | @btn-warning-color: @btn-default-color;
135 | @btn-warning-bg: @brand-warning;
136 | @btn-warning-border: @btn-warning-bg;
137 |
138 | @btn-danger-color: @btn-default-color;
139 | @btn-danger-bg: @brand-danger;
140 | @btn-danger-border: @btn-danger-bg;
141 |
142 | @btn-info-color: @btn-default-color;
143 | @btn-info-bg: @brand-info;
144 | @btn-info-border: @btn-info-bg;
145 |
146 | @btn-link-disabled-color: @gray-light;
147 |
148 |
149 | // Forms
150 | // -------------------------
151 |
152 | @input-bg: #fff;
153 | @input-bg-disabled: @gray-lighter;
154 |
155 | @input-color: @text-color;
156 | @input-border: @gray-dark;
157 | @input-border-radius: @border-radius-base;
158 | @input-border-focus: #66afe9;
159 |
160 | @input-color-placeholder: @gray-light;
161 |
162 | @input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
163 | @input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
164 | @input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
165 |
166 | @legend-color: @text-color;
167 | @legend-border-color: @gray-dark;
168 |
169 | @input-group-addon-bg: @gray-lighter;
170 | @input-group-addon-border-color: @input-border;
171 |
172 |
173 | // Dropdowns
174 | // -------------------------
175 |
176 | @dropdown-bg: @gray-darker;
177 | @dropdown-border: rgba(255,255,255,0.1);
178 | @dropdown-fallback-border: #444;
179 | @dropdown-divider-bg: rgba(255,255,255,0.1);
180 |
181 | @dropdown-link-color: #fff;
182 | @dropdown-link-hover-color: #fff;
183 | @dropdown-link-hover-bg: @dropdown-link-active-bg;
184 |
185 | @dropdown-link-active-color: #fff;
186 | @dropdown-link-active-bg: @component-active-bg;
187 |
188 | @dropdown-link-disabled-color: @text-muted;
189 |
190 | @dropdown-header-color: @text-muted;
191 |
192 |
193 | // COMPONENT VARIABLES
194 | // --------------------------------------------------
195 |
196 |
197 | // Z-index master list
198 | // -------------------------
199 | // Used for a bird's eye view of components dependent on the z-axis
200 | // Try to avoid customizing these :)
201 |
202 | @zindex-navbar: 1000;
203 | @zindex-dropdown: 1000;
204 | @zindex-popover: 1010;
205 | @zindex-tooltip: 1030;
206 | @zindex-navbar-fixed: 1030;
207 | @zindex-modal-background: 1040;
208 | @zindex-modal: 1050;
209 |
210 | // Media queries breakpoints
211 | // --------------------------------------------------
212 |
213 | // Extra small screen / phone
214 | // Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
215 | @screen-xs: 480px;
216 | @screen-xs-min: @screen-xs;
217 | @screen-phone: @screen-xs-min;
218 |
219 | // Small screen / tablet
220 | // Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1
221 | @screen-sm: 768px;
222 | @screen-sm-min: @screen-sm;
223 | @screen-tablet: @screen-sm-min;
224 |
225 | // Medium screen / desktop
226 | // Note: Deprecated @screen-md and @screen-desktop as of v3.0.1
227 | @screen-md: 992px;
228 | @screen-md-min: @screen-md;
229 | @screen-desktop: @screen-md-min;
230 |
231 | // Large screen / wide desktop
232 | // Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1
233 | @screen-lg: 1200px;
234 | @screen-lg-min: @screen-lg;
235 | @screen-lg-desktop: @screen-lg-min;
236 |
237 | // So media queries don't overlap when required, provide a maximum
238 | @screen-xs-max: (@screen-sm-min - 1);
239 | @screen-sm-max: (@screen-md-min - 1);
240 | @screen-md-max: (@screen-lg-min - 1);
241 |
242 |
243 | // Grid system
244 | // --------------------------------------------------
245 |
246 | // Number of columns in the grid system
247 | @grid-columns: 12;
248 | // Padding, to be divided by two and applied to the left and right of all columns
249 | @grid-gutter-width: 30px;
250 |
251 | // Navbar collapse
252 |
253 | // Point at which the navbar becomes uncollapsed
254 | @grid-float-breakpoint: @screen-sm-min;
255 | // Point at which the navbar begins collapsing
256 | @grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
257 |
258 |
259 | // Navbar
260 | // -------------------------
261 |
262 | // Basics of a navbar
263 | @navbar-height: 50px;
264 | @navbar-margin-bottom: @line-height-computed;
265 | @navbar-border-radius: @border-radius-base;
266 | @navbar-padding-horizontal: floor(@grid-gutter-width / 2);
267 | @navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
268 |
269 | @navbar-default-color: @text-color;
270 | @navbar-default-bg: @body-bg;
271 | @navbar-default-border: darken(@navbar-default-bg, 6.5%);
272 |
273 | // Navbar links
274 | @navbar-default-link-color: @text-color;
275 | @navbar-default-link-hover-color: #fff;
276 | @navbar-default-link-hover-bg: transparent;
277 | @navbar-default-link-active-color: #fff;
278 | @navbar-default-link-active-bg: transparent;
279 | @navbar-default-link-disabled-color: @gray-light;
280 | @navbar-default-link-disabled-bg: transparent;
281 |
282 | // Navbar brand label
283 | @navbar-default-brand-color: #fff;
284 | @navbar-default-brand-hover-color: #fff;
285 | @navbar-default-brand-hover-bg: transparent;
286 |
287 | // Navbar toggle
288 | @navbar-default-toggle-hover-bg: @gray-dark;
289 | @navbar-default-toggle-icon-bar-bg: #ccc;
290 | @navbar-default-toggle-border-color: @gray-dark;
291 |
292 |
293 | // Inverted navbar
294 | //
295 | // Reset inverted navbar basics
296 | @navbar-inverse-color: @gray-light;
297 | @navbar-inverse-bg: @gray-darker;
298 | @navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
299 |
300 | // Inverted navbar links
301 | @navbar-inverse-link-color: @gray-light;
302 | @navbar-inverse-link-hover-color: #fff;
303 | @navbar-inverse-link-hover-bg: transparent;
304 | @navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
305 | @navbar-inverse-link-active-bg: transparent;
306 | @navbar-inverse-link-disabled-color: #aaa;
307 | @navbar-inverse-link-disabled-bg: transparent;
308 |
309 | // Inverted navbar brand label
310 | @navbar-inverse-brand-color: #fff;
311 | @navbar-inverse-brand-hover-color: #fff;
312 | @navbar-inverse-brand-hover-bg: transparent;
313 |
314 | // Inverted navbar toggle
315 | @navbar-inverse-toggle-hover-bg: #333;
316 | @navbar-inverse-toggle-icon-bar-bg: #fff;
317 | @navbar-inverse-toggle-border-color: #333;
318 |
319 |
320 | // Navs
321 | // -------------------------
322 |
323 | @nav-link-padding: 10px 15px;
324 | @nav-link-hover-bg: @gray-darker;
325 |
326 | @nav-disabled-link-color: @gray-light;
327 | @nav-disabled-link-hover-color: @gray-light;
328 |
329 | @nav-open-link-hover-color: @gray-darker;
330 |
331 | // Tabs
332 | @nav-tabs-border-color: @gray-dark;
333 |
334 | @nav-tabs-link-hover-border-color: transparent;
335 |
336 | @nav-tabs-active-link-hover-bg: @brand-primary;
337 | @nav-tabs-active-link-hover-color: #fff;
338 | @nav-tabs-active-link-hover-border-color: @gray-dark;
339 |
340 | @nav-tabs-justified-link-border-color: #ddd;
341 | @nav-tabs-justified-active-link-border-color: @body-bg;
342 |
343 | // Pills
344 | @nav-pills-border-radius: @border-radius-base;
345 | @nav-pills-active-link-hover-bg: @component-active-bg;
346 | @nav-pills-active-link-hover-color: @component-active-color;
347 |
348 |
349 | // Pagination
350 | // -------------------------
351 |
352 | @pagination-bg: @gray-darker;
353 | @pagination-border: @gray-dark;
354 |
355 | @pagination-hover-bg: @component-active-bg;
356 |
357 | @pagination-active-bg: @brand-primary;
358 | @pagination-active-color: #fff;
359 |
360 | @pagination-disabled-color: @gray-light;
361 |
362 |
363 | // Pager
364 | // -------------------------
365 |
366 | @pager-border-radius: 15px;
367 | @pager-disabled-color: @gray-light;
368 |
369 |
370 | // Jumbotron
371 | // -------------------------
372 |
373 | @jumbotron-padding: 30px;
374 | @jumbotron-color: inherit;
375 | @jumbotron-bg: darken(@gray-darker, 5%);
376 | @jumbotron-heading-color: inherit;
377 | @jumbotron-font-size: ceil(@font-size-base * 1.5);
378 |
379 |
380 | // Form states and alerts
381 | // -------------------------
382 |
383 | @state-success-text: #fff;
384 | @state-success-bg: @brand-success;
385 | @state-success-border: darken(spin(@state-success-bg, -10), 5%);
386 |
387 | @state-info-text: #fff;
388 | @state-info-bg: @brand-info;
389 | @state-info-border: darken(spin(@state-info-bg, -10), 7%);
390 |
391 | @state-warning-text: #fff;
392 | @state-warning-bg: @brand-warning;
393 | @state-warning-border: darken(spin(@state-warning-bg, -10), 3%);
394 |
395 | @state-danger-text: #fff;
396 | @state-danger-bg: @brand-danger;
397 | @state-danger-border: darken(spin(@state-danger-bg, -10), 3%);
398 |
399 |
400 | // Tooltips
401 | // -------------------------
402 | @tooltip-max-width: 200px;
403 | @tooltip-color: #fff;
404 | @tooltip-bg: rgba(0,0,0,.9);
405 |
406 | @tooltip-arrow-width: 5px;
407 | @tooltip-arrow-color: @tooltip-bg;
408 |
409 |
410 | // Popovers
411 | // -------------------------
412 | @popover-bg: lighten(@body-bg, 10%);
413 | @popover-max-width: 276px;
414 | @popover-border-color: rgba(0,0,0,.2);
415 | @popover-fallback-border-color: #999;
416 |
417 | @popover-title-bg: darken(@popover-bg, 3%);
418 |
419 | @popover-arrow-width: 10px;
420 | @popover-arrow-color: @popover-bg;
421 |
422 | @popover-arrow-outer-width: (@popover-arrow-width + 1);
423 | @popover-arrow-outer-color: rgba(0,0,0,.25);
424 | @popover-arrow-outer-fallback-color: #999;
425 |
426 |
427 | // Labels
428 | // -------------------------
429 |
430 | @label-default-bg: @btn-default-bg;
431 | @label-primary-bg: @brand-primary;
432 | @label-success-bg: @brand-success;
433 | @label-info-bg: @brand-info;
434 | @label-warning-bg: @brand-warning;
435 | @label-danger-bg: @brand-danger;
436 |
437 | @label-color: #fff;
438 | @label-link-hover-color: #fff;
439 |
440 |
441 | // Modals
442 | // -------------------------
443 | @modal-inner-padding: 20px;
444 |
445 | @modal-title-padding: 15px;
446 | @modal-title-line-height: @line-height-base;
447 |
448 | @modal-content-bg: lighten(@body-bg, 10%);
449 | @modal-content-border-color: rgba(0,0,0,.2);
450 | @modal-content-fallback-border-color: #999;
451 |
452 | @modal-backdrop-bg: #000;
453 | @modal-header-border-color: @gray-dark;
454 | @modal-footer-border-color: @modal-header-border-color;
455 |
456 |
457 | // Alerts
458 | // -------------------------
459 | @alert-padding: 15px;
460 | @alert-border-radius: @border-radius-base;
461 | @alert-link-font-weight: bold;
462 |
463 | @alert-success-bg: @state-success-bg;
464 | @alert-success-text: @state-success-text;
465 | @alert-success-border: @state-success-border;
466 |
467 | @alert-info-bg: @state-info-bg;
468 | @alert-info-text: @state-info-text;
469 | @alert-info-border: @state-info-border;
470 |
471 | @alert-warning-bg: @state-warning-bg;
472 | @alert-warning-text: @state-warning-text;
473 | @alert-warning-border: @state-warning-border;
474 |
475 | @alert-danger-bg: @state-danger-bg;
476 | @alert-danger-text: @state-danger-text;
477 | @alert-danger-border: @state-danger-border;
478 |
479 |
480 | // Progress bars
481 | // -------------------------
482 | @progress-bg: @gray-darker;
483 | @progress-bar-color: #fff;
484 |
485 | @progress-bar-bg: @brand-primary;
486 | @progress-bar-success-bg: @brand-success;
487 | @progress-bar-warning-bg: @brand-warning;
488 | @progress-bar-danger-bg: @brand-danger;
489 | @progress-bar-info-bg: @brand-info;
490 |
491 |
492 | // List group
493 | // -------------------------
494 | @list-group-bg: @gray-darker;
495 | @list-group-border: @gray-dark;
496 | @list-group-border-radius: @border-radius-base;
497 |
498 | @list-group-hover-bg: lighten(@list-group-bg, 15%);
499 | @list-group-active-color: @component-active-color;
500 | @list-group-active-bg: @component-active-bg;
501 | @list-group-active-border: @list-group-active-bg;
502 |
503 | @list-group-link-color: @text-color;
504 | @list-group-link-heading-color: #fff;
505 |
506 |
507 | // Panels
508 | // -------------------------
509 | @panel-bg: @gray-darker;
510 | @panel-inner-border: @gray-dark;
511 | @panel-border-radius: @border-radius-base;
512 | @panel-footer-bg: @panel-default-heading-bg;
513 |
514 | @panel-default-text: @text-color;
515 | @panel-default-border: @panel-inner-border;
516 | @panel-default-heading-bg: lighten(@gray-darker, 10%);
517 |
518 | @panel-primary-text: #fff;
519 | @panel-primary-border: @brand-primary;
520 | @panel-primary-heading-bg: @brand-primary;
521 |
522 | @panel-success-text: @state-success-text;
523 | @panel-success-border: @state-success-border;
524 | @panel-success-heading-bg: @state-success-bg;
525 |
526 | @panel-warning-text: @state-warning-text;
527 | @panel-warning-border: @state-warning-border;
528 | @panel-warning-heading-bg: @state-warning-bg;
529 |
530 | @panel-danger-text: @state-danger-text;
531 | @panel-danger-border: @state-danger-border;
532 | @panel-danger-heading-bg: @state-danger-bg;
533 |
534 | @panel-info-text: @state-info-text;
535 | @panel-info-border: @state-info-border;
536 | @panel-info-heading-bg: @state-info-bg;
537 |
538 |
539 | // Thumbnails
540 | // -------------------------
541 | @thumbnail-padding: 4px;
542 | @thumbnail-bg: @body-bg;
543 | @thumbnail-border: #ddd;
544 | @thumbnail-border-radius: @border-radius-base;
545 |
546 | @thumbnail-caption-color: @text-color;
547 | @thumbnail-caption-padding: 9px;
548 |
549 |
550 | // Wells
551 | // -------------------------
552 | @well-bg: darken(@gray-darker, 5%);
553 |
554 |
555 | // Badges
556 | // -------------------------
557 | @badge-color: #fff;
558 | @badge-link-hover-color: #fff;
559 | @badge-bg: @brand-primary;
560 |
561 | @badge-active-color: @brand-primary;
562 | @badge-active-bg: #fff;
563 |
564 | @badge-font-weight: bold;
565 | @badge-line-height: 1;
566 | @badge-border-radius: 10px;
567 |
568 |
569 | // Breadcrumbs
570 | // -------------------------
571 | @breadcrumb-bg: @gray-darker;
572 | @breadcrumb-color: #fff;
573 | @breadcrumb-active-color: @text-color;
574 | @breadcrumb-separator: "/";
575 |
576 |
577 | // Carousel
578 | // ------------------------
579 |
580 | @carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
581 |
582 | @carousel-control-color: #fff;
583 | @carousel-control-width: 15%;
584 | @carousel-control-opacity: .5;
585 | @carousel-control-font-size: 20px;
586 |
587 | @carousel-indicator-active-bg: #fff;
588 | @carousel-indicator-border-color: #fff;
589 |
590 | @carousel-caption-color: #fff;
591 |
592 |
593 | // Close
594 | // ------------------------
595 | @close-font-weight: bold;
596 | @close-color: #000;
597 | @close-text-shadow: 0 1px 0 #fff;
598 |
599 |
600 | // Code
601 | // ------------------------
602 | @code-color: #c7254e;
603 | @code-bg: #f9f2f4;
604 |
605 | @pre-bg: #f5f5f5;
606 | @pre-color: @gray-dark;
607 | @pre-border-color: #ccc;
608 | @pre-scrollable-max-height: 340px;
609 |
610 | // Type
611 | // ------------------------
612 | @text-muted: @gray-light;
613 | @abbr-border-color: @gray-light;
614 | @headings-small-color: @gray-light;
615 | @blockquote-small-color: @gray;
616 | @blockquote-border-color: @gray-dark;
617 | @page-header-border-color: @gray-dark;
618 |
619 | // Miscellaneous
620 | // -------------------------
621 |
622 | // Hr border color
623 | @hr-border: @gray-dark;
624 |
625 | // Horizontal forms & lists
626 | @component-offset-horizontal: 180px;
627 |
628 |
629 | // Container sizes
630 | // --------------------------------------------------
631 |
632 | // Small screen / tablet
633 | @container-tablet: ((720px + @grid-gutter-width));
634 | @container-sm: @container-tablet;
635 |
636 | // Medium screen / desktop
637 | @container-desktop: ((940px + @grid-gutter-width));
638 | @container-md: @container-desktop;
639 |
640 | // Large screen / wide desktop
641 | @container-large-desktop: ((1140px + @grid-gutter-width));
642 | @container-lg: @container-large-desktop;
643 |
--------------------------------------------------------------------------------
/app/styles/themes/default.less:
--------------------------------------------------------------------------------
1 | //
2 | // Variables
3 | // --------------------------------------------------
4 |
5 |
6 | // Global values
7 | // --------------------------------------------------
8 |
9 | // Grays
10 | // -------------------------
11 |
12 | @gray-darker: lighten(#000, 13.5%); // #222
13 | @gray-dark: lighten(#000, 20%); // #333
14 | @gray: lighten(#000, 33.5%); // #555
15 | @gray-light: lighten(#000, 60%); // #999
16 | @gray-lighter: lighten(#000, 93.5%); // #eee
17 |
18 | // Brand colors
19 | // -------------------------
20 |
21 | @brand-primary: #0F5E83;
22 | @brand-success: #5cb85c;
23 | @brand-warning: #f0ad4e;
24 | @brand-danger: #d9534f;
25 | @brand-info: #5bc0de;
26 |
27 | // Scaffolding
28 | // -------------------------
29 |
30 | @body-bg: #fff;
31 | @text-color: @gray-dark;
32 |
33 | // Links
34 | // -------------------------
35 |
36 | @link-color: @brand-primary;
37 | @link-hover-color: darken(@link-color, 15%);
38 |
39 | // Typography
40 | // -------------------------
41 |
42 | @font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
43 | @font-family-serif: Georgia, "Times New Roman", Times, serif;
44 | @font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
45 | @font-family-base: @font-family-sans-serif;
46 |
47 | @font-size-base: 14px;
48 | @font-size-large: ceil(@font-size-base * 1.25); // ~18px
49 | @font-size-small: ceil(@font-size-base * 0.85); // ~12px
50 |
51 | @font-size-h1: floor(@font-size-base * 2.6); // ~36px
52 | @font-size-h2: floor(@font-size-base * 2.15); // ~30px
53 | @font-size-h3: ceil(@font-size-base * 1.7); // ~24px
54 | @font-size-h4: ceil(@font-size-base * 1.25); // ~18px
55 | @font-size-h5: @font-size-base;
56 | @font-size-h6: ceil(@font-size-base * 0.85); // ~12px
57 |
58 | @line-height-base: 1.428571429; // 20/14
59 | @line-height-computed: floor(@font-size-base * @line-height-base); // ~20px
60 |
61 | @headings-font-family: @font-family-base;
62 | @headings-font-weight: 500;
63 | @headings-line-height: 1.1;
64 | @headings-color: inherit;
65 |
66 |
67 | // Iconography
68 | // -------------------------
69 |
70 | @icon-font-path: "../../bower_components/bootstrap/dist/fonts/";
71 | @icon-font-name: "glyphicons-halflings-regular";
72 |
73 |
74 | // Components
75 | // -------------------------
76 | // Based on 14px font-size and 1.428 line-height (~20px to start)
77 |
78 | @padding-base-vertical: 6px;
79 | @padding-base-horizontal: 12px;
80 |
81 | @padding-large-vertical: 10px;
82 | @padding-large-horizontal: 16px;
83 |
84 | @padding-small-vertical: 5px;
85 | @padding-small-horizontal: 10px;
86 |
87 | @padding-xs-vertical: 1px;
88 | @padding-xs-horizontal: 5px;
89 |
90 | @line-height-large: 1.33;
91 | @line-height-small: 1.5;
92 |
93 | @border-radius-base: 4px;
94 | @border-radius-large: 6px;
95 | @border-radius-small: 3px;
96 |
97 | @component-active-color: #fff;
98 | @component-active-bg: @brand-primary;
99 |
100 | @caret-width-base: 4px;
101 | @caret-width-large: 5px;
102 |
103 | // Tables
104 | // -------------------------
105 |
106 | @table-cell-padding: 8px;
107 | @table-condensed-cell-padding: 5px;
108 |
109 | @table-bg: transparent; // overall background-color
110 | @table-bg-accent: #f9f9f9; // for striping
111 | @table-bg-hover: #f5f5f5;
112 | @table-bg-active: @table-bg-hover;
113 |
114 | @table-border-color: #ddd; // table and cell border
115 |
116 |
117 | // Buttons
118 | // -------------------------
119 |
120 | @btn-font-weight: normal;
121 |
122 | @btn-default-color: #333;
123 | @btn-default-bg: #fff;
124 | @btn-default-border: #ccc;
125 |
126 | @btn-primary-color: #fff;
127 | @btn-primary-bg: @brand-primary;
128 | @btn-primary-border: darken(@btn-primary-bg, 5%);
129 |
130 | @btn-success-color: #fff;
131 | @btn-success-bg: @brand-success;
132 | @btn-success-border: darken(@btn-success-bg, 5%);
133 |
134 | @btn-warning-color: #fff;
135 | @btn-warning-bg: @brand-warning;
136 | @btn-warning-border: darken(@btn-warning-bg, 5%);
137 |
138 | @btn-danger-color: #fff;
139 | @btn-danger-bg: @brand-danger;
140 | @btn-danger-border: darken(@btn-danger-bg, 5%);
141 |
142 | @btn-info-color: #fff;
143 | @btn-info-bg: @brand-info;
144 | @btn-info-border: darken(@btn-info-bg, 5%);
145 |
146 | @btn-link-disabled-color: @gray-light;
147 |
148 |
149 | // Forms
150 | // -------------------------
151 |
152 | @input-bg: #fff;
153 | @input-bg-disabled: @gray-lighter;
154 |
155 | @input-color: @gray;
156 | @input-border: #ccc;
157 | @input-border-radius: @border-radius-base;
158 | @input-border-focus: #66afe9;
159 |
160 | @input-color-placeholder: @gray-light;
161 |
162 | @input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
163 | @input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
164 | @input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
165 |
166 | @legend-color: @gray-dark;
167 | @legend-border-color: #e5e5e5;
168 |
169 | @input-group-addon-bg: @gray-lighter;
170 | @input-group-addon-border-color: @input-border;
171 |
172 |
173 | // Dropdowns
174 | // -------------------------
175 |
176 | @dropdown-bg: #fff;
177 | @dropdown-border: rgba(0,0,0,.15);
178 | @dropdown-fallback-border: #ccc;
179 | @dropdown-divider-bg: #e5e5e5;
180 |
181 | @dropdown-link-color: @gray-dark;
182 | @dropdown-link-hover-color: darken(@gray-dark, 5%);
183 | @dropdown-link-hover-bg: #f5f5f5;
184 |
185 | @dropdown-link-active-color: @component-active-color;
186 | @dropdown-link-active-bg: @component-active-bg;
187 |
188 | @dropdown-link-disabled-color: @gray-light;
189 |
190 | @dropdown-header-color: @gray-light;
191 |
192 |
193 | // COMPONENT VARIABLES
194 | // --------------------------------------------------
195 |
196 |
197 | // Z-index master list
198 | // -------------------------
199 | // Used for a bird's eye view of components dependent on the z-axis
200 | // Try to avoid customizing these :)
201 |
202 | @zindex-navbar: 1000;
203 | @zindex-dropdown: 1000;
204 | @zindex-popover: 1010;
205 | @zindex-tooltip: 1030;
206 | @zindex-navbar-fixed: 1030;
207 | @zindex-modal-background: 1040;
208 | @zindex-modal: 1050;
209 |
210 | // Media queries breakpoints
211 | // --------------------------------------------------
212 |
213 | // Extra small screen / phone
214 | // Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
215 | @screen-xs: 480px;
216 | @screen-xs-min: @screen-xs;
217 | @screen-phone: @screen-xs-min;
218 |
219 | // Small screen / tablet
220 | // Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1
221 | @screen-sm: 768px;
222 | @screen-sm-min: @screen-sm;
223 | @screen-tablet: @screen-sm-min;
224 |
225 | // Medium screen / desktop
226 | // Note: Deprecated @screen-md and @screen-desktop as of v3.0.1
227 | @screen-md: 992px;
228 | @screen-md-min: @screen-md;
229 | @screen-desktop: @screen-md-min;
230 |
231 | // Large screen / wide desktop
232 | // Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1
233 | @screen-lg: 1200px;
234 | @screen-lg-min: @screen-lg;
235 | @screen-lg-desktop: @screen-lg-min;
236 |
237 | // So media queries don't overlap when required, provide a maximum
238 | @screen-xs-max: (@screen-sm-min - 1);
239 | @screen-sm-max: (@screen-md-min - 1);
240 | @screen-md-max: (@screen-lg-min - 1);
241 |
242 |
243 | // Grid system
244 | // --------------------------------------------------
245 |
246 | // Number of columns in the grid system
247 | @grid-columns: 12;
248 | // Padding, to be divided by two and applied to the left and right of all columns
249 | @grid-gutter-width: 30px;
250 |
251 | // Navbar collapse
252 |
253 | // Point at which the navbar becomes uncollapsed
254 | @grid-float-breakpoint: @screen-sm-min;
255 | // Point at which the navbar begins collapsing
256 | @grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
257 |
258 |
259 | // Navbar
260 | // -------------------------
261 |
262 | // Basics of a navbar
263 | @navbar-height: 50px;
264 | @navbar-margin-bottom: @line-height-computed;
265 | @navbar-border-radius: @border-radius-base;
266 | @navbar-padding-horizontal: floor(@grid-gutter-width / 2);
267 | @navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
268 |
269 | @navbar-default-color: #777;
270 | @navbar-default-bg: #f8f8f8;
271 | @navbar-default-border: darken(@navbar-default-bg, 6.5%);
272 |
273 | // Navbar links
274 | @navbar-default-link-color: #777;
275 | @navbar-default-link-hover-color: #333;
276 | @navbar-default-link-hover-bg: transparent;
277 | @navbar-default-link-active-color: #555;
278 | @navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
279 | @navbar-default-link-disabled-color: #ccc;
280 | @navbar-default-link-disabled-bg: transparent;
281 |
282 | // Navbar brand label
283 | @navbar-default-brand-color: @navbar-default-link-color;
284 | @navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);
285 | @navbar-default-brand-hover-bg: transparent;
286 |
287 | // Navbar toggle
288 | @navbar-default-toggle-hover-bg: #ddd;
289 | @navbar-default-toggle-icon-bar-bg: #ccc;
290 | @navbar-default-toggle-border-color: #ddd;
291 |
292 |
293 | // Inverted navbar
294 | //
295 | // Reset inverted navbar basics
296 | @navbar-inverse-color: @gray-light;
297 | @navbar-inverse-bg: #222;
298 | @navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
299 |
300 | // Inverted navbar links
301 | @navbar-inverse-link-color: @gray-light;
302 | @navbar-inverse-link-hover-color: #fff;
303 | @navbar-inverse-link-hover-bg: transparent;
304 | @navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
305 | @navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
306 | @navbar-inverse-link-disabled-color: #444;
307 | @navbar-inverse-link-disabled-bg: transparent;
308 |
309 | // Inverted navbar brand label
310 | @navbar-inverse-brand-color: @navbar-inverse-link-color;
311 | @navbar-inverse-brand-hover-color: #fff;
312 | @navbar-inverse-brand-hover-bg: transparent;
313 |
314 | // Inverted navbar toggle
315 | @navbar-inverse-toggle-hover-bg: #333;
316 | @navbar-inverse-toggle-icon-bar-bg: #fff;
317 | @navbar-inverse-toggle-border-color: #333;
318 |
319 |
320 | // Navs
321 | // -------------------------
322 |
323 | @nav-link-padding: 10px 15px;
324 | @nav-link-hover-bg: @gray-lighter;
325 |
326 | @nav-disabled-link-color: @gray-light;
327 | @nav-disabled-link-hover-color: @gray-light;
328 |
329 | @nav-open-link-hover-color: #fff;
330 |
331 | // Tabs
332 | @nav-tabs-border-color: #ddd;
333 |
334 | @nav-tabs-link-hover-border-color: @gray-lighter;
335 |
336 | @nav-tabs-active-link-hover-bg: @body-bg;
337 | @nav-tabs-active-link-hover-color: @gray;
338 | @nav-tabs-active-link-hover-border-color: #ddd;
339 |
340 | @nav-tabs-justified-link-border-color: #ddd;
341 | @nav-tabs-justified-active-link-border-color: @body-bg;
342 |
343 | // Pills
344 | @nav-pills-border-radius: @border-radius-base;
345 | @nav-pills-active-link-hover-bg: @component-active-bg;
346 | @nav-pills-active-link-hover-color: @component-active-color;
347 |
348 |
349 | // Pagination
350 | // -------------------------
351 |
352 | @pagination-bg: #fff;
353 | @pagination-border: #ddd;
354 |
355 | @pagination-hover-bg: @gray-lighter;
356 |
357 | @pagination-active-bg: @brand-primary;
358 | @pagination-active-color: #fff;
359 |
360 | @pagination-disabled-color: @gray-light;
361 |
362 |
363 | // Pager
364 | // -------------------------
365 |
366 | @pager-border-radius: 15px;
367 | @pager-disabled-color: @gray-light;
368 |
369 |
370 | // Jumbotron
371 | // -------------------------
372 |
373 | @jumbotron-padding: 30px;
374 | @jumbotron-color: inherit;
375 | @jumbotron-bg: @gray-lighter;
376 | @jumbotron-heading-color: inherit;
377 | @jumbotron-font-size: ceil(@font-size-base * 1.5);
378 |
379 |
380 | // Form states and alerts
381 | // -------------------------
382 |
383 | @state-success-text: #3c763d;
384 | @state-success-bg: #dff0d8;
385 | @state-success-border: darken(spin(@state-success-bg, -10), 5%);
386 |
387 | @state-info-text: #31708f;
388 | @state-info-bg: #d9edf7;
389 | @state-info-border: darken(spin(@state-info-bg, -10), 7%);
390 |
391 | @state-warning-text: #8a6d3b;
392 | @state-warning-bg: #fcf8e3;
393 | @state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
394 |
395 | @state-danger-text: #a94442;
396 | @state-danger-bg: #f2dede;
397 | @state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
398 |
399 |
400 | // Tooltips
401 | // -------------------------
402 | @tooltip-max-width: 200px;
403 | @tooltip-color: #fff;
404 | @tooltip-bg: #000;
405 |
406 | @tooltip-arrow-width: 5px;
407 | @tooltip-arrow-color: @tooltip-bg;
408 |
409 |
410 | // Popovers
411 | // -------------------------
412 | @popover-bg: #fff;
413 | @popover-max-width: 276px;
414 | @popover-border-color: rgba(0,0,0,.2);
415 | @popover-fallback-border-color: #ccc;
416 |
417 | @popover-title-bg: darken(@popover-bg, 3%);
418 |
419 | @popover-arrow-width: 10px;
420 | @popover-arrow-color: #fff;
421 |
422 | @popover-arrow-outer-width: (@popover-arrow-width + 1);
423 | @popover-arrow-outer-color: rgba(0,0,0,.25);
424 | @popover-arrow-outer-fallback-color: #999;
425 |
426 |
427 | // Labels
428 | // -------------------------
429 |
430 | @label-default-bg: @gray-light;
431 | @label-primary-bg: @brand-primary;
432 | @label-success-bg: @brand-success;
433 | @label-info-bg: @brand-info;
434 | @label-warning-bg: @brand-warning;
435 | @label-danger-bg: @brand-danger;
436 |
437 | @label-color: #fff;
438 | @label-link-hover-color: #fff;
439 |
440 |
441 | // Modals
442 | // -------------------------
443 | @modal-inner-padding: 20px;
444 |
445 | @modal-title-padding: 15px;
446 | @modal-title-line-height: @line-height-base;
447 |
448 | @modal-content-bg: #fff;
449 | @modal-content-border-color: rgba(0,0,0,.2);
450 | @modal-content-fallback-border-color: #999;
451 |
452 | @modal-backdrop-bg: #000;
453 | @modal-header-border-color: #e5e5e5;
454 | @modal-footer-border-color: @modal-header-border-color;
455 |
456 |
457 | // Alerts
458 | // -------------------------
459 | @alert-padding: 15px;
460 | @alert-border-radius: @border-radius-base;
461 | @alert-link-font-weight: bold;
462 |
463 | @alert-success-bg: @state-success-bg;
464 | @alert-success-text: @state-success-text;
465 | @alert-success-border: @state-success-border;
466 |
467 | @alert-info-bg: @state-info-bg;
468 | @alert-info-text: @state-info-text;
469 | @alert-info-border: @state-info-border;
470 |
471 | @alert-warning-bg: @state-warning-bg;
472 | @alert-warning-text: @state-warning-text;
473 | @alert-warning-border: @state-warning-border;
474 |
475 | @alert-danger-bg: @state-danger-bg;
476 | @alert-danger-text: @state-danger-text;
477 | @alert-danger-border: @state-danger-border;
478 |
479 |
480 | // Progress bars
481 | // -------------------------
482 | @progress-bg: #f5f5f5;
483 | @progress-bar-color: #fff;
484 |
485 | @progress-bar-bg: @brand-primary;
486 | @progress-bar-success-bg: @brand-success;
487 | @progress-bar-warning-bg: @brand-warning;
488 | @progress-bar-danger-bg: @brand-danger;
489 | @progress-bar-info-bg: @brand-info;
490 |
491 |
492 | // List group
493 | // -------------------------
494 | @list-group-bg: #fff;
495 | @list-group-border: #ddd;
496 | @list-group-border-radius: @border-radius-base;
497 |
498 | @list-group-hover-bg: #f5f5f5;
499 | @list-group-active-color: @component-active-color;
500 | @list-group-active-bg: @component-active-bg;
501 | @list-group-active-border: @list-group-active-bg;
502 |
503 | @list-group-link-color: #555;
504 | @list-group-link-heading-color: #333;
505 |
506 |
507 | // Panels
508 | // -------------------------
509 | @panel-bg: #fff;
510 | @panel-inner-border: #ddd;
511 | @panel-border-radius: @border-radius-base;
512 | @panel-footer-bg: #f5f5f5;
513 |
514 | @panel-default-text: @gray-dark;
515 | @panel-default-border: #ddd;
516 | @panel-default-heading-bg: #f5f5f5;
517 |
518 | @panel-primary-text: #fff;
519 | @panel-primary-border: @brand-primary;
520 | @panel-primary-heading-bg: @brand-primary;
521 |
522 | @panel-success-text: @state-success-text;
523 | @panel-success-border: @state-success-border;
524 | @panel-success-heading-bg: @state-success-bg;
525 |
526 | @panel-warning-text: @state-warning-text;
527 | @panel-warning-border: @state-warning-border;
528 | @panel-warning-heading-bg: @state-warning-bg;
529 |
530 | @panel-danger-text: @state-danger-text;
531 | @panel-danger-border: @state-danger-border;
532 | @panel-danger-heading-bg: @state-danger-bg;
533 |
534 | @panel-info-text: @state-info-text;
535 | @panel-info-border: @state-info-border;
536 | @panel-info-heading-bg: @state-info-bg;
537 |
538 |
539 | // Thumbnails
540 | // -------------------------
541 | @thumbnail-padding: 4px;
542 | @thumbnail-bg: @body-bg;
543 | @thumbnail-border: #ddd;
544 | @thumbnail-border-radius: @border-radius-base;
545 |
546 | @thumbnail-caption-color: @text-color;
547 | @thumbnail-caption-padding: 9px;
548 |
549 |
550 | // Wells
551 | // -------------------------
552 | @well-bg: #f5f5f5;
553 |
554 |
555 | // Badges
556 | // -------------------------
557 | @badge-color: #fff;
558 | @badge-link-hover-color: #fff;
559 | @badge-bg: @gray-light;
560 |
561 | @badge-active-color: @link-color;
562 | @badge-active-bg: #fff;
563 |
564 | @badge-font-weight: bold;
565 | @badge-line-height: 1;
566 | @badge-border-radius: 10px;
567 |
568 |
569 | // Breadcrumbs
570 | // -------------------------
571 | @breadcrumb-bg: #f5f5f5;
572 | @breadcrumb-color: #ccc;
573 | @breadcrumb-active-color: @gray-light;
574 | @breadcrumb-separator: "/";
575 |
576 |
577 | // Carousel
578 | // ------------------------
579 |
580 | @carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
581 |
582 | @carousel-control-color: #fff;
583 | @carousel-control-width: 15%;
584 | @carousel-control-opacity: .5;
585 | @carousel-control-font-size: 20px;
586 |
587 | @carousel-indicator-active-bg: #fff;
588 | @carousel-indicator-border-color: #fff;
589 |
590 | @carousel-caption-color: #fff;
591 |
592 |
593 | // Close
594 | // ------------------------
595 | @close-font-weight: bold;
596 | @close-color: #000;
597 | @close-text-shadow: 0 1px 0 #fff;
598 |
599 |
600 | // Code
601 | // ------------------------
602 | @code-color: #c7254e;
603 | @code-bg: #f9f2f4;
604 |
605 | @pre-bg: #f5f5f5;
606 | @pre-color: @gray-dark;
607 | @pre-border-color: #ccc;
608 | @pre-scrollable-max-height: 340px;
609 |
610 | // Type
611 | // ------------------------
612 | @text-muted: @gray-light;
613 | @abbr-border-color: @gray-light;
614 | @headings-small-color: @gray-light;
615 | @blockquote-small-color: @gray-light;
616 | @blockquote-border-color: @gray-lighter;
617 | @page-header-border-color: @gray-lighter;
618 |
619 | // Miscellaneous
620 | // -------------------------
621 |
622 | // Hr border color
623 | @hr-border: @gray-lighter;
624 |
625 | // Horizontal forms & lists
626 | @component-offset-horizontal: 180px;
627 |
628 |
629 | // Container sizes
630 | // --------------------------------------------------
631 |
632 | // Small screen / tablet
633 | @container-tablet: ((720px + @grid-gutter-width));
634 | @container-sm: @container-tablet;
635 |
636 | // Medium screen / desktop
637 | @container-desktop: ((940px + @grid-gutter-width));
638 | @container-md: @container-desktop;
639 |
640 | // Large screen / wide desktop
641 | @container-large-desktop: ((1140px + @grid-gutter-width));
642 | @container-lg: @container-large-desktop;
643 |
644 |
645 |
646 | // ----------------------------------
647 | // angular-dashboard variables
648 | // ----------------------------------
--------------------------------------------------------------------------------
/app/styles/themes/simplex.less:
--------------------------------------------------------------------------------
1 | // Simplex 3.0.3
2 | // Variables
3 | // --------------------------------------------------
4 |
5 |
6 | // Global values
7 | // --------------------------------------------------
8 |
9 | // Grays
10 | // -------------------------
11 |
12 | @gray-darker: lighten(#000, 13.5%); // #222
13 | @gray-dark: lighten(#000, 20%); // #333
14 | @gray: lighten(#000, 33.5%); // #555
15 | @gray-light: lighten(#000, 60%); // #999
16 | @gray-lighter: lighten(#000, 93.5%); // #eee
17 |
18 | // Brand colors
19 | // -------------------------
20 |
21 | @brand-primary: #D9230F;
22 | @brand-success: #3D9400;
23 | @brand-warning: #9B479F;
24 | @brand-danger: #D9831F;
25 | @brand-info: #029ACF;
26 |
27 | // Scaffolding
28 | // -------------------------
29 |
30 | @body-bg: #F7F7F7;
31 | @text-color: @gray-dark;
32 |
33 | // Links
34 | // -------------------------
35 |
36 | @link-color: @brand-primary;
37 | @link-hover-color: darken(@link-color, 15%);
38 |
39 | // Typography
40 | // -------------------------
41 |
42 | @font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
43 | @font-family-serif: Georgia, "Times New Roman", Times, serif;
44 | @font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
45 | @font-family-base: @font-family-sans-serif;
46 |
47 | @font-size-base: 13px;
48 | @font-size-large: ceil(@font-size-base * 1.25); // ~18px
49 | @font-size-small: ceil(@font-size-base * 0.85); // ~12px
50 |
51 | @font-size-h1: floor(@font-size-base * 2.6); // ~36px
52 | @font-size-h2: floor(@font-size-base * 2.15); // ~30px
53 | @font-size-h3: ceil(@font-size-base * 1.7); // ~24px
54 | @font-size-h4: ceil(@font-size-base * 1.25); // ~18px
55 | @font-size-h5: @font-size-base;
56 | @font-size-h6: ceil(@font-size-base * 0.85); // ~12px
57 |
58 | @line-height-base: 1.428571429; // 20/14
59 | @line-height-computed: floor(@font-size-base * @line-height-base); // ~20px
60 |
61 | @headings-font-family: "Josefin Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
62 | @headings-font-weight: 500;
63 | @headings-line-height: 1.1;
64 | @headings-color: inherit;
65 |
66 |
67 | // Iconography
68 | // -------------------------
69 |
70 | @icon-font-path: "../fonts/";
71 | @icon-font-name: "glyphicons-halflings-regular";
72 |
73 |
74 | // Components
75 | // -------------------------
76 | // Based on 14px font-size and 1.428 line-height (~20px to start)
77 |
78 | @padding-base-vertical: 8px;
79 | @padding-base-horizontal: 12px;
80 |
81 | @padding-large-vertical: 14px;
82 | @padding-large-horizontal: 16px;
83 |
84 | @padding-small-vertical: 5px;
85 | @padding-small-horizontal: 10px;
86 |
87 | @padding-xs-vertical: 1px;
88 | @padding-xs-horizontal: 5px;
89 |
90 | @line-height-large: 1.33;
91 | @line-height-small: 1.5;
92 |
93 | @border-radius-base: 4px;
94 | @border-radius-large: 6px;
95 | @border-radius-small: 3px;
96 |
97 | @component-active-color: #fff;
98 | @component-active-bg: @brand-primary;
99 |
100 | @caret-width-base: 4px;
101 | @caret-width-large: 5px;
102 |
103 | // Tables
104 | // -------------------------
105 |
106 | @table-cell-padding: 8px;
107 | @table-condensed-cell-padding: 5px;
108 |
109 | @table-bg: transparent; // overall background-color
110 | @table-bg-accent: #f9f9f9; // for striping
111 | @table-bg-hover: #f5f5f5;
112 | @table-bg-active: @table-bg-hover;
113 |
114 | @table-border-color: #ddd; // table and cell border
115 |
116 |
117 | // Buttons
118 | // -------------------------
119 |
120 | @btn-font-weight: normal;
121 |
122 | @btn-default-color: #fff;
123 | @btn-default-bg: #474949;
124 | @btn-default-border: @btn-default-bg;
125 |
126 | @btn-primary-color: @btn-default-color;
127 | @btn-primary-bg: @brand-primary;
128 | @btn-primary-border: @btn-primary-bg;
129 |
130 | @btn-success-color: @btn-default-color;
131 | @btn-success-bg: @brand-success;
132 | @btn-success-border: @btn-success-bg;
133 |
134 | @btn-warning-color: @btn-default-color;
135 | @btn-warning-bg: @brand-warning;
136 | @btn-warning-border: @btn-warning-bg;
137 |
138 | @btn-danger-color: @btn-default-color;
139 | @btn-danger-bg: @brand-danger;
140 | @btn-danger-border: @btn-danger-bg;
141 |
142 | @btn-info-color: @btn-default-color;
143 | @btn-info-bg: @brand-info;
144 | @btn-info-border: @btn-info-bg;
145 |
146 | @btn-link-disabled-color: @gray-light;
147 |
148 |
149 | // Forms
150 | // -------------------------
151 |
152 | @input-bg: #fff;
153 | @input-bg-disabled: @gray-lighter;
154 |
155 | @input-color: @text-color;
156 | @input-border: #ccc;
157 | @input-border-radius: @border-radius-base;
158 | @input-border-focus: #66afe9;
159 |
160 | @input-color-placeholder: @gray-light;
161 |
162 | @input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
163 | @input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
164 | @input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
165 |
166 | @legend-color: @text-color;
167 | @legend-border-color: #e5e5e5;
168 |
169 | @input-group-addon-bg: @gray-lighter;
170 | @input-group-addon-border-color: @input-border;
171 |
172 |
173 | // Dropdowns
174 | // -------------------------
175 |
176 | @dropdown-bg: #fff;
177 | @dropdown-border: rgba(0,0,0,.15);
178 | @dropdown-fallback-border: #ccc;
179 | @dropdown-divider-bg: #e5e5e5;
180 |
181 | @dropdown-link-color: @gray-dark;
182 | @dropdown-link-hover-color: #fff;
183 | @dropdown-link-hover-bg: @dropdown-link-active-bg;
184 |
185 | @dropdown-link-active-color: #fff;
186 | @dropdown-link-active-bg: @component-active-bg;
187 |
188 | @dropdown-link-disabled-color: @text-muted;
189 |
190 | @dropdown-header-color: @text-muted;
191 |
192 |
193 | // COMPONENT VARIABLES
194 | // --------------------------------------------------
195 |
196 |
197 | // Z-index master list
198 | // -------------------------
199 | // Used for a bird's eye view of components dependent on the z-axis
200 | // Try to avoid customizing these :)
201 |
202 | @zindex-navbar: 1000;
203 | @zindex-dropdown: 1000;
204 | @zindex-popover: 1010;
205 | @zindex-tooltip: 1030;
206 | @zindex-navbar-fixed: 1030;
207 | @zindex-modal-background: 1040;
208 | @zindex-modal: 1050;
209 |
210 | // Media queries breakpoints
211 | // --------------------------------------------------
212 |
213 | // Extra small screen / phone
214 | // Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
215 | @screen-xs: 480px;
216 | @screen-xs-min: @screen-xs;
217 | @screen-phone: @screen-xs-min;
218 |
219 | // Small screen / tablet
220 | // Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1
221 | @screen-sm: 768px;
222 | @screen-sm-min: @screen-sm;
223 | @screen-tablet: @screen-sm-min;
224 |
225 | // Medium screen / desktop
226 | // Note: Deprecated @screen-md and @screen-desktop as of v3.0.1
227 | @screen-md: 992px;
228 | @screen-md-min: @screen-md;
229 | @screen-desktop: @screen-md-min;
230 |
231 | // Large screen / wide desktop
232 | // Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1
233 | @screen-lg: 1200px;
234 | @screen-lg-min: @screen-lg;
235 | @screen-lg-desktop: @screen-lg-min;
236 |
237 | // So media queries don't overlap when required, provide a maximum
238 | @screen-xs-max: (@screen-sm-min - 1);
239 | @screen-sm-max: (@screen-md-min - 1);
240 | @screen-md-max: (@screen-lg-min - 1);
241 |
242 |
243 | // Grid system
244 | // --------------------------------------------------
245 |
246 | // Number of columns in the grid system
247 | @grid-columns: 12;
248 | // Padding, to be divided by two and applied to the left and right of all columns
249 | @grid-gutter-width: 30px;
250 |
251 | // Navbar collapse
252 |
253 | // Point at which the navbar becomes uncollapsed
254 | @grid-float-breakpoint: @screen-sm-min;
255 | // Point at which the navbar begins collapsing
256 | @grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
257 |
258 |
259 | // Navbar
260 | // -------------------------
261 |
262 | // Basics of a navbar
263 | @navbar-height: 40px;
264 | @navbar-margin-bottom: @line-height-computed;
265 | @navbar-border-radius: @border-radius-base;
266 | @navbar-padding-horizontal: floor(@grid-gutter-width / 2); // ~15px
267 | @navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
268 |
269 | @navbar-default-color: @gray-dark;
270 | @navbar-default-bg: #fff;
271 | @navbar-default-border: darken(@navbar-default-bg, 6.5%);
272 |
273 | // Navbar links
274 | @navbar-default-link-color: @gray-dark;
275 | @navbar-default-link-hover-color: @brand-primary;
276 | @navbar-default-link-hover-bg: transparent;
277 | @navbar-default-link-active-color: @navbar-default-link-hover-color;
278 | @navbar-default-link-active-bg: transparent;
279 | @navbar-default-link-disabled-color: #444;
280 | @navbar-default-link-disabled-bg: transparent;
281 |
282 | // Navbar brand label
283 | @navbar-default-brand-color: @navbar-default-link-color;
284 | @navbar-default-brand-hover-color: @navbar-default-link-hover-color;
285 | @navbar-default-brand-hover-bg: transparent;
286 |
287 | // Navbar toggle
288 | @navbar-default-toggle-hover-bg: #ddd;
289 | @navbar-default-toggle-icon-bar-bg: #ccc;
290 | @navbar-default-toggle-border-color: #ddd;
291 |
292 |
293 | // Inverted navbar
294 | //
295 | // Reset inverted navbar basics
296 | @navbar-inverse-color: #fff;
297 | @navbar-inverse-bg: @brand-primary;
298 | @navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
299 |
300 | // Inverted navbar links
301 | @navbar-inverse-link-color: #fff;
302 | @navbar-inverse-link-hover-color: lighten(@brand-primary, 40%);
303 | @navbar-inverse-link-hover-bg: transparent;
304 | @navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
305 | @navbar-inverse-link-active-bg: transparent;
306 | @navbar-inverse-link-disabled-color: #ccc;
307 | @navbar-inverse-link-disabled-bg: transparent;
308 |
309 | // Inverted navbar brand label
310 | @navbar-inverse-brand-color: @navbar-inverse-link-color;
311 | @navbar-inverse-brand-hover-color: #fff;
312 | @navbar-inverse-brand-hover-bg: transparent;
313 |
314 | // Inverted navbar toggle
315 | @navbar-inverse-toggle-hover-bg: darken(@navbar-inverse-bg, 10%);
316 | @navbar-inverse-toggle-icon-bar-bg: #fff;
317 | @navbar-inverse-toggle-border-color: darken(@navbar-inverse-bg, 10%);
318 |
319 |
320 | // Navs
321 | // -------------------------
322 |
323 | @nav-link-padding: 10px 15px;
324 | @nav-link-hover-bg: @gray-lighter;
325 |
326 | @nav-disabled-link-color: @gray-light;
327 | @nav-disabled-link-hover-color: @gray-light;
328 |
329 | @nav-open-link-hover-color: #fff;
330 |
331 | // Tabs
332 | @nav-tabs-border-color: #ddd;
333 |
334 | @nav-tabs-link-hover-border-color: @gray-lighter;
335 |
336 | @nav-tabs-active-link-hover-bg: @body-bg;
337 | @nav-tabs-active-link-hover-color: @gray;
338 | @nav-tabs-active-link-hover-border-color: #ddd;
339 |
340 | @nav-tabs-justified-link-border-color: #ddd;
341 | @nav-tabs-justified-active-link-border-color: @body-bg;
342 |
343 | // Pills
344 | @nav-pills-border-radius: @border-radius-base;
345 | @nav-pills-active-link-hover-bg: @component-active-bg;
346 | @nav-pills-active-link-hover-color: @component-active-color;
347 |
348 |
349 | // Pagination
350 | // -------------------------
351 |
352 | @pagination-bg: #fff;
353 | @pagination-border: #ddd;
354 |
355 | @pagination-hover-bg: @gray-lighter;
356 |
357 | @pagination-active-bg: #f5f5f5;
358 | @pagination-active-color: @gray-light;
359 |
360 | @pagination-disabled-color: @gray-light;
361 |
362 |
363 | // Pager
364 | // -------------------------
365 |
366 | @pager-border-radius: 15px;
367 | @pager-disabled-color: @gray-light;
368 |
369 |
370 | // Jumbotron
371 | // -------------------------
372 |
373 | @jumbotron-padding: 30px;
374 | @jumbotron-color: inherit;
375 | @jumbotron-bg: darken(@body-bg, 3%);
376 | @jumbotron-heading-color: inherit;
377 | @jumbotron-font-size: ceil(@font-size-base * 1.5);
378 |
379 |
380 | // Form states and alerts
381 | // -------------------------
382 |
383 | @state-success-text: #468847;
384 | @state-success-bg: #dff0d8;
385 | @state-success-border: darken(spin(@state-success-bg, -10), 5%);
386 |
387 | @state-info-text: #3a87ad;
388 | @state-info-bg: #d9edf7;
389 | @state-info-border: darken(spin(@state-info-bg, -10), 7%);
390 |
391 | @state-warning-text: #c09853;
392 | @state-warning-bg: #fcf8e3;
393 | @state-warning-border: darken(spin(@state-warning-bg, -10), 3%);
394 |
395 | @state-danger-text: #b94a48;
396 | @state-danger-bg: #f2dede;
397 | @state-danger-border: darken(spin(@state-danger-bg, -10), 3%);
398 |
399 |
400 | // Tooltips
401 | // -------------------------
402 | @tooltip-max-width: 200px;
403 | @tooltip-color: #fff;
404 | @tooltip-bg: rgba(0,0,0,.9);
405 |
406 | @tooltip-arrow-width: 5px;
407 | @tooltip-arrow-color: @tooltip-bg;
408 |
409 |
410 | // Popovers
411 | // -------------------------
412 | @popover-bg: #fff;
413 | @popover-max-width: 276px;
414 | @popover-border-color: rgba(0,0,0,.2);
415 | @popover-fallback-border-color: #ccc;
416 |
417 | @popover-title-bg: darken(@popover-bg, 3%);
418 |
419 | @popover-arrow-width: 10px;
420 | @popover-arrow-color: #fff;
421 |
422 | @popover-arrow-outer-width: (@popover-arrow-width + 1);
423 | @popover-arrow-outer-color: rgba(0,0,0,.25);
424 | @popover-arrow-outer-fallback-color: #999;
425 |
426 |
427 | // Labels
428 | // -------------------------
429 |
430 | @label-default-bg: @btn-default-bg;
431 | @label-primary-bg: @brand-primary;
432 | @label-success-bg: @brand-success;
433 | @label-info-bg: @brand-info;
434 | @label-warning-bg: @brand-warning;
435 | @label-danger-bg: @brand-danger;
436 |
437 | @label-color: #fff;
438 | @label-link-hover-color: #fff;
439 |
440 |
441 | // Modals
442 | // -------------------------
443 | @modal-inner-padding: 20px;
444 |
445 | @modal-title-padding: 15px;
446 | @modal-title-line-height: @line-height-base;
447 |
448 | @modal-content-bg: #fff;
449 | @modal-content-border-color: rgba(0,0,0,.2);
450 | @modal-content-fallback-border-color: #999;
451 |
452 | @modal-backdrop-bg: #000;
453 | @modal-header-border-color: #e5e5e5;
454 | @modal-footer-border-color: @modal-header-border-color;
455 |
456 |
457 | // Alerts
458 | // -------------------------
459 | @alert-padding: 15px;
460 | @alert-border-radius: @border-radius-base;
461 | @alert-link-font-weight: bold;
462 |
463 | @alert-success-bg: @state-success-bg;
464 | @alert-success-text: @state-success-text;
465 | @alert-success-border: @state-success-border;
466 |
467 | @alert-info-bg: @state-info-bg;
468 | @alert-info-text: @state-info-text;
469 | @alert-info-border: @state-info-border;
470 |
471 | @alert-warning-bg: @state-warning-bg;
472 | @alert-warning-text: @state-warning-text;
473 | @alert-warning-border: @state-warning-border;
474 |
475 | @alert-danger-bg: @state-danger-bg;
476 | @alert-danger-text: @state-danger-text;
477 | @alert-danger-border: @state-danger-border;
478 |
479 |
480 | // Progress bars
481 | // -------------------------
482 | @progress-bg: #f5f5f5;
483 | @progress-bar-color: #fff;
484 |
485 | @progress-bar-bg: @brand-primary;
486 | @progress-bar-success-bg: @brand-success;
487 | @progress-bar-warning-bg: @brand-warning;
488 | @progress-bar-danger-bg: @brand-danger;
489 | @progress-bar-info-bg: @brand-info;
490 |
491 |
492 | // List group
493 | // -------------------------
494 | @list-group-bg: #fff;
495 | @list-group-border: #ddd;
496 | @list-group-border-radius: @border-radius-base;
497 |
498 | @list-group-hover-bg: #f5f5f5;
499 | @list-group-active-color: @component-active-color;
500 | @list-group-active-bg: @component-active-bg;
501 | @list-group-active-border: @list-group-active-bg;
502 |
503 | @list-group-link-color: #555;
504 | @list-group-link-heading-color: #333;
505 |
506 |
507 | // Panels
508 | // -------------------------
509 | @panel-bg: #fff;
510 | @panel-inner-border: #ddd;
511 | @panel-border-radius: @border-radius-base;
512 | @panel-footer-bg: @panel-default-heading-bg;
513 |
514 | @panel-default-text: @gray-dark;
515 | @panel-default-border: #ddd;
516 | @panel-default-heading-bg: @body-bg;
517 |
518 | @panel-primary-text: #fff;
519 | @panel-primary-border: @brand-primary;
520 | @panel-primary-heading-bg: @brand-primary;
521 |
522 | @panel-success-text: @state-success-text;
523 | @panel-success-border: @state-success-border;
524 | @panel-success-heading-bg: @state-success-bg;
525 |
526 | @panel-warning-text: @state-warning-text;
527 | @panel-warning-border: @state-warning-border;
528 | @panel-warning-heading-bg: @state-warning-bg;
529 |
530 | @panel-danger-text: @state-danger-text;
531 | @panel-danger-border: @state-danger-border;
532 | @panel-danger-heading-bg: @state-danger-bg;
533 |
534 | @panel-info-text: @state-info-text;
535 | @panel-info-border: @state-info-border;
536 | @panel-info-heading-bg: @state-info-bg;
537 |
538 |
539 | // Thumbnails
540 | // -------------------------
541 | @thumbnail-padding: 4px;
542 | @thumbnail-bg: @body-bg;
543 | @thumbnail-border: #ddd;
544 | @thumbnail-border-radius: @border-radius-base;
545 |
546 | @thumbnail-caption-color: @text-color;
547 | @thumbnail-caption-padding: 9px;
548 |
549 |
550 | // Wells
551 | // -------------------------
552 | @well-bg: darken(@body-bg, 3%);
553 |
554 |
555 | // Badges
556 | // -------------------------
557 | @badge-color: #fff;
558 | @badge-link-hover-color: #fff;
559 | @badge-bg: @gray-light;
560 |
561 | @badge-active-color: @link-color;
562 | @badge-active-bg: #fff;
563 |
564 | @badge-font-weight: bold;
565 | @badge-line-height: 1;
566 | @badge-border-radius: 10px;
567 |
568 |
569 | // Breadcrumbs
570 | // -------------------------
571 | @breadcrumb-bg: transparent;
572 | @breadcrumb-color: #ccc;
573 | @breadcrumb-active-color: @gray-light;
574 | @breadcrumb-separator: "/";
575 |
576 |
577 | // Carousel
578 | // ------------------------
579 |
580 | @carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
581 |
582 | @carousel-control-color: #fff;
583 | @carousel-control-width: 15%;
584 | @carousel-control-opacity: .5;
585 | @carousel-control-font-size: 20px;
586 |
587 | @carousel-indicator-active-bg: #fff;
588 | @carousel-indicator-border-color: #fff;
589 |
590 | @carousel-caption-color: #fff;
591 |
592 |
593 | // Close
594 | // ------------------------
595 | @close-font-weight: bold;
596 | @close-color: #000;
597 | @close-text-shadow: 0 1px 0 #fff;
598 |
599 |
600 | // Code
601 | // ------------------------
602 | @code-color: #c7254e;
603 | @code-bg: #f9f2f4;
604 |
605 | @pre-bg: #f5f5f5;
606 | @pre-color: @gray-dark;
607 | @pre-border-color: #ccc;
608 | @pre-scrollable-max-height: 340px;
609 |
610 | // Type
611 | // ------------------------
612 | @text-muted: @gray-light;
613 | @abbr-border-color: @gray-light;
614 | @headings-small-color: @gray-light;
615 | @blockquote-small-color: @gray-light;
616 | @blockquote-border-color: @gray-lighter;
617 | @page-header-border-color: @gray-lighter;
618 |
619 | // Miscellaneous
620 | // -------------------------
621 |
622 | // Hr border color
623 | @hr-border: @gray-lighter;
624 |
625 | // Horizontal forms & lists
626 | @component-offset-horizontal: 180px;
627 |
628 |
629 | // Container sizes
630 | // --------------------------------------------------
631 |
632 | // Small screen / tablet
633 | @container-tablet: ((720px + @grid-gutter-width));
634 | @container-sm: @container-tablet;
635 |
636 | // Medium screen / desktop
637 | @container-desktop: ((940px + @grid-gutter-width));
638 | @container-md: @container-desktop;
639 |
640 | // Large screen / wide desktop
641 | @container-large-desktop: ((1140px + @grid-gutter-width));
642 | @container-lg: @container-large-desktop;
643 |
--------------------------------------------------------------------------------
/app/styles/themes/amelia.less:
--------------------------------------------------------------------------------
1 | // Amelia 3.0.3
2 | // Variables
3 | // --------------------------------------------------
4 |
5 |
6 | // Global values
7 | // --------------------------------------------------
8 |
9 | // Grays
10 | // -------------------------
11 |
12 | @gray-darker: #111;
13 | @gray-dark: #444;
14 | @gray: lighten(#000, 33.5%); // #555
15 | @gray-light: #bbb;
16 | @gray-lighter: #ddd;
17 |
18 | // Brand colors
19 | // -------------------------
20 |
21 | @brand-primary: #AD1D28;
22 | @brand-success: #48CA3B;
23 | @brand-warning: #DEBB27;
24 | @brand-danger: #DF6E1E;
25 | @brand-info: #4D3A7D;
26 |
27 | // Scaffolding
28 | // -------------------------
29 |
30 | @body-bg: #108A93;
31 | @text-color: #fff;
32 |
33 | // Links
34 | // -------------------------
35 |
36 | @link-color: lighten(@brand-warning, 15%);
37 | @link-hover-color: @brand-warning;
38 |
39 | // Typography
40 | // -------------------------
41 |
42 | @font-family-sans-serif: "Cabin", Arial, sans-serif;
43 | @font-family-serif: Georgia, "Times New Roman", Times, serif;
44 | @font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
45 | @font-family-base: @font-family-sans-serif;
46 |
47 | @font-size-base: 14px;
48 | @font-size-large: ceil(@font-size-base * 1.25); // ~18px
49 | @font-size-small: ceil(@font-size-base * 0.85); // ~12px
50 |
51 | @font-size-h1: floor(@font-size-base * 2.6); // ~36px
52 | @font-size-h2: floor(@font-size-base * 2.15); // ~30px
53 | @font-size-h3: ceil(@font-size-base * 1.7); // ~24px
54 | @font-size-h4: ceil(@font-size-base * 1.25); // ~18px
55 | @font-size-h5: @font-size-base;
56 | @font-size-h6: ceil(@font-size-base * 0.85); // ~12px
57 |
58 | @line-height-base: 1.428571429; // 20/14
59 | @line-height-computed: floor(@font-size-base * @line-height-base); // ~20px
60 |
61 | @headings-font-family: 'Lobster', cursive;
62 | @headings-font-weight: 500;
63 | @headings-line-height: 1.1;
64 | @headings-color: inherit;
65 |
66 |
67 | // Iconography
68 | // -------------------------
69 |
70 | @icon-font-path: "../fonts/";
71 | @icon-font-name: "glyphicons-halflings-regular";
72 |
73 |
74 | // Components
75 | // -------------------------
76 | // Based on 14px font-size and 1.428 line-height (~20px to start)
77 |
78 | @padding-base-vertical: 8px;
79 | @padding-base-horizontal: 12px;
80 |
81 | @padding-large-vertical: 14px;
82 | @padding-large-horizontal: 16px;
83 |
84 | @padding-small-vertical: 5px;
85 | @padding-small-horizontal: 10px;
86 |
87 | @padding-xs-vertical: 1px;
88 | @padding-xs-horizontal: 5px;
89 |
90 | @line-height-large: 1.33;
91 | @line-height-small: 1.5;
92 |
93 | @border-radius-base: 4px;
94 | @border-radius-large: 6px;
95 | @border-radius-small: 3px;
96 |
97 | @component-active-color: #fff;
98 | @component-active-bg: lighten(@body-bg, 10%);
99 |
100 | @caret-width-base: 4px;
101 | @caret-width-large: 5px;
102 |
103 | // Tables
104 | // -------------------------
105 |
106 | @table-cell-padding: 8px;
107 | @table-condensed-cell-padding: 5px;
108 |
109 | @table-bg: transparent; // overall background-color
110 | @table-bg-accent: darken(@body-bg, 2.5%); // for striping
111 | @table-bg-hover: lighten(@body-bg, 5%);
112 | @table-bg-active: darken(@body-bg, 5%);
113 |
114 | @table-border-color: darken(@body-bg, 5%); // table and cell border
115 |
116 |
117 | // Buttons
118 | // -------------------------
119 |
120 | @btn-font-weight: normal;
121 |
122 | @btn-default-color: @gray-dark;
123 | @btn-default-bg: @gray-lighter;
124 | @btn-default-border: @btn-default-bg;
125 |
126 | @btn-primary-color: #fff;
127 | @btn-primary-bg: @brand-primary;
128 | @btn-primary-border: @btn-primary-bg;
129 |
130 | @btn-success-color: @btn-primary-color;
131 | @btn-success-bg: @brand-success;
132 | @btn-success-border: @btn-success-bg;
133 |
134 | @btn-warning-color: @btn-primary-color;
135 | @btn-warning-bg: @brand-warning;
136 | @btn-warning-border: @btn-warning-bg;
137 |
138 | @btn-danger-color: @btn-primary-color;
139 | @btn-danger-bg: @brand-danger;
140 | @btn-danger-border: @btn-danger-bg;
141 |
142 | @btn-info-color: @btn-primary-color;
143 | @btn-info-bg: @brand-info;
144 | @btn-info-border: @btn-info-bg;
145 |
146 | @btn-link-disabled-color: @gray-light;
147 |
148 |
149 | // Forms
150 | // -------------------------
151 |
152 | @input-bg: #fff;
153 | @input-bg-disabled: @gray-lighter;
154 |
155 | @input-color: @gray-dark;
156 | @input-border: #ccc;
157 | @input-border-radius: @border-radius-base;
158 | @input-border-focus: #66afe9;
159 |
160 | @input-color-placeholder: @gray-light;
161 |
162 | @input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
163 | @input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
164 | @input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
165 |
166 | @legend-color: @text-color;
167 | @legend-border-color: darken(@body-bg, 5%);
168 |
169 | @input-group-addon-bg: @gray-lighter;
170 | @input-group-addon-border-color: @input-border;
171 |
172 |
173 | // Dropdowns
174 | // -------------------------
175 |
176 | @dropdown-bg: #fff;
177 | @dropdown-border: rgba(0,0,0,.15);
178 | @dropdown-fallback-border: #ccc;
179 | @dropdown-divider-bg: #e5e5e5;
180 |
181 | @dropdown-link-color: @gray-dark;
182 | @dropdown-link-hover-color: #fff;
183 | @dropdown-link-hover-bg: @dropdown-link-active-bg;
184 |
185 | @dropdown-link-active-color: #fff;
186 | @dropdown-link-active-bg: @component-active-bg;
187 |
188 | @dropdown-link-disabled-color: @gray-lighter;
189 |
190 | @dropdown-header-color: @gray-lighter;
191 |
192 |
193 | // COMPONENT VARIABLES
194 | // --------------------------------------------------
195 |
196 |
197 | // Z-index master list
198 | // -------------------------
199 | // Used for a bird's eye view of components dependent on the z-axis
200 | // Try to avoid customizing these :)
201 |
202 | @zindex-navbar: 1000;
203 | @zindex-dropdown: 1000;
204 | @zindex-popover: 1010;
205 | @zindex-tooltip: 1030;
206 | @zindex-navbar-fixed: 1030;
207 | @zindex-modal-background: 1040;
208 | @zindex-modal: 1050;
209 |
210 | // Media queries breakpoints
211 | // --------------------------------------------------
212 |
213 | // Extra small screen / phone
214 | // Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
215 | @screen-xs: 480px;
216 | @screen-xs-min: @screen-xs;
217 | @screen-phone: @screen-xs-min;
218 |
219 | // Small screen / tablet
220 | // Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1
221 | @screen-sm: 768px;
222 | @screen-sm-min: @screen-sm;
223 | @screen-tablet: @screen-sm-min;
224 |
225 | // Medium screen / desktop
226 | // Note: Deprecated @screen-md and @screen-desktop as of v3.0.1
227 | @screen-md: 992px;
228 | @screen-md-min: @screen-md;
229 | @screen-desktop: @screen-md-min;
230 |
231 | // Large screen / wide desktop
232 | // Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1
233 | @screen-lg: 1200px;
234 | @screen-lg-min: @screen-lg;
235 | @screen-lg-desktop: @screen-lg-min;
236 |
237 | // So media queries don't overlap when required, provide a maximum
238 | @screen-xs-max: (@screen-sm-min - 1);
239 | @screen-sm-max: (@screen-md-min - 1);
240 | @screen-md-max: (@screen-lg-min - 1);
241 |
242 |
243 | // Grid system
244 | // --------------------------------------------------
245 |
246 | // Number of columns in the grid system
247 | @grid-columns: 12;
248 | // Padding, to be divided by two and applied to the left and right of all columns
249 | @grid-gutter-width: 30px;
250 |
251 | // Navbar collapse
252 |
253 | // Point at which the navbar becomes uncollapsed
254 | @grid-float-breakpoint: @screen-sm-min;
255 | // Point at which the navbar begins collapsing
256 | @grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
257 |
258 |
259 | // Navbar
260 | // -------------------------
261 |
262 | // Basics of a navbar
263 | @navbar-height: 50px;
264 | @navbar-margin-bottom: @line-height-computed;
265 | @navbar-border-radius: @border-radius-base;
266 | @navbar-padding-horizontal: floor(@grid-gutter-width / 2);
267 | @navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
268 |
269 | @navbar-default-color: @gray-light;
270 | @navbar-default-bg: @brand-primary;
271 | @navbar-default-border: darken(@navbar-default-bg, 6.5%);
272 |
273 | // Navbar links
274 | @navbar-default-link-color: #fff;
275 | @navbar-default-link-hover-color: #fff;
276 | @navbar-default-link-hover-bg: lighten(@navbar-default-bg, 10%);
277 | @navbar-default-link-active-color: #fff;
278 | @navbar-default-link-active-bg: @navbar-default-link-hover-bg;
279 | @navbar-default-link-disabled-color: #ccc;
280 | @navbar-default-link-disabled-bg: transparent;
281 |
282 | // Navbar brand label
283 | @navbar-default-brand-color: @navbar-default-link-color;
284 | @navbar-default-brand-hover-color: @navbar-default-brand-color;
285 | @navbar-default-brand-hover-bg: none;
286 |
287 | // Navbar toggle
288 | @navbar-default-toggle-hover-bg: @navbar-default-link-hover-bg;
289 | @navbar-default-toggle-icon-bar-bg: #fff;
290 | @navbar-default-toggle-border-color: @navbar-default-link-hover-bg;
291 |
292 |
293 | // Inverted navbar
294 | //
295 | // Reset inverted navbar basics
296 | @navbar-inverse-color: @gray-light;
297 | @navbar-inverse-bg: @brand-warning;
298 | @navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
299 |
300 | // Inverted navbar links
301 | @navbar-inverse-link-color: #fff;
302 | @navbar-inverse-link-hover-color: #fff;
303 | @navbar-inverse-link-hover-bg: lighten(@navbar-inverse-bg, 10%);
304 | @navbar-inverse-link-active-color: #fff;
305 | @navbar-inverse-link-active-bg: @navbar-inverse-link-hover-bg;
306 | @navbar-inverse-link-disabled-color: #444;
307 | @navbar-inverse-link-disabled-bg: transparent;
308 |
309 | // Inverted navbar brand label
310 | @navbar-inverse-brand-color: @navbar-inverse-link-color;
311 | @navbar-inverse-brand-hover-color: #fff;
312 | @navbar-inverse-brand-hover-bg: none;
313 |
314 | // Inverted navbar toggle
315 | @navbar-inverse-toggle-hover-bg: @navbar-inverse-link-hover-bg;
316 | @navbar-inverse-toggle-icon-bar-bg: #fff;
317 | @navbar-inverse-toggle-border-color: @navbar-inverse-link-hover-bg;
318 |
319 |
320 | // Navs
321 | // -------------------------
322 |
323 | @nav-link-padding: 10px 15px;
324 | @nav-link-hover-bg: lighten(@body-bg, 10%);
325 |
326 | @nav-disabled-link-color: @gray-lighter;
327 | @nav-disabled-link-hover-color: @gray-lighter;
328 |
329 | @nav-open-link-hover-color: @nav-link-hover-bg;
330 |
331 | // Tabs
332 | @nav-tabs-border-color: @nav-link-hover-bg;
333 |
334 | @nav-tabs-link-hover-border-color: transparent;
335 |
336 | @nav-tabs-active-link-hover-bg: @nav-link-hover-bg;
337 | @nav-tabs-active-link-hover-color: #fff;
338 | @nav-tabs-active-link-hover-border-color: transparent;
339 |
340 | @nav-tabs-justified-link-border-color: transparent;
341 | @nav-tabs-justified-active-link-border-color: transparent;
342 |
343 | // Pills
344 | @nav-pills-border-radius: @border-radius-base;
345 | @nav-pills-active-link-hover-bg: @component-active-bg;
346 | @nav-pills-active-link-hover-color: #fff;
347 |
348 |
349 | // Pagination
350 | // -------------------------
351 |
352 | @pagination-bg: lighten(@body-bg, 5%);
353 | @pagination-border: transparent;
354 |
355 | @pagination-hover-bg: @component-active-bg;
356 |
357 | @pagination-active-bg: lighten(@body-bg, 10%);
358 | @pagination-active-color: #fff;
359 |
360 | @pagination-disabled-color: #fff;
361 |
362 |
363 | // Pager
364 | // -------------------------
365 |
366 | @pager-border-radius: 15px;
367 | @pager-disabled-color: @gray-lighter;
368 |
369 |
370 | // Jumbotron
371 | // -------------------------
372 |
373 | @jumbotron-padding: 30px;
374 | @jumbotron-color: inherit;
375 | @jumbotron-bg: darken(@body-bg, 5%);
376 | @jumbotron-heading-color: inherit;
377 | @jumbotron-font-size: ceil(@font-size-base * 1.5);
378 |
379 |
380 | // Form states and alerts
381 | // -------------------------
382 |
383 | @state-success-text: #fff;
384 | @state-success-bg: @brand-success;
385 | @state-success-border: darken(spin(@state-success-bg, -10), 5%);
386 |
387 | @state-info-text: #fff;
388 | @state-info-bg: @brand-info;
389 | @state-info-border: darken(spin(@state-info-bg, -10), 7%);
390 |
391 | @state-warning-text: #fff;
392 | @state-warning-bg: @brand-warning;
393 | @state-warning-border: darken(spin(@state-warning-bg, -10), 3%);
394 |
395 | @state-danger-text: #fff;
396 | @state-danger-bg: @brand-danger;
397 | @state-danger-border: darken(spin(@state-danger-bg, -10), 3%);
398 |
399 |
400 | // Tooltips
401 | // -------------------------
402 | @tooltip-max-width: 200px;
403 | @tooltip-color: #fff;
404 | @tooltip-bg: rgba(0,0,0,.9);
405 |
406 | @tooltip-arrow-width: 5px;
407 | @tooltip-arrow-color: @tooltip-bg;
408 |
409 |
410 | // Popovers
411 | // -------------------------
412 | @popover-bg: #fff;
413 | @popover-max-width: 276px;
414 | @popover-border-color: rgba(0,0,0,.2);
415 | @popover-fallback-border-color: #ccc;
416 |
417 | @popover-title-bg: darken(@popover-bg, 3%);
418 |
419 | @popover-arrow-width: 10px;
420 | @popover-arrow-color: #fff;
421 |
422 | @popover-arrow-outer-width: (@popover-arrow-width + 1);
423 | @popover-arrow-outer-color: rgba(0,0,0,.25);
424 | @popover-arrow-outer-fallback-color: #999;
425 |
426 |
427 | // Labels
428 | // -------------------------
429 |
430 | @label-default-bg: @btn-default-bg;
431 | @label-primary-bg: @brand-primary;
432 | @label-success-bg: @brand-success;
433 | @label-info-bg: @brand-info;
434 | @label-warning-bg: @brand-warning;
435 | @label-danger-bg: @brand-danger;
436 |
437 | @label-color: #fff;
438 | @label-link-hover-color: #fff;
439 |
440 |
441 | // Modals
442 | // -------------------------
443 | @modal-inner-padding: 20px;
444 |
445 | @modal-title-padding: 15px;
446 | @modal-title-line-height: @line-height-base;
447 |
448 | @modal-content-bg: lighten(@body-bg, 5%);
449 | @modal-content-border-color: rgba(0,0,0,.2);
450 | @modal-content-fallback-border-color: #999;
451 |
452 | @modal-backdrop-bg: #000;
453 | @modal-header-border-color: darken(@body-bg, 5%);
454 | @modal-footer-border-color: @modal-header-border-color;
455 |
456 |
457 | // Alerts
458 | // -------------------------
459 | @alert-padding: 15px;
460 | @alert-border-radius: @border-radius-base;
461 | @alert-link-font-weight: bold;
462 |
463 | @alert-success-bg: @state-success-bg;
464 | @alert-success-text: @state-success-text;
465 | @alert-success-border: @state-success-border;
466 |
467 | @alert-info-bg: @state-info-bg;
468 | @alert-info-text: @state-info-text;
469 | @alert-info-border: @state-info-border;
470 |
471 | @alert-warning-bg: @state-warning-bg;
472 | @alert-warning-text: @state-warning-text;
473 | @alert-warning-border: @state-warning-border;
474 |
475 | @alert-danger-bg: @state-danger-bg;
476 | @alert-danger-text: @state-danger-text;
477 | @alert-danger-border: @state-danger-border;
478 |
479 |
480 | // Progress bars
481 | // -------------------------
482 | @progress-bg: darken(@body-bg, 5%);
483 | @progress-bar-color: #fff;
484 |
485 | @progress-bar-bg: @brand-primary;
486 | @progress-bar-success-bg: @brand-success;
487 | @progress-bar-warning-bg: @brand-warning;
488 | @progress-bar-danger-bg: @brand-danger;
489 | @progress-bar-info-bg: @brand-info;
490 |
491 |
492 | // List group
493 | // -------------------------
494 | @list-group-bg: transparent;
495 | @list-group-border: darken(@body-bg, 5%);
496 | @list-group-border-radius: @border-radius-base;
497 |
498 | @list-group-hover-bg: lighten(@body-bg, 10%);
499 | @list-group-active-color: @component-active-color;
500 | @list-group-active-bg: @component-active-bg;
501 | @list-group-active-border: @list-group-border;
502 |
503 | @list-group-link-color: @link-color;
504 | @list-group-link-heading-color: #fff;
505 |
506 |
507 | // Panels
508 | // -------------------------
509 | @panel-bg: lighten(@body-bg, 5%);
510 | @panel-inner-border: darken(@body-bg, 5%);
511 | @panel-border-radius: @border-radius-base;
512 | @panel-footer-bg: @panel-default-heading-bg;
513 |
514 | @panel-default-text: #fff;
515 | @panel-default-border: darken(@body-bg, 5%);
516 | @panel-default-heading-bg: lighten(@body-bg, 15%);
517 |
518 | @panel-primary-text: #fff;
519 | @panel-primary-border: @brand-primary;
520 | @panel-primary-heading-bg: @brand-primary;
521 |
522 | @panel-success-text: @state-success-text;
523 | @panel-success-border: @state-success-border;
524 | @panel-success-heading-bg: @state-success-bg;
525 |
526 | @panel-warning-text: @state-warning-text;
527 | @panel-warning-border: @state-warning-border;
528 | @panel-warning-heading-bg: @state-warning-bg;
529 |
530 | @panel-danger-text: @state-danger-text;
531 | @panel-danger-border: @state-danger-border;
532 | @panel-danger-heading-bg: @state-danger-bg;
533 |
534 | @panel-info-text: @state-info-text;
535 | @panel-info-border: @state-info-border;
536 | @panel-info-heading-bg: @state-info-bg;
537 |
538 |
539 | // Thumbnails
540 | // -------------------------
541 | @thumbnail-padding: 4px;
542 | @thumbnail-bg: @body-bg;
543 | @thumbnail-border: #ddd;
544 | @thumbnail-border-radius: @border-radius-base;
545 |
546 | @thumbnail-caption-color: @text-color;
547 | @thumbnail-caption-padding: 9px;
548 |
549 |
550 | // Wells
551 | // -------------------------
552 | @well-bg: darken(@body-bg, 5%);
553 |
554 |
555 | // Badges
556 | // -------------------------
557 | @badge-color: #fff;
558 | @badge-link-hover-color: #fff;
559 | @badge-bg: @brand-primary;
560 |
561 | @badge-active-color: #fff;
562 | @badge-active-bg: @brand-primary;
563 |
564 | @badge-font-weight: bold;
565 | @badge-line-height: 1;
566 | @badge-border-radius: 10px;
567 |
568 |
569 | // Breadcrumbs
570 | // -------------------------
571 | @breadcrumb-bg: lighten(@body-bg, 5%);
572 | @breadcrumb-color: @gray-lighter;
573 | @breadcrumb-active-color: #fff;
574 | @breadcrumb-separator: "/";
575 |
576 |
577 | // Carousel
578 | // ------------------------
579 |
580 | @carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
581 |
582 | @carousel-control-color: #fff;
583 | @carousel-control-width: 15%;
584 | @carousel-control-opacity: .5;
585 | @carousel-control-font-size: 20px;
586 |
587 | @carousel-indicator-active-bg: #fff;
588 | @carousel-indicator-border-color: #fff;
589 |
590 | @carousel-caption-color: #fff;
591 |
592 |
593 | // Close
594 | // ------------------------
595 | @close-font-weight: bold;
596 | @close-color: #000;
597 | @close-text-shadow: 0 1px 0 #fff;
598 |
599 |
600 | // Code
601 | // ------------------------
602 | @code-color: #c7254e;
603 | @code-bg: #f9f2f4;
604 |
605 | @pre-bg: #f5f5f5;
606 | @pre-color: @gray-dark;
607 | @pre-border-color: #ccc;
608 | @pre-scrollable-max-height: 340px;
609 |
610 | // Type
611 | // ------------------------
612 | @text-muted: rgba(255, 255, 255, 0.6);
613 | @abbr-border-color: @gray-light;
614 | @headings-small-color: @gray-light;
615 | @blockquote-small-color: rgba(255, 255, 255, 0.6);
616 | @blockquote-border-color: rgba(255, 255, 255, 0.6);
617 | @page-header-border-color: darken(@body-bg, 5%);
618 |
619 | // Miscellaneous
620 | // -------------------------
621 |
622 | // Hr border color
623 | @hr-border: darken(@body-bg, 5%);
624 |
625 | // Horizontal forms & lists
626 | @component-offset-horizontal: 180px;
627 |
628 |
629 | // Container sizes
630 | // --------------------------------------------------
631 |
632 | // Small screen / tablet
633 | @container-tablet: ((720px + @grid-gutter-width));
634 | @container-sm: @container-tablet;
635 |
636 | // Medium screen / desktop
637 | @container-desktop: ((940px + @grid-gutter-width));
638 | @container-md: @container-desktop;
639 |
640 | // Large screen / wide desktop
641 | @container-large-desktop: ((1140px + @grid-gutter-width));
642 | @container-lg: @container-large-desktop;
643 |
644 |
645 | // ----------------------------------
646 | // angular-dashboard variables
647 | // ----------------------------------
--------------------------------------------------------------------------------