Merge pull request #302 from hashicorp/ui-acls
UI: ACLs, Notifications, Settings
This commit is contained in:
commit
50f6fecad1
|
@ -47,6 +47,11 @@ An example of this command, from inside the `ui/` directory, would be:
|
|||
Basic tests can be run by adding the `?test` query parameter to the
|
||||
application.
|
||||
|
||||
When developing Consul, it's recommended that you use the included
|
||||
development configuration.
|
||||
|
||||
consul agent -config-file=development_config.json
|
||||
|
||||
### Releasing
|
||||
|
||||
`make dist`
|
||||
|
|
9
ui/development_config.json
Normal file
9
ui/development_config.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"datacenter": "dc1",
|
||||
"data_dir": "/tmp/",
|
||||
"ui_dir": ".",
|
||||
"bootstrap": true,
|
||||
"server": true,
|
||||
"acl_datacenter": "dc1",
|
||||
"acl_master_token": "dev"
|
||||
}
|
207
ui/index.html
207
ui/index.html
|
@ -38,6 +38,36 @@
|
|||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" data-template-name="dc/unauthorized">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2 col-sm-12 col-xs-12">
|
||||
<div class="text-center vertical-center">
|
||||
<p class="bold">Access Denied</p>
|
||||
{{#if aclToken}}
|
||||
<p>Your ACL token, <code>{{aclToken}}</code>, does not
|
||||
have the appropriate permissions to perform the expected action.</p>
|
||||
{{else}}
|
||||
<p>The default agent token does not
|
||||
have the appropriate permissions to perform the expected action.</p>
|
||||
{{/if}}
|
||||
<p>Learn more in the <a href="http://www.consul.io/docs/internals/acl.html">ACL documentation</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" data-template-name="dc/aclsdisabled">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2 col-sm-12 col-xs-12">
|
||||
<div class="text-center vertical-center">
|
||||
<p class="bold">ACLs Disabled</p>
|
||||
<p>ACLs are disabled in this Consul cluster. This is the default behavior, as you have to implictly enable them.</p>
|
||||
</p>Learn more in the <a href="http://www.consul.io/docs/internals/acl.html">ACL documentation</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" data-template-name="loading">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2 col-sm-12 col-xs-12">
|
||||
|
@ -52,51 +82,61 @@
|
|||
<script type="text/x-handlebars" id="actionbar">
|
||||
<div class="row">
|
||||
<div class="action-bar">
|
||||
<div class="col-md-5">
|
||||
<div {{ bind-attr class="searchBar:col-md-10:col-md-5" }} >
|
||||
<div class="form-group">
|
||||
{{ input type="text" value=filter class="form-control form-control-mini" placeholder="Filter by name"}}
|
||||
{{ input type="text" value=filter class="form-control form-control-mini" placeholder=filterText}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if newAclButton }}
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
{{#link-to 'acls' class='btn btn-mini btn-default btn-noactive pull-right'}}New ACL{{/link-to}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if statuses}}
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
{{view Ember.Select content=statuses value=status class="form-control form-control-mini"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if hasExpanded }}
|
||||
<div class="col-md-2 hidden-xs hidden-sm">
|
||||
<div class="form-group">
|
||||
<button {{ bind-attr class=":btn :btn-mini :pull-right condensed:btn-default:btn-primary" }} {{action toggleCondensed }}>Expand</button>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" data-template-name="dc">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-sm-12 col-xs-12 topbar">
|
||||
<div {{ bind-attr class=":col-md-12 :col-sm-12 :col-xs-12 :topbar" }}>
|
||||
|
||||
<div class="col-md-1 col-sm-2 col-xs-10 col-sm-offset-0 col-xs-offset-1">
|
||||
<div class="col-md-1 col-sm-2 col-xs-8 col-sm-offset-0 col-xs-offset-1">
|
||||
<a href="#"><div class="top-brand"></div></a>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3 col-xs-10 col-sm-offset-0 col-xs-offset-1">
|
||||
<div class="col-md-2 col-sm-3 col-xs-8 col-sm-offset-0 col-xs-offset-1">
|
||||
{{#link-to 'services' class='btn btn-default col-xs-12'}}Services{{/link-to}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3 col-xs-10 col-sm-offset-0 col-xs-offset-1">
|
||||
<div class="col-md-2 col-sm-3 col-xs-8 col-sm-offset-0 col-xs-offset-1">
|
||||
{{#link-to 'nodes' class='btn btn-default col-xs-12'}}Nodes{{/link-to}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3 col-xs-10 col-sm-offset-0 col-xs-offset-1">
|
||||
<div class="col-md-2 col-sm-3 col-xs-8 col-sm-offset-0 col-xs-offset-1">
|
||||
{{#link-to 'kv' class='btn btn-default col-xs-12'}}Key/Value{{/link-to}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-md-offset-1 col-sm-3 col-sm-offset-5 col-xs-10 col-xs-offset-1">
|
||||
{{#link-to 'services' (query-params status=checkStatus) tagName="div" href=false }}<a {{bind-attr class=":col-xs-12 :btn hasFailingChecks:btn-warning:btn-success"}}>{{ checkMessage }}</a>{{/link-to}}
|
||||
<div class="col-md-2 col-sm-2 col-xs-8 col-md-offset-0 col-sm-offset-2 col-xs-offset-1">
|
||||
{{#link-to 'acls' class='btn btn-default col-xs-12'}}ACL{{/link-to}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3 col-xs-10 col-sm-offset-0 col-xs-offset-1">
|
||||
<a {{bind-attr class=":col-xs-12 :btn isDropDownVisible:btn-primary:btn-default"}} {{action "toggle"}}> {{model}} <span class="caret"></span> </a>
|
||||
<div class="col-md-2 col-sm-2 col-xs-6 col-md-offset-0 col-sm-offset-4 col-xs-offset-1">
|
||||
<a {{bind-attr class=":col-xs-12 :btn isDropDownVisible:btn-primary:btn-default"}} {{action "toggle"}}> <span class="elip-overflow">{{model}} <span class="caret"></span></span> </a>
|
||||
|
||||
{{#if isDropdownVisible}}
|
||||
<ul class="dropdown-menu col-xs-8" style="display:block;">
|
||||
|
@ -107,6 +147,10 @@
|
|||
{{/if}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-1 col-sm-2 col-xs-2 col-md-offset-0 col-sm-offset-0 col-xs-offset-0">
|
||||
{{#link-to 'settings' class='btn btn-default col-xs-6 icon'}}<span class="wrap">⚙</span>{{/link-to}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -524,6 +568,124 @@
|
|||
{{/if}}
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" id="acls">
|
||||
<div class="row">
|
||||
<div {{ bind-attr class=":col-md-6 :col-lg-5 :padded-right-middle isShowingItem:hidden-xs isShowingItem:hidden-sm" }}>
|
||||
{{view App.ActionBarView }}
|
||||
|
||||
{{#if filteredContent}}
|
||||
{{#collection Ember.ListView contentBinding="filteredContent" height=800 rowHeight=44 }}
|
||||
{{#link-to 'acls.show' ID tagName="div" href=false class="list-group-item list-condensed-link" }}
|
||||
<div class="bg-light-gray list-bar-horizontal"></div>
|
||||
<div class="name">
|
||||
{{ aclName Name ID }}
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{/collection}}
|
||||
{{else}}
|
||||
<p class="light">There are no ACLs to show.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="border-left hidden-xs hidden-sm">
|
||||
</div>
|
||||
|
||||
{{#if isShowingItem}}
|
||||
<div class="col-md-6 col-lg-7 border-left scrollable">
|
||||
<div class="row padded-border">
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-md-6 col-lg-7 border-left">
|
||||
<div class="row padded-border">
|
||||
<div class="panel">
|
||||
<div {{ bind-attr class=":panel-bar isLoading:bg-orange:bg-light-gray" }}></div>
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
New ACL
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="panel-body panel-form">
|
||||
<div class="form-group"></div>
|
||||
|
||||
<form class="form">
|
||||
<div class="form-group">
|
||||
{{ input value=newAcl.Name class="form-control" }}
|
||||
<span class="help-block">Set the optional name for the ACL.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{view Ember.Select content=types value=newAcl.Type class="form-control form-control-mini"}}
|
||||
<span class="help-block">The type of ACL this is.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Rules</label>
|
||||
{{ textarea value=newAcl.Rules class="form-control" }}
|
||||
<span class="help-block">For more information on rules, visit the <a href="http://www.consul.io/docs/internals/acl.html">ACL documentation.</a></span>
|
||||
</div>
|
||||
|
||||
<button {{ action "createAcl"}} {{ bind-attr class=":btn :btn-success" }}>Create</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" id="acl">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 visible-xs visible-sm">
|
||||
{{#link-to "acls" class="btn btn-default btn-block" }}Back to all ACLs{{/link-to}}
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div {{ bind-attr class=":panel-bar isLoading:bg-orange:bg-light-gray" }}></div>
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
{{ aclName "Update ACL" model.ID }}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="panel-body panel-form">
|
||||
<div class="form-group"></div>
|
||||
|
||||
<form class="form">
|
||||
<div class="form-group">
|
||||
{{ input value=model.Name class="form-control" }}
|
||||
<span class="help-block">Set the optional name for the ACL.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{view Ember.Select content=types value=model.Type class="form-control form-control-mini"}}
|
||||
<span class="help-block">The type of ACL this is.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Rules</label>
|
||||
{{ textarea value=model.Rules class="form-control" }}
|
||||
<span class="help-block">For more information on rules, visit the <a href="http://www.consul.io/docs/internals/acl.html">ACL documentation.</a></span>
|
||||
</div>
|
||||
|
||||
<button {{ action "updateAcl"}} {{ bind-attr class=":btn :btn-success" }}>Update</button>
|
||||
<button {{ action "clone" }} {{ bind-attr class=":btn :btn-default" }}>Clone</button>
|
||||
<button {{ action "set" }} {{ bind-attr class=":btn :btn-default" }}>Use Token</button>
|
||||
{{# if model.isNotAnon }}
|
||||
<button {{ action "delete"}} {{ bind-attr class=":btn isLoading:btn-warning:btn-danger :pull-right" }}>Delete</button>
|
||||
{{/if}}
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" id="index">
|
||||
<div class="col-md-8 col-md-offset-2 col-xs-offset-0 col-sm-offset-0 col-xs-12 col-sm-12 vertical-center">
|
||||
<h5>Select a datacenter</h5>
|
||||
|
@ -543,6 +705,25 @@
|
|||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-handlebars" id="settings">
|
||||
<div class="col-md-8 col-md-offset-2 col-xs-offset-0 col-sm-offset-0 col-xs-12 col-sm-12">
|
||||
<h3>Settings</h3>
|
||||
<p>These settings allow you to configure your browser for the Consul Web UI. Everything is saved to localstorage,
|
||||
and should persist through visits and browser usage.</p>
|
||||
<p>Settings are automatically persisted upon modification, so no manual save is required.</p>
|
||||
<h5>Access Token</h5>
|
||||
<div class="form-group">
|
||||
{{ input type="text" value=model.token class="form-control form-mono" placeholder="token"}}
|
||||
<span class="help-block">The token is sent with requests as the <code>?token</code> parameter. This is used to control the ACL for the
|
||||
web UI.</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button {{ action "reset" }} {{ bind-attr class=":btn :btn-danger" }}>Reset Defaults</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
// Enable query params, must be loaded before ember is
|
||||
EmberENV = {FEATURES: {'query-params-new': true}};
|
||||
|
@ -554,6 +735,8 @@
|
|||
<script src="javascripts/libs/ember-debug.min.js"></script>
|
||||
<script src="javascripts/libs/ember-validations.min.js"></script>
|
||||
<script src="javascripts/libs/list-view.min.js"></script>
|
||||
<script src="javascripts/libs/classie.js"></script>
|
||||
<script src="javascripts/libs/notificationFx.js"></script>
|
||||
<script src="javascripts/fixtures.js"></script>
|
||||
<script src="javascripts/app/router.js"></script>
|
||||
<script src="javascripts/app/routes.js"></script>
|
||||
|
|
|
@ -5,8 +5,10 @@ App.ApplicationController = Ember.ObjectController.extend({
|
|||
});
|
||||
|
||||
App.DcController = Ember.Controller.extend({
|
||||
needs: ["application"],
|
||||
// Whether or not the dropdown menu can be seen
|
||||
isDropdownVisible: false,
|
||||
aclToken: Ember.computed.alias("application.settings.token"),
|
||||
|
||||
datacenter: function() {
|
||||
return this.get('content');
|
||||
|
@ -44,9 +46,9 @@ App.DcController = Ember.Controller.extend({
|
|||
var passingChecks = checks.filterBy('Status', 'passing').get('length');
|
||||
|
||||
if (this.get('hasFailingChecks') === true) {
|
||||
return failingChecks + ' checks failing';
|
||||
return failingChecks + ' failing';
|
||||
} else {
|
||||
return passingChecks + ' checks passing';
|
||||
return passingChecks + ' passing';
|
||||
}
|
||||
|
||||
}.property('nodes'),
|
||||
|
@ -241,6 +243,8 @@ ItemBaseController = Ember.ArrayController.extend({
|
|||
queryParams: ["filter", "status", "condensed"],
|
||||
dc: Ember.computed.alias("controllers.dc"),
|
||||
condensed: true,
|
||||
hasExpanded: true,
|
||||
filterText: "Filter by name",
|
||||
filter: "", // default
|
||||
status: "any status", // default
|
||||
statuses: ["any status", "passing", "failing"],
|
||||
|
@ -313,3 +317,189 @@ App.ServicesController = ItemBaseController.extend({
|
|||
items: Ember.computed.alias("services"),
|
||||
});
|
||||
|
||||
App.AclsController = Ember.ArrayController.extend({
|
||||
needs: ["dc", "application"],
|
||||
queryParams: ["filter"],
|
||||
filterText: "Filter by name or ID",
|
||||
searchBar: true,
|
||||
newAclButton: true,
|
||||
types: ["management", "client"],
|
||||
|
||||
dc: Ember.computed.alias("controllers.dc"),
|
||||
items: Ember.computed.alias("acls"),
|
||||
|
||||
filter: "",
|
||||
|
||||
isShowingItem: function() {
|
||||
var currentPath = this.get('controllers.application.currentPath');
|
||||
return (currentPath === "dc.acls.show");
|
||||
}.property('controllers.application.currentPath'),
|
||||
|
||||
filteredContent: function() {
|
||||
var filter = this.get('filter');
|
||||
|
||||
var items = this.get('items').filter(function(item, index, enumerable){
|
||||
// First try to match on the name
|
||||
var nameMatch = item.get('Name').toLowerCase().match(filter.toLowerCase());
|
||||
if (nameMatch !== null) {
|
||||
return nameMatch;
|
||||
} else {
|
||||
return item.get('ID').toLowerCase().match(filter.toLowerCase());
|
||||
}
|
||||
});
|
||||
|
||||
return items;
|
||||
}.property('filter', 'items.@each'),
|
||||
|
||||
actions: {
|
||||
createAcl: function() {
|
||||
this.set('isLoading', true);
|
||||
|
||||
var controller = this;
|
||||
var newAcl = controller.get('newAcl');
|
||||
var dc = controller.get('dc').get('datacenter');
|
||||
var token = App.get('settings.token');
|
||||
|
||||
// Create the ACL
|
||||
Ember.$.ajax({
|
||||
url: formatUrl('/v1/acl/create', dc, token),
|
||||
type: 'PUT',
|
||||
data: JSON.stringify(newAcl)
|
||||
}).then(function(response) {
|
||||
// transition to the acl
|
||||
controller.transitionToRoute('acls.show', response.ID);
|
||||
controller.set('isLoading', false);
|
||||
}).fail(function(response) {
|
||||
// Render the error message on the form if the request failed
|
||||
notify('Received error while creating ACL: ' + response.statusText, 8000);
|
||||
controller.set('isLoading', false);
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
App.AclsShowController = Ember.ObjectController.extend({
|
||||
needs: ["dc", "acls"],
|
||||
dc: Ember.computed.alias("controllers.dc"),
|
||||
isLoading: false,
|
||||
types: ["management", "client"],
|
||||
|
||||
actions: {
|
||||
set: function() {
|
||||
this.set('isLoading', true);
|
||||
var controller = this;
|
||||
var acl = controller.get('model');
|
||||
var dc = controller.get('dc').get('datacenter');
|
||||
|
||||
if (window.confirm("Are you sure you want to use this token for your session?")) {
|
||||
// Set
|
||||
var token = App.set('settings.token', acl.ID);
|
||||
controller.transitionToRoute('services');
|
||||
this.set('isLoading', false);
|
||||
notify('Now using token: ' + acl.ID, 3000);
|
||||
}
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
this.set('isLoading', true);
|
||||
var controller = this;
|
||||
var acl = controller.get('model');
|
||||
var dc = controller.get('dc').get('datacenter');
|
||||
var token = App.get('settings.token');
|
||||
|
||||
// Set
|
||||
controller.transitionToRoute('services');
|
||||
|
||||
Ember.$.ajax({
|
||||
url: formatUrl('/v1/acl/clone/'+ acl.ID, dc, token),
|
||||
type: 'PUT'
|
||||
}).then(function(response) {
|
||||
controller.transitionToRoute('acls.show', response.ID);
|
||||
controller.set('isLoading', false);
|
||||
notify('Succesfully cloned token', 4000);
|
||||
}).fail(function(response) {
|
||||
// Render the error message on the form if the request failed
|
||||
controller.set('errorMessage', 'Received error while processing: ' + response.statusText);
|
||||
controller.set('isLoading', false);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
delete: function() {
|
||||
this.set('isLoading', true);
|
||||
var controller = this;
|
||||
var acl = controller.get('model');
|
||||
var dc = controller.get('dc').get('datacenter');
|
||||
var token = App.get('settings.token');
|
||||
|
||||
if (window.confirm("Are you sure you want to delete this token?")) {
|
||||
Ember.$.ajax({
|
||||
url: formatUrl('/v1/acl/destroy/'+ acl.ID, dc, token),
|
||||
type: 'PUT'
|
||||
}).then(function(response) {
|
||||
Ember.$.getJSON(formatUrl('/v1/acl/list', dc, token)).then(function(data) {
|
||||
objs = [];
|
||||
data.map(function(obj){
|
||||
if (obj.ID === "anonymous") {
|
||||
objs.unshift(App.Acl.create(obj));
|
||||
} else {
|
||||
objs.push(App.Acl.create(obj));
|
||||
}
|
||||
});
|
||||
controller.get('controllers.acls').set('acls', objs);
|
||||
}).then(function() {
|
||||
controller.transitionToRoute('acls');
|
||||
controller.set('isLoading', false);
|
||||
notify('ACL token deleted', 3000);
|
||||
});
|
||||
}).fail(function(response) {
|
||||
// Render the error message on the form if the request failed
|
||||
controller.set('errorMessage', 'Received error while processing: ' + response.statusText);
|
||||
controller.set('isLoading', false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateAcl: function() {
|
||||
this.set('isLoading', true);
|
||||
|
||||
var controller = this;
|
||||
var acl = controller.get('model');
|
||||
var dc = controller.get('dc').get('datacenter');
|
||||
var token = App.get('settings.token');
|
||||
|
||||
// Update the ACL
|
||||
Ember.$.ajax({
|
||||
url: formatUrl('/v1/acl/update', dc, token),
|
||||
type: 'PUT',
|
||||
data: JSON.stringify(acl)
|
||||
}).then(function(response) {
|
||||
// transition to the acl
|
||||
controller.set('isLoading', false);
|
||||
notify('ACL updated successfully', 3000);
|
||||
}).fail(function(response) {
|
||||
// Render the error message on the form if the request failed
|
||||
notify('Received error while creating ACL: ' + response.statusText, 8000);
|
||||
controller.set('isLoading', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
App.SettingsController = Ember.ObjectController.extend({
|
||||
actions: {
|
||||
reset: function() {
|
||||
this.set('isLoading', true);
|
||||
var controller = this;
|
||||
|
||||
if (window.confirm("Are your sure you want to reset your settings?")) {
|
||||
localStorage.clear();
|
||||
controller.set('content', App.Settings.create());
|
||||
notify('Settings reset', 3000);
|
||||
this.set('isLoading', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -28,6 +28,24 @@ Ember.Handlebars.helper('sessionName', function(session) {
|
|||
}
|
||||
});
|
||||
|
||||
Ember.Handlebars.helper('aclName', function(name, id) {
|
||||
if (name === "") {
|
||||
return id;
|
||||
} else {
|
||||
return new Handlebars.SafeString(name + ' <small class="pull-right">' + id + '</small>');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Ember.Handlebars.helper('formatRules', function(rules) {
|
||||
if (rules === "") {
|
||||
return "No rules defined";
|
||||
} else {
|
||||
return rules;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// We need to do this because of our global namespace properties. The
|
||||
// service.Tags
|
||||
Ember.Handlebars.helper('serviceTagMessage', function(tags) {
|
||||
|
@ -35,3 +53,27 @@ Ember.Handlebars.helper('serviceTagMessage', function(tags) {
|
|||
return "No tags";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Sends a new notification to the UI
|
||||
function notify(message, ttl) {
|
||||
if (window.notifications !== undefined && window.notifications.length > 0) {
|
||||
$(window.notifications).each(function(i, v) {
|
||||
v.dismiss();
|
||||
});
|
||||
}
|
||||
var notification = new NotificationFx({
|
||||
message : '<p>'+ message + '</p>',
|
||||
layout : 'growl',
|
||||
effect : 'slide',
|
||||
type : 'notice',
|
||||
ttl: ttl,
|
||||
});
|
||||
|
||||
// show the notification
|
||||
notification.show();
|
||||
|
||||
// Add the notification to the queue to be closed
|
||||
window.notifications = [];
|
||||
window.notifications.push(notification);
|
||||
}
|
||||
|
|
|
@ -239,3 +239,44 @@ App.Key = Ember.Object.extend(Ember.Validations.Mixin, {
|
|||
return parts.join("/") + "/";
|
||||
}.property('Key')
|
||||
});
|
||||
|
||||
//
|
||||
// An ACL
|
||||
//
|
||||
App.Acl = Ember.Object.extend({
|
||||
isNotAnon: function() {
|
||||
if (this.get('ID') === "anonymous"){
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}.property('ID')
|
||||
});
|
||||
|
||||
// Wrap localstorage with an ember object
|
||||
App.Settings = Ember.Object.extend({
|
||||
unknownProperty: function(key) {
|
||||
return localStorage[key];
|
||||
},
|
||||
|
||||
setUnknownProperty: function(key, value) {
|
||||
if(Ember.isNone(value)) {
|
||||
delete localStorage[key];
|
||||
} else {
|
||||
localStorage[key] = value;
|
||||
}
|
||||
this.notifyPropertyChange(key);
|
||||
return value;
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this.beginPropertyChanges();
|
||||
for (var i=0, l=localStorage.length; i<l; i++){
|
||||
this.set(localStorage.key(i));
|
||||
}
|
||||
localStorage.clear();
|
||||
this.endPropertyChanges();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,13 @@ window.App = Ember.Application.create({
|
|||
currentPath: ''
|
||||
});
|
||||
|
||||
Ember.Application.initializer({
|
||||
name: 'settings',
|
||||
|
||||
initialize: function(container, application) {
|
||||
application.set('settings', App.Settings.create());
|
||||
}
|
||||
});
|
||||
|
||||
App.Router.map(function() {
|
||||
// Our parent datacenter resource sets the namespace
|
||||
|
@ -25,7 +32,19 @@ App.Router.map(function() {
|
|||
this.route("show", { path: "/*key" });
|
||||
// Edit a specific key
|
||||
this.route("edit", { path: "/*key/edit" });
|
||||
})
|
||||
});
|
||||
// ACLs
|
||||
this.resource("acls", { path: "/acls" }, function(){
|
||||
this.route("show", { path: "/:id" });
|
||||
});
|
||||
|
||||
// Shows a page explaining that ACLs haven't been set-up
|
||||
this.route("aclsdisabled", { path: "/aclsdisabled" });
|
||||
// Shows a page explaining that the ACL key being used isn't
|
||||
// authorized
|
||||
this.route("unauthorized", { path: "/unauthorized" });
|
||||
|
||||
this.resource("settings", { path: "/settings" });
|
||||
});
|
||||
|
||||
// Shows a datacenter picker. If you only have one
|
||||
|
|
|
@ -299,3 +299,81 @@ App.NodesRoute = App.BaseRoute.extend({
|
|||
controller.set('nodes', model);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
App.AclsRoute = App.BaseRoute.extend({
|
||||
model: function(params) {
|
||||
var dc = this.modelFor('dc').dc;
|
||||
var token = App.get('settings.token');
|
||||
// Return a promise containing the ACLS
|
||||
return Ember.$.getJSON(formatUrl('/v1/acl/list', dc, token)).then(function(data) {
|
||||
objs = [];
|
||||
data.map(function(obj){
|
||||
if (obj.ID === "anonymous") {
|
||||
objs.unshift(App.Acl.create(obj));
|
||||
} else {
|
||||
objs.push(App.Acl.create(obj));
|
||||
}
|
||||
});
|
||||
return objs;
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
error: function(error, transition) {
|
||||
// If consul returns 401, ACLs are disabled
|
||||
if (error && error.status === 401) {
|
||||
this.transitionTo('dc.aclsdisabled');
|
||||
// If consul returns 403, they key isn't authorized for that
|
||||
// action.
|
||||
} else if (error && error.status === 403) {
|
||||
this.transitionTo('dc.unauthorized');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set('acls', model);
|
||||
controller.set('newAcl', App.Acl.create());
|
||||
}
|
||||
});
|
||||
|
||||
App.AclsShowRoute = App.BaseRoute.extend({
|
||||
model: function(params) {
|
||||
var dc = this.modelFor('dc').dc;
|
||||
var token = App.get('settings.token');
|
||||
// Return a promise hash of the node and nodes
|
||||
return Ember.RSVP.hash({
|
||||
dc: dc,
|
||||
acl: Ember.$.getJSON(formatUrl('/v1/acl/info/'+ params.id, dc, token)).then(function(data) {
|
||||
return App.Acl.create(data[0]);
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function(controller, models) {
|
||||
controller.set('content', models.acl);
|
||||
}
|
||||
});
|
||||
|
||||
App.SettingsRoute = App.BaseRoute.extend({
|
||||
model: function(params) {
|
||||
return App.get('settings');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Adds any global parameters we need to set to a url/path
|
||||
function formatUrl(url, dc, token) {
|
||||
if (url.indexOf("?") > 0) {
|
||||
// If our url has existing params
|
||||
url = url + "&dc=" + dc;
|
||||
url = url + "&token=" + token;
|
||||
} else {
|
||||
// Our url doesn't have params
|
||||
url = url + "?dc=" + dc;
|
||||
url = url + "&token=" + token;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
|
|
@ -62,3 +62,20 @@ App.KvListView = Ember.View.extend({
|
|||
App.ActionBarView = Ember.View.extend({
|
||||
templateName: 'actionbar'
|
||||
});
|
||||
|
||||
// ACLS
|
||||
|
||||
App.AclView = Ember.View.extend({
|
||||
templateName: 'acls',
|
||||
});
|
||||
|
||||
App.AclsShowView = Ember.View.extend({
|
||||
templateName: 'acl'
|
||||
});
|
||||
|
||||
|
||||
// Settings
|
||||
|
||||
App.SettingsView = Ember.View.extend({
|
||||
templateName: 'settings',
|
||||
});
|
||||
|
|
80
ui/javascripts/libs/classie.js
Executable file
80
ui/javascripts/libs/classie.js
Executable file
|
@ -0,0 +1,80 @@
|
|||
/*!
|
||||
* classie - class helper functions
|
||||
* from bonzo https://github.com/ded/bonzo
|
||||
*
|
||||
* classie.has( elem, 'my-class' ) -> true/false
|
||||
* classie.add( elem, 'my-new-class' )
|
||||
* classie.remove( elem, 'my-unwanted-class' )
|
||||
* classie.toggle( elem, 'my-class' )
|
||||
*/
|
||||
|
||||
/*jshint browser: true, strict: true, undef: true */
|
||||
/*global define: false */
|
||||
|
||||
( function( window ) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// class helper functions from bonzo https://github.com/ded/bonzo
|
||||
|
||||
function classReg( className ) {
|
||||
return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
|
||||
}
|
||||
|
||||
// classList support for class management
|
||||
// altho to be fair, the api sucks because it won't accept multiple classes at once
|
||||
var hasClass, addClass, removeClass;
|
||||
|
||||
if ( 'classList' in document.documentElement ) {
|
||||
hasClass = function( elem, c ) {
|
||||
return elem.classList.contains( c );
|
||||
};
|
||||
addClass = function( elem, c ) {
|
||||
elem.classList.add( c );
|
||||
};
|
||||
removeClass = function( elem, c ) {
|
||||
elem.classList.remove( c );
|
||||
};
|
||||
}
|
||||
else {
|
||||
hasClass = function( elem, c ) {
|
||||
return classReg( c ).test( elem.className );
|
||||
};
|
||||
addClass = function( elem, c ) {
|
||||
if ( !hasClass( elem, c ) ) {
|
||||
elem.className = elem.className + ' ' + c;
|
||||
}
|
||||
};
|
||||
removeClass = function( elem, c ) {
|
||||
elem.className = elem.className.replace( classReg( c ), ' ' );
|
||||
};
|
||||
}
|
||||
|
||||
function toggleClass( elem, c ) {
|
||||
var fn = hasClass( elem, c ) ? removeClass : addClass;
|
||||
fn( elem, c );
|
||||
}
|
||||
|
||||
var classie = {
|
||||
// full names
|
||||
hasClass: hasClass,
|
||||
addClass: addClass,
|
||||
removeClass: removeClass,
|
||||
toggleClass: toggleClass,
|
||||
// short names
|
||||
has: hasClass,
|
||||
add: addClass,
|
||||
remove: removeClass,
|
||||
toggle: toggleClass
|
||||
};
|
||||
|
||||
// transport
|
||||
if ( typeof define === 'function' && define.amd ) {
|
||||
// AMD
|
||||
define( classie );
|
||||
} else {
|
||||
// browser global
|
||||
window.classie = classie;
|
||||
}
|
||||
|
||||
})( window );
|
0
ui/javascripts/libs/classie.min.js
vendored
Normal file
0
ui/javascripts/libs/classie.min.js
vendored
Normal file
146
ui/javascripts/libs/notificationFx.js
Normal file
146
ui/javascripts/libs/notificationFx.js
Normal file
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* notificationFx.js v1.0.0
|
||||
* http://www.codrops.com
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Copyright 2014, Codrops
|
||||
* http://www.codrops.com
|
||||
*/
|
||||
;( function( window ) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var docElem = window.document.documentElement,
|
||||
// animation end event name
|
||||
animEndEventName = "webkitAnimationEnd";
|
||||
|
||||
/**
|
||||
* extend obj function
|
||||
*/
|
||||
function extend( a, b ) {
|
||||
for( var key in b ) {
|
||||
if( b.hasOwnProperty( key ) ) {
|
||||
a[key] = b[key];
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* NotificationFx function
|
||||
*/
|
||||
function NotificationFx( options ) {
|
||||
this.options = extend( {}, this.options );
|
||||
extend( this.options, options );
|
||||
this._init();
|
||||
}
|
||||
|
||||
/**
|
||||
* NotificationFx options
|
||||
*/
|
||||
NotificationFx.prototype.options = {
|
||||
// element to which the notification will be appended
|
||||
// defaults to the document.body
|
||||
wrapper : document.body,
|
||||
// the message
|
||||
message : 'yo!',
|
||||
// layout type: growl|attached|bar|other
|
||||
layout : 'growl',
|
||||
// effects for the specified layout:
|
||||
// for growl layout: scale|slide|genie|jelly
|
||||
// for attached layout: flip|bouncyflip
|
||||
// for other layout: boxspinner|cornerexpand|loadingcircle|thumbslider
|
||||
// ...
|
||||
effect : 'slide',
|
||||
// notice, warning, error, success
|
||||
// will add class ns-type-warning, ns-type-error or ns-type-success
|
||||
type : 'error',
|
||||
// if the user doesn´t close the notification then we remove it
|
||||
// after the following time
|
||||
ttl : 6000,
|
||||
// callbacks
|
||||
onClose : function() { return false; },
|
||||
onOpen : function() { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
* init function
|
||||
* initialize and cache some vars
|
||||
*/
|
||||
NotificationFx.prototype._init = function() {
|
||||
// create HTML structure
|
||||
this.ntf = document.createElement( 'div' );
|
||||
this.ntf.className = 'ns-box ns-' + this.options.layout + ' ns-effect-' + this.options.effect + ' ns-type-' + this.options.type;
|
||||
var strinner = '<div class="ns-box-inner">';
|
||||
strinner += this.options.message;
|
||||
strinner += '</div>';
|
||||
strinner += '<span class="ns-close"></span></div>';
|
||||
this.ntf.innerHTML = strinner;
|
||||
|
||||
// append to body or the element specified in options.wrapper
|
||||
this.options.wrapper.insertBefore( this.ntf, this.options.wrapper.firstChild );
|
||||
|
||||
// dismiss after [options.ttl]ms
|
||||
var self = this;
|
||||
this.dismissttl = setTimeout( function() {
|
||||
if( self.active ) {
|
||||
self.dismiss();
|
||||
}
|
||||
}, this.options.ttl );
|
||||
|
||||
// init events
|
||||
this._initEvents();
|
||||
};
|
||||
|
||||
/**
|
||||
* init events
|
||||
*/
|
||||
NotificationFx.prototype._initEvents = function() {
|
||||
var self = this;
|
||||
// dismiss notification
|
||||
this.ntf.querySelector( '.ns-close' ).addEventListener( 'click', function() { self.dismiss(); } );
|
||||
};
|
||||
|
||||
/**
|
||||
* show the notification
|
||||
*/
|
||||
NotificationFx.prototype.show = function() {
|
||||
this.active = true;
|
||||
classie.remove( this.ntf, 'ns-hide' );
|
||||
classie.add( this.ntf, 'ns-show' );
|
||||
this.options.onOpen();
|
||||
};
|
||||
|
||||
/**
|
||||
* dismiss the notification
|
||||
*/
|
||||
NotificationFx.prototype.dismiss = function() {
|
||||
var self = this;
|
||||
this.active = false;
|
||||
clearTimeout( this.dismissttl );
|
||||
classie.remove( this.ntf, 'ns-show' );
|
||||
setTimeout( function() {
|
||||
classie.add( self.ntf, 'ns-hide' );
|
||||
|
||||
// callback
|
||||
self.options.onClose();
|
||||
}, 25 );
|
||||
|
||||
// after animation ends remove ntf from the DOM
|
||||
var onEndAnimationFn = function( ev ) {
|
||||
if( ev.target !== self.ntf ) return false;
|
||||
this.removeEventListener( animEndEventName, onEndAnimationFn );
|
||||
self.options.wrapper.removeChild( this );
|
||||
};
|
||||
|
||||
this.ntf.addEventListener( animEndEventName, onEndAnimationFn );
|
||||
};
|
||||
|
||||
/**
|
||||
* add to global namespace
|
||||
*/
|
||||
window.NotificationFx = NotificationFx;
|
||||
|
||||
} )( window );
|
|
@ -8,6 +8,8 @@ libs = [
|
|||
"javascripts/libs/ember.min.js",
|
||||
"javascripts/libs/ember-validations.min.js",
|
||||
"javascripts/libs/list-view.min.js",
|
||||
"javascripts/libs/classie.js",
|
||||
"javascripts/libs/notificationFx.js",
|
||||
]
|
||||
|
||||
app = [
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.btn-primary, &.active {
|
||||
&.btn-primary {
|
||||
color: $purple-dark;
|
||||
background-color: transparent;
|
||||
border: 2px solid $purple;
|
||||
|
@ -61,7 +61,6 @@
|
|||
background-color: lighten($green-faded, 24%);
|
||||
color: darken($green-dark, 10%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.btn-danger {
|
||||
|
@ -73,6 +72,24 @@
|
|||
background-color: lighten($red, 38%);
|
||||
color: darken($red, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.active {
|
||||
color: $purple-dark;
|
||||
background-color: transparent;
|
||||
border: 2px solid $purple;
|
||||
|
||||
&:hover {
|
||||
background-color: $light-purple;
|
||||
color: darken($purple, 10%);
|
||||
}
|
||||
|
||||
&.btn-noactive {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
border: 2px solid #ccc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -89,3 +106,17 @@
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
.topbar {
|
||||
.btn.icon {
|
||||
min-width: 50px;
|
||||
font-size: 30px;
|
||||
height: 33px;
|
||||
padding: 0;
|
||||
.wrap {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,3 +20,7 @@
|
|||
background-color: $gray-background;
|
||||
}
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: 130px;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
.btn {
|
||||
margin-top: 20px;
|
||||
min-width: 140px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.btn-dropdown {
|
||||
|
|
267
ui/styles/_notifications.scss
Normal file
267
ui/styles/_notifications.scss
Normal file
|
@ -0,0 +1,267 @@
|
|||
.ns-box {
|
||||
position: fixed;
|
||||
background: lighten(black, 40%);
|
||||
padding: 14px;
|
||||
line-height: 1.4;
|
||||
z-index: 1000;
|
||||
min-width: 400px;
|
||||
pointer-events: none;
|
||||
color: rgba(250,251,255,0.95);
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.ns-box.ns-show {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.ns-box a {
|
||||
color: inherit;
|
||||
opacity: 0.7;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ns-box a:hover,
|
||||
.ns-box a:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ns-box p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ns-box.ns-show,
|
||||
.ns-box.ns-visible {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.ns-close {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
overflow: hidden;
|
||||
text-indent: 100%;
|
||||
cursor: pointer;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.ns-close:hover,
|
||||
.ns-close:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ns-close::before,
|
||||
.ns-close::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
height: 60%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.ns-close:hover::before,
|
||||
.ns-close:hover::after {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.ns-close::before {
|
||||
-webkit-transform: translate(-50%,-50%) rotate(45deg);
|
||||
transform: translate(-50%,-50%) rotate(45deg);
|
||||
}
|
||||
|
||||
.ns-close::after {
|
||||
-webkit-transform: translate(-50%,-50%) rotate(-45deg);
|
||||
transform: translate(-50%,-50%) rotate(-45deg);
|
||||
}
|
||||
|
||||
|
||||
/* Growl-style notifications */
|
||||
|
||||
.ns-growl {
|
||||
top: 30px;
|
||||
left: 30px;
|
||||
max-width: 300px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.ns-growl p {
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
[class^="ns-effect-"].ns-growl.ns-hide,
|
||||
[class*=" ns-effect-"].ns-growl.ns-hide {
|
||||
-webkit-animation-direction: reverse;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
|
||||
|
||||
/* Slide */
|
||||
.ns-effect-slide {
|
||||
top: 30px;
|
||||
}
|
||||
|
||||
.ns-effect-slide .ns-close:hover::before,
|
||||
.ns-effect-slide .ns-close:hover::after {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.ns-effect-slide.ns-show {
|
||||
-webkit-animation-name: animSlideElastic;
|
||||
animation-name: animSlideElastic;
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animSlideElastic {
|
||||
0% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); }
|
||||
1.666667% { -webkit-transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); }
|
||||
3.333333% { -webkit-transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); }
|
||||
5% { -webkit-transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); }
|
||||
6.666667% { -webkit-transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); }
|
||||
8.333333% { -webkit-transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); }
|
||||
10% { -webkit-transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); }
|
||||
11.666667% { -webkit-transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); }
|
||||
13.333333% { -webkit-transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); }
|
||||
15% { -webkit-transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); }
|
||||
16.666667% { -webkit-transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); }
|
||||
18.333333% { -webkit-transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); }
|
||||
20% { -webkit-transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); }
|
||||
21.666667% { -webkit-transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); }
|
||||
23.333333% { -webkit-transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); }
|
||||
25% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); }
|
||||
26.666667% { -webkit-transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); }
|
||||
28.333333% { -webkit-transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); }
|
||||
30% { -webkit-transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); }
|
||||
31.666667% { -webkit-transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); }
|
||||
33.333333% { -webkit-transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); }
|
||||
35% { -webkit-transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); }
|
||||
36.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); }
|
||||
38.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); }
|
||||
40% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); }
|
||||
41.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); }
|
||||
43.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); }
|
||||
45% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); }
|
||||
46.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); }
|
||||
48.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); }
|
||||
50% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); }
|
||||
51.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); }
|
||||
53.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); }
|
||||
55% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); }
|
||||
56.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); }
|
||||
58.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); }
|
||||
60% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); }
|
||||
61.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); }
|
||||
63.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); }
|
||||
65% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); }
|
||||
66.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); }
|
||||
68.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); }
|
||||
70% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); }
|
||||
71.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); }
|
||||
73.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); }
|
||||
75% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); }
|
||||
76.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); }
|
||||
78.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); }
|
||||
80% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); }
|
||||
81.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); }
|
||||
83.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); }
|
||||
85% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); }
|
||||
86.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); }
|
||||
88.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); }
|
||||
90% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); }
|
||||
91.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); }
|
||||
93.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); }
|
||||
95% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); }
|
||||
96.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); }
|
||||
98.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); }
|
||||
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
|
||||
}
|
||||
|
||||
@keyframes animSlideElastic {
|
||||
0% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); }
|
||||
1.666667% { -webkit-transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); }
|
||||
3.333333% { -webkit-transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); }
|
||||
5% { -webkit-transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); }
|
||||
6.666667% { -webkit-transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); }
|
||||
8.333333% { -webkit-transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); }
|
||||
10% { -webkit-transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); }
|
||||
11.666667% { -webkit-transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); }
|
||||
13.333333% { -webkit-transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); }
|
||||
15% { -webkit-transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); }
|
||||
16.666667% { -webkit-transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); }
|
||||
18.333333% { -webkit-transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); }
|
||||
20% { -webkit-transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); }
|
||||
21.666667% { -webkit-transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); }
|
||||
23.333333% { -webkit-transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); }
|
||||
25% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); }
|
||||
26.666667% { -webkit-transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); }
|
||||
28.333333% { -webkit-transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); }
|
||||
30% { -webkit-transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); }
|
||||
31.666667% { -webkit-transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); }
|
||||
33.333333% { -webkit-transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); }
|
||||
35% { -webkit-transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); }
|
||||
36.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); }
|
||||
38.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); }
|
||||
40% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); }
|
||||
41.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); }
|
||||
43.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); }
|
||||
45% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); }
|
||||
46.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); }
|
||||
48.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); }
|
||||
50% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); }
|
||||
51.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); }
|
||||
53.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); }
|
||||
55% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); }
|
||||
56.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); }
|
||||
58.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); }
|
||||
60% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); }
|
||||
61.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); }
|
||||
63.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); }
|
||||
65% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); }
|
||||
66.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); }
|
||||
68.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); }
|
||||
70% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); }
|
||||
71.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); }
|
||||
73.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); }
|
||||
75% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); }
|
||||
76.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); }
|
||||
78.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); }
|
||||
80% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); }
|
||||
81.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); }
|
||||
83.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); }
|
||||
85% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); }
|
||||
86.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); }
|
||||
88.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); }
|
||||
90% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); }
|
||||
91.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); }
|
||||
93.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); }
|
||||
95% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); }
|
||||
96.666667% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); }
|
||||
98.333333% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); }
|
||||
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
|
||||
}
|
||||
|
||||
.ns-effect-slide.ns-hide {
|
||||
-webkit-animation-name: animSlide;
|
||||
animation-name: animSlide;
|
||||
-webkit-animation-duration: 0.25s;
|
||||
animation-duration: 0.25s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animSlide {
|
||||
0% { -webkit-transform: translate3d(-30px,0,0) translate3d(-100%,0,0); }
|
||||
100% { -webkit-transform: translate3d(0,0,0); }
|
||||
}
|
||||
|
||||
@keyframes animSlide {
|
||||
0% { -webkit-transform: translate3d(-30px,0,0) translate3d(-100%,0,0); transform: translate3d(-30px,0,0) translate3d(-100%,0,0); }
|
||||
100% { -webkit-transform: translate3d(0,0,0); transform: translate3d(0,0,0); }
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
}
|
||||
|
||||
h4.panel-title {
|
||||
padding: 4px 10px 4px 10px;
|
||||
padding: 4px 10px 4px 2px;
|
||||
font-size: 20px;
|
||||
color: $gray-light;
|
||||
color: $gray-darker;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
@import "buttons";
|
||||
@import "lists";
|
||||
@import "forms";
|
||||
@import "notifications";
|
||||
|
||||
@media (min-width: 1120px) { // + 30
|
||||
.container {
|
||||
|
@ -120,3 +121,10 @@ a {
|
|||
height: 800px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.elip-overflow {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue