robeaux 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -4
- data/index.html +14 -2
- data/javascripts/app.js +106 -4
- data/javascripts/vendor/angular-route.min.js +6 -6
- data/javascripts/vendor/angular.min.js +189 -190
- data/javascripts/vendor/bootstrap.min.js +4 -5
- data/javascripts/vendor/jquery.min.js +4 -6
- data/package.json +1 -1
- data/partials/themes.html +29 -0
- data/robeaux.gemspec +1 -1
- data/stylesheets/bootstrap.css +1245 -2583
- data/stylesheets/style.css +65 -39
- data/stylesheets/themes/dark.css +106 -0
- data/stylesheets/themes/default.css +73 -0
- data/stylesheets/themes/flat.css +164 -0
- metadata +6 -3
- data/.keep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e9cb1794d02b9393af64856a6b291061ae9fd4f
|
4
|
+
data.tar.gz: 9df1c29727e8f1d16e971f4c1909c4b4a54d4756
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07d8b1440b14a49f5bb95bd3898abb3610916e8b357cfce24089072789e612edfa4152943171f6e9f9ef48849f8655b4acab57fa76e485401fb70e4c174ef49e
|
7
|
+
data.tar.gz: dcd894b2fefcca0d39b88aea069060bba1cd9f57137a8d064687a590231440bc970f23a9c875506468f3bc2773e78e6ec09903ccfa1086e08a75855c1ab64ba1
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Robeaux is powered by [AngularJS](http://angularjs.org/), and provides
|
|
7
7
|
a front-end to the API interface offered by [Artoo](http://artoo.io),
|
8
8
|
[Cylon.js](http://cylonjs.com) and [Gobot](http://gobot.io). It looks like this:
|
9
9
|
|
10
|
-
![Robeaux Interface](http://i.imgur.com/
|
10
|
+
![Robeaux Interface](http://i.imgur.com/Uxb21j0.png)
|
11
11
|
|
12
12
|
## How It Works
|
13
13
|
|
@@ -21,14 +21,14 @@ connected to a compatible API server.
|
|
21
21
|
You can see each robot that your are connected to, and then drill in to view or
|
22
22
|
edit it.
|
23
23
|
|
24
|
-
![Robots View](http://i.imgur.com/
|
24
|
+
![Robots View](http://i.imgur.com/Uxb21j0.png)
|
25
25
|
|
26
26
|
### Connections
|
27
27
|
|
28
28
|
How are you connected? Serial port? WiFi? View the details for each of your
|
29
29
|
robots.
|
30
30
|
|
31
|
-
![Connections View](http://i.imgur.com/
|
31
|
+
![Connections View](http://i.imgur.com/Kof6g50.png)
|
32
32
|
|
33
33
|
### Devices
|
34
34
|
|
@@ -36,7 +36,31 @@ Each robot has one or more devices connected. You can view the device status and
|
|
36
36
|
send commands all via the web interface. You can even stream the real-time
|
37
37
|
websockets data for your buttons, switches, LEDs, sensors, and more.
|
38
38
|
|
39
|
-
![Devices View](http://i.imgur.com/
|
39
|
+
![Devices View](http://i.imgur.com/AMJZCe9.png)
|
40
|
+
|
41
|
+
## Themes
|
42
|
+
|
43
|
+
You can change the theme! Pick from one of the presets, or write your own. It'll
|
44
|
+
be persisted in `localStorage` and ready to go for the next time you want to use
|
45
|
+
Robeaux.
|
46
|
+
|
47
|
+
We have three default themes:
|
48
|
+
|
49
|
+
**Default Theme**:
|
50
|
+
|
51
|
+
![Default Theme](http://i.imgur.com/AMJZCe9.png)
|
52
|
+
|
53
|
+
**Dark Theme**:
|
54
|
+
|
55
|
+
![Dark Theme](http://i.imgur.com/SNSLROf.png)
|
56
|
+
|
57
|
+
**Flat Theme**:
|
58
|
+
|
59
|
+
![Flat Theme](http://i.imgur.com/AVzMd7j.png)
|
60
|
+
|
61
|
+
You can also use the theme editor to write your own custom themes:
|
62
|
+
|
63
|
+
![Custom Theme Editor](http://i.imgur.com/pxxmhfD.png)
|
40
64
|
|
41
65
|
## Pushing new versions
|
42
66
|
|
data/index.html
CHANGED
@@ -6,9 +6,19 @@
|
|
6
6
|
<link rel="stylesheet" href="/stylesheets/bootstrap.css">
|
7
7
|
<link rel="stylesheet" href="/stylesheets/font-awesome.css">
|
8
8
|
<link rel="stylesheet" href="/stylesheets/style.css">
|
9
|
+
|
10
|
+
<span class="ng-hide" ng-controller="ThemesCtrl">
|
11
|
+
<link ng-if="!themes.current().custom" rel="stylesheet" ng-href="{{themes.current().url}}">
|
12
|
+
<style ng-if="themes.current().custom" ng-bind-template="{{themes.current().css}}"></style>
|
13
|
+
</span>
|
9
14
|
</head>
|
10
15
|
<body>
|
11
16
|
<nav class="navbar navbar-default" role="navigation">
|
17
|
+
<div class="theme-selector" ng-controller="ThemesCtrl">
|
18
|
+
<select class="nav navbar-nav" ng-selected="themes.setActiveTheme()" ng-model="themes.activeTheme" ng-options="name for name in themes.list()">
|
19
|
+
</select>
|
20
|
+
</div>
|
21
|
+
|
12
22
|
<div class="container">
|
13
23
|
<div class="navbar-header">
|
14
24
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
@@ -21,10 +31,12 @@
|
|
21
31
|
</div>
|
22
32
|
|
23
33
|
<div class="collapse navbar-collapse">
|
24
|
-
<ul class="nav navbar-nav" ng-
|
25
|
-
<li class="active"><a href="
|
34
|
+
<ul class="nav navbar-nav" ng-controller="NavigationCtrl">
|
35
|
+
<li ng-class="{active: active('robots')}"><a href="#/robots">Robots</a></li>
|
36
|
+
<li ng-class="{active: active('themes')}"><a href="#/themes">Themes</a></li>
|
26
37
|
</ul>
|
27
38
|
</div>
|
39
|
+
|
28
40
|
</div>
|
29
41
|
</nav>
|
30
42
|
|
data/javascripts/app.js
CHANGED
@@ -2,18 +2,120 @@
|
|
2
2
|
var robeaux = angular.module("robeaux", ['ngRoute']);
|
3
3
|
|
4
4
|
robeaux.config(["$routeProvider", function($routeProvider) {
|
5
|
-
$routeProvider
|
5
|
+
$routeProvider
|
6
|
+
|
7
|
+
.when("/robots", {
|
6
8
|
templateUrl: "/partials/robot-index.html",
|
7
9
|
controller: RobotIndexCtrl
|
8
|
-
})
|
10
|
+
})
|
11
|
+
|
12
|
+
.when("/robots/:robotId", {
|
9
13
|
templateUrl: "/partials/robot-detail.html",
|
10
14
|
controller: RobotDetailCtrl
|
11
|
-
})
|
15
|
+
})
|
16
|
+
|
17
|
+
.when("/themes", {
|
18
|
+
templateUrl: "/partials/themes.html",
|
19
|
+
controller: ThemesCtrl
|
20
|
+
})
|
21
|
+
|
22
|
+
.otherwise({
|
12
23
|
redirectTo: "/robots"
|
13
24
|
});
|
14
|
-
}])
|
25
|
+
}]);
|
26
|
+
|
27
|
+
robeaux.service("Themes", function() {
|
28
|
+
var service = {};
|
29
|
+
var defaultThemes = {
|
30
|
+
"default": { custom: false, url: "/stylesheets/themes/default.css" },
|
31
|
+
"dark": { custom: false, url: "/stylesheets/themes/dark.css" },
|
32
|
+
"flat": { custom: false, url: "/stylesheets/themes/flat.css" }
|
33
|
+
};
|
34
|
+
|
35
|
+
var saveThemes = function() {
|
36
|
+
localStorage.setItem("themes", angular.toJson(service.themes));
|
37
|
+
};
|
38
|
+
|
39
|
+
var loadThemes = function() {
|
40
|
+
if (localStorage.getItem("themes")) {
|
41
|
+
return angular.fromJson(localStorage.getItem("themes"));
|
42
|
+
} else {
|
43
|
+
return defaultThemes;
|
44
|
+
}
|
45
|
+
};
|
46
|
+
|
47
|
+
var getActiveTheme = function() {
|
48
|
+
return localStorage.getItem("activeTheme") || "default";
|
49
|
+
};
|
50
|
+
|
51
|
+
service.themes = loadThemes();
|
52
|
+
|
53
|
+
service.activeTheme = getActiveTheme();
|
54
|
+
|
55
|
+
service.saveThemes = saveThemes;
|
56
|
+
|
57
|
+
service.current = function() {
|
58
|
+
return service.themes[service.activeTheme];
|
59
|
+
};
|
60
|
+
|
61
|
+
service.list = function() {
|
62
|
+
return Object.keys(service.themes);
|
63
|
+
};
|
64
|
+
|
65
|
+
service.customThemes = function() {
|
66
|
+
var themes = {};
|
67
|
+
|
68
|
+
for (var name in service.themes) {
|
69
|
+
if (service.themes[name].custom) {
|
70
|
+
themes[name] = service.themes[name];
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
return themes;
|
75
|
+
};
|
76
|
+
|
77
|
+
service.setActiveTheme = function() {
|
78
|
+
localStorage.setItem("activeTheme", service.activeTheme);
|
79
|
+
}
|
80
|
+
|
81
|
+
service.newTheme = function(name) {
|
82
|
+
if (service.themes[name] || name === '' || name === undefined) {
|
83
|
+
return false;
|
84
|
+
}
|
85
|
+
|
86
|
+
service.themes[name] = {css: "", custom: true};
|
87
|
+
return service.themes[name];
|
88
|
+
};
|
89
|
+
|
90
|
+
return service;
|
91
|
+
});
|
15
92
|
|
16
93
|
// Controllers
|
94
|
+
var ThemesCtrl = function($scope, Themes) {
|
95
|
+
$scope.themes = Themes;
|
96
|
+
|
97
|
+
$scope.selectTheme = function(name) {
|
98
|
+
$scope.selectedTheme = Themes.themes[name];
|
99
|
+
$scope.selectedThemeName = name;
|
100
|
+
};
|
101
|
+
|
102
|
+
$scope.deleteTheme = function(name) {
|
103
|
+
delete Themes.themes[name];
|
104
|
+
$scope.selectedTheme = null;
|
105
|
+
$scope.selectedThemeName = null;
|
106
|
+
};
|
107
|
+
|
108
|
+
$scope.newTheme = function(name) {
|
109
|
+
if (Themes.newTheme(name)) { $scope.newThemeName = ''; }
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
var NavigationCtrl = function($scope, $location) {
|
114
|
+
$scope.active = function(path) {
|
115
|
+
return ($location.path().substring(1).split("/")[0] || "robots") === path;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
17
119
|
var RobotIndexCtrl = function($scope, $http, $location, $route) {
|
18
120
|
$http.get('/robots').success(function(data) {
|
19
121
|
$scope.robots = data;
|
@@ -1,14 +1,14 @@
|
|
1
1
|
/*
|
2
|
-
AngularJS v1.2.
|
2
|
+
AngularJS v1.2.11
|
3
3
|
(c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
License: MIT
|
5
5
|
*/
|
6
6
|
(function(h,e,A){'use strict';function u(w,q,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,n){function y(){l&&(l.$destroy(),l=null);g&&(k.leave(g),g=null)}function v(){var b=w.current&&w.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),f=w.current;g=n(b,function(d){k.enter(d,null,g||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||q()});y()});l=f.scope=b;l.$emit("$viewContentLoaded");l.$eval(h)}else y()}var l,g,t=b.autoscroll,h=b.onload||"";
|
7
7
|
a.$on("$routeChangeSuccess",v);v()}}}function z(e,h,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var n=e(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));n(a)}}}h=e.module("ngRoute",["ng"]).provider("$route",function(){function h(a,c){return e.extend(new (e.extend(function(){},{prototype:a})),c)}function q(a,
|
8
|
-
e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;h.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&q(a,c));if(a){var b="/"==a[a.length-1]?a.substr(0,a.length-
|
9
|
+
1):a+"/";k[b]=e.extend({redirectTo:a},q(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,n,q,v,l){function g(){var d=t(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!x)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)x=!1,a.$broadcast("$routeChangeStart",d,m),(r.current=
|
10
|
+
d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(u(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?n.get(d):n.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=l.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=b,c=q.get(b,
|
11
|
+
{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function t(){var a,b;e.forEach(k,function(f,k){var p;if(p=!b){var s=c.path();p=f.keys;var l={};if(f.regexp)if(s=f.regexp.exec(s)){for(var g=1,q=s.length;g<q;++g){var n=p[g-1],r="string"==typeof s[g]?decodeURIComponent(s[g]):s[g];
|
12
|
+
n&&r&&(l[n.name]=r)}p=l}else p=null;else p=null;p=a=p}p&&(b=h(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&h(k[null],{params:{},pathParams:{}})}function u(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var x=!1,r={routes:k,reload:function(){x=!0;a.$evalAsync(g)}};a.$on("$locationChangeSuccess",g);return r}]});h.provider("$routeParams",
|
13
13
|
function(){this.$get=function(){return{}}});h.directive("ngView",u);h.directive("ngView",z);u.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
|
14
14
|
//# sourceMappingURL=angular-route.min.js.map
|