Merge branch 'master' into metrics

Conflicts:
	src/ImageCard.react.js
This commit is contained in:
Jeffrey Morgan
2015-02-20 15:32:18 -08:00
34 changed files with 1234 additions and 1562 deletions

View File

@@ -62,6 +62,13 @@ app.on('ready', function() {
e.preventDefault();
});
mainWindow.webContents.on('will-navigate', function (e, url) {
if (url.indexOf('build/index.html#/containers') < 0) {
console.log(url);
e.preventDefault();
}
});
mainWindow.webContents.on('did-finish-load', function() {
if (!argv.test) {
mainWindow.show();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -5,6 +5,8 @@ var remote = require('remote');
var dialog = remote.require('dialog');
var metrics = require('./Metrics');
var ContainerStore = require('./ContainerStore');
var OverlayTrigger = require('react-bootstrap').OverlayTrigger;
var Tooltip = require('react-bootstrap').Tooltip;
var ContainerListItem = React.createClass({
handleItemMouseEnter: function () {
@@ -39,7 +41,18 @@ var ContainerListItem = React.createClass({
render: function () {
var self = this;
var container = this.props.container;
var imageName = container.Config.Image;
var imageNameTokens = container.Config.Image.split('/');
var repo;
if (imageNameTokens.length > 1) {
repo = imageNameTokens[1];
} else {
repo = imageNameTokens[0];
}
var imageName = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>{container.Config.Image}</Tooltip>}>
<div>{repo}</div>
</OverlayTrigger>
);
// Synchronize all animations
var style = {
@@ -48,18 +61,43 @@ var ContainerListItem = React.createClass({
var state;
if (container.State.Downloading) {
state = <div className="state state-downloading"><div style={style} className="downloading-arrow"></div></div>;
state = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>Downloading</Tooltip>}>
<div className="state state-downloading">
<div style={style} className="downloading-arrow"></div>
</div>
</OverlayTrigger>
);
} else if (container.State.Running && !container.State.Paused) {
state = <div className="state state-running"><div style={style} className="runningwave"></div></div>;
state = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>Running</Tooltip>}>
<div className="state state-running"><div style={style} className="runningwave"></div></div>
</OverlayTrigger>
);
} else if (container.State.Restarting) {
state = <div className="state state-restarting" style={style}></div>;
state = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>Restarting</Tooltip>}>
<div className="state state-restarting" style={style}></div>
</OverlayTrigger>
);
} else if (container.State.Paused) {
state = <div className="state state-paused"></div>;
state = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>Paused</Tooltip>}>
<div className="state state-paused"></div>
</OverlayTrigger>
);
} else if (container.State.ExitCode) {
// state = <div className="state state-error"></div>;
state = <div className="state state-stopped"></div>;
state = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>Stopped</Tooltip>}>
<div className="state state-stopped"></div>
</OverlayTrigger>
);
} else {
state = <div className="state state-stopped"></div>;
state = (
<OverlayTrigger placement="bottom" overlay={<Tooltip>Stopped</Tooltip>}>
<div className="state state-stopped"></div>
</OverlayTrigger>
);
}
return (

View File

@@ -40,9 +40,9 @@ var Header = React.createClass({
return (
<div className="header no-drag">
<div className="buttons">
<div className="button button-close red disabled"></div>
<div className="button button-minimize yellow disabled"></div>
<div className="button button-fullscreenclose green enabled" onClick={this.handleFullscreen}></div>
<div className="button button-close disabled"></div>
<div className="button button-minimize disabled"></div>
<div className="button button-fullscreenclose enabled" onClick={this.handleFullscreen}></div>
</div>
<RetinaImage className="logo" src="logo.png"/>
</div>
@@ -51,9 +51,9 @@ var Header = React.createClass({
return (
<div className="header">
<div className="buttons">
<div className="button button-close red enabled" onClick={this.handleClose}></div>
<div className="button button-minimize yellow enabled" onClick={this.handleMinimize}></div>
<div className="button button-fullscreen green enabled" onClick={this.handleFullscreen}></div>
<div className="button button-close enabled" onClick={this.handleClose}></div>
<div className="button button-minimize enabled" onClick={this.handleMinimize}></div>
<div className="button button-fullscreen enabled" onClick={this.handleFullscreen}></div>
</div>
<RetinaImage className="logo" src="logo.png"/>
</div>

View File

@@ -2,7 +2,12 @@ var $ = require('jquery');
var React = require('react/addons');
var RetinaImage = require('react-retina-image');
var ContainerStore = require('./ContainerStore');
<<<<<<< HEAD
var metrics = require('./Metrics');
=======
var OverlayTrigger = require('react-bootstrap').OverlayTrigger;
var Tooltip = require('react-bootstrap').Tooltip;
>>>>>>> master
var ImageCard = React.createClass({
getInitialState: function () {
@@ -44,10 +49,34 @@ var ImageCard = React.createClass({
render: function () {
var self = this;
var name;
if (this.props.image.is_official) {
name = <span><RetinaImage src="official.png"/>{this.props.image.name}</span>;
var imageNameTokens = this.props.image.name.split('/');
var namespace;
var repo;
if (imageNameTokens.length > 1) {
namespace = imageNameTokens[0];
repo = imageNameTokens[1];
} else {
name = <span>{this.props.image.name}</span>;
namespace = "official";
repo = imageNameTokens[0];
}
if (this.props.image.is_official) {
name = (
<div>
<div className="namespace official">{namespace}</div>
<OverlayTrigger placement="bottom" overlay={<Tooltip>{this.props.image.name}</Tooltip>}>
<span className="repo">{repo}</span>
</OverlayTrigger>
</div>
);
} else {
name = (
<div>
<div className="namespace">{namespace}</div>
<OverlayTrigger placement="bottom" overlay={<Tooltip>{this.props.image.name}</Tooltip>}>
<span className="repo">{repo}</span>
</OverlayTrigger>
</div>
);
}
var description;
if (this.props.image.description) {
@@ -77,6 +106,12 @@ var ImageCard = React.createClass({
} else {
tags = <RetinaImage className="tags-loading" src="loading-white.png"/>;
}
var officialBadge;
if (this.props.image.is_official) {
officialBadge = (
<RetinaImage src="official.png" />
);
}
return (
<div className="image-item">
<div className="tag-overlay" onClick={self.handleCloseTagOverlay}>
@@ -86,6 +121,9 @@ var ImageCard = React.createClass({
<RetinaImage src={imgsrc}/>
</div>
<div className="card">
<div className="badges">
{officialBadge}
</div>
<div className="name">
{name}
</div>
@@ -93,13 +131,17 @@ var ImageCard = React.createClass({
{description}
</div>
<div className="actions">
<div className="stars">
<span className="icon icon-star-9"></span>
<span className="text">{this.props.image.star_count}</span>
</div>
<OverlayTrigger placement="bottom" overlay={<Tooltip>Favorites</Tooltip>}>
<div className="stars">
<span className="icon icon-star-9"></span>
<span className="text">{this.props.image.star_count}</span>
</div>
</OverlayTrigger>
<div className="tags">
<span className="icon icon-tag-1"></span>
<span className="text" onClick={self.handleTagOverlayClick.bind(self, this.props.image.name)} data-name={this.props.image.name}>{this.state.chosenTag}</span>
<span className="icon icon-bookmark-2"></span>
<OverlayTrigger placement="bottom" overlay={<Tooltip>Change Tag</Tooltip>}>
<span className="text" onClick={self.handleTagOverlayClick.bind(self, this.props.image.name)} data-name={this.props.image.name}>{this.state.chosenTag}</span>
</OverlayTrigger>
</div>
<div className="action">
<a className="btn btn-action" onClick={self.handleClick.bind(self, this.props.image.name)}>Create</a>

36
styles/animation.less Normal file
View File

@@ -0,0 +1,36 @@
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@-webkit-keyframes translatewave {
from {
-webkit-transform: translateX(0px);
}
to {
-webkit-transform: translateX(20px);
}
}
@-webkit-keyframes translatedownload {
0% {
-webkit-transform: translateY(6px);
opacity: 0;
}
25% {
opacity: 1;
-webkit-transform: translateY(6px);
}
50% {
opacity: 1;
-webkit-transform: translateY(20px);
}
100% {
opacity: 1;
-webkit-transform: translateY(20px);
}
}

View File

@@ -1,56 +0,0 @@
@font-face {
font-family: 'Clear';
src: url('clearsans-regular-webfont.ttf') format('truetype');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-medium-webfont.ttf') format('truetype');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-light-webfont.ttf') format('truetype');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-thin-webfont.ttf') format('truetype');
font-weight: 100;
font-style: normal;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-mediumitalic-webfont.ttf') format('truetype');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-italic-webfont.ttf') format('truetype');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-bolditalic-webfont.ttf') format('truetype');
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: 'Clear Sans';
src: url('clearsans-bold-webfont.ttf') format('truetype');
font-weight: 700;
font-style: normal;
}

153
styles/container-home.less Normal file
View File

@@ -0,0 +1,153 @@
.details-panel.home {
background-color: @color-background;
overflow: hidden;
.content {
display: flex;
flex: 1 auto;
flex-direction: row;
padding: 10px 27px;
.left {
width: 60%;
flex-direction: column;
margin-right: 30px;
}
.right {
width: 40%;
flex-direction: column;
}
.subtext {
text-align: right;
color: @gray-lightest;
margin-top: 2px;
transition: all 0.25s;
&:hover {
color: darken(@gray-lightest, 10%);
}
}
.web-preview {
margin-bottom: 50px;
.widget {
.widget-style();
background-color: white;
width: 100%;
height: 100%;
p {
font-size: 13px;
color: @gray-normal;
padding: 10px;
padding-bottom: 0px;
}
.ip-port {
padding: 20px;
padding-top: 5px;
color: @gray-darkest;
-webkit-user-select: text;
}
.frame {
border: 0;
position: absolute;
left: -100%;
top: -100%;
height: 400%;
width: 401%;
transform: scale(0.5);
}
.frame-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
color: transparent;
transition: all 0.25s;
.icon {
margin-top: 40%;
display: block;
font-size: 60px;
text-align: center;
}
.text {
font-size: 20px;
text-align: center;
}
&:hover {
color: white;
background-color: @gray-darkest;
opacity: 0.75;
}
}
}
}
.mini-logs {
margin-bottom: 50px;
.widget {
.widget-style();
background-color: @gray-darkest;
color: @gray-lightest;
height: 100%;
padding: 10px;
font-family: @font-code;
font-size: 7px;
white-space: pre;
.logs {
overflow: hidden;
height: 100%;
}
p {
margin-bottom: 0px;
}
.mini-logs-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
color: transparent;
transition: all 0.25s;
.icon {
margin-top: 25%;
display: block;
font-size: 60px;
text-align: center;
}
.text {
font-family: @font-regular;
font-size: 20px;
text-align: center;
}
&:hover {
color: white;
background-color: @gray-darkest;
opacity: 0.75;
}
}
}
}
.folders {
.widget {
.widget-style();
padding: 10px 5px;
background-color: white;
display: flex;
.folder {
width: 110px;
padding: 5px;
&:hover {
background-color: @color-background;
border-radius: 10px;
}
img {
display: block;
margin: 0 auto;
}
.text {
margin-top: 4px;
text-align: center;
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
.details-panel.logs {
background-color: @gray-darkest;
-webkit-user-select: text;
font-family: @font-code;
font-size: 12px;
padding: 20px 18px;
color: @gray-lightest;
white-space: pre-wrap;
p {
margin-bottom: 0px;
}
}

View File

@@ -1,207 +0,0 @@
.create-modal {
@modal-padding: 32px;
@search-width: 372px;
@custom-width: 0;
.modal-dialog {
margin-top: 80px;
width: calc(@modal-padding + @search-width + 2 * @modal-padding + @custom-width);
}
.modal-content {
//box-shadow: 0 3px 15px rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.10);
border: none; //1px solid #ccc;
height: 610px;
display: flex;
}
.modal-body {
flex: 1 auto;
display: flex;
flex-direction: row;
padding: 32px 32px;
.popover {
width: 180px;
text-align: center;
.popover-content {
max-height: 160px;
padding: 0;
overflow: auto;
}
ul {
padding: 0;
list-style: none;
margin: 0;
li {
padding: 8px 0;
border-bottom: 1px solid #eee;
&:hover {
color: white;
background: @brand-primary;
}
}
}
.tags-loading {
text-align: center;
margin: 14px auto;
text-align: center;
-webkit-animation-name: spin;
-webkit-animation-duration: 1.8s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
}
section.search {
min-width: 404px;
.question {
text-align: right;
}
.search-bar {
position: relative;
.loading {
position: absolute;
left: 13px;
top: 10px;
width: 20px;
height: 20px;
-webkit-animation-name: spin;
-webkit-animation-duration: 1.8s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
.search-icon {
font-size: 20px;
color: @gray-lighter;
position: absolute;
top: 9px;
left: 14px;
}
input {
border-radius: 20px;
font-size: 13px;
height: 38px;
padding: 8px 16px 8px 40px;
color: @gray-darkest;
margin-bottom: 3px;
border-color: @gray-lightest;
box-shadow: none;
&:focus {
box-shadow: none;
border-color: @gray-lighter;
}
&::-webkit-input-placeholder {
color: #ddd;
font-weight: 300;
}
}
}
.results {
overflow: auto;
padding-bottom: 80px;
.no-results {
text-align: center;
h3 {
color: #ABC0C0;
font-size: 16px;
margin-top: 160px;
}
}
.title {
flex: 0 auto;
margin-top: 16px;
}
ul {
margin-top: 10px;
list-style: none;
padding: 0;
li {
&:hover {
background-color: lighten(@gray-lightest, 17.5%);
}
display: flex;
flex-direction: row;
padding: 8px 14px 5px 14px;
//margin: 12px;
border-bottom: 1px solid #eee;
&:last-child {
border-bottom: 0;
}
.info {
.name {
color: @gray-darkest;
max-width: 278px;
img {
margin-right: 6px;
margin-left: 2px;
}
font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.properties {
color: @gray-lighter;
margin-top: 2px;
.star-count {
font-size: 10px;
display: inline-block;
position: relative;
top: -3px;
left: 1px;
height: 17px;
}
.icon {
overflow: hidden;
display: inline-block;
font-size: 15px;
height: 15px;
}
}
flex: 0 auto;
}
.action {
position: relative;
top: 5px;
text-align: right;
flex: 1 auto;
ul {
text-align: center;
ul {
overflow: auto;
max-height: 300px;
}
}
.icon {
position: relative;
top: 2px;
font-size: 11px;
}
}
}
}
}
}
}
}
.modal-backdrop.in {
background: rgba(227,230,230,0.95);
opacity: 1;
height: 100%;
}

View File

@@ -0,0 +1,199 @@
.details-panel .settings {
display: flex;
flex: 1 auto;
flex-direction: row;
.settings-menu {
min-width: 180px;
flex: 0 auto;
ul {
position: fixed;
margin: 0;
padding: 0;
padding-top: 14px;
display: flex;
flex-direction: column;
a {
min-width: 160px;
margin-left: 12px;
color: @gray-normal;
flex-shrink: 0;
cursor: default;
outline: none;
margin-bottom: 10px;
&.active {
li {
color: white;
border-radius: 40px;
.brand-gradient();
}
}
&:hover {
text-decoration: none;
li {
cursor: default;
border-radius: 40px;
background-color: @color-background;
}
}
&:focus {
text-decoration: none;
}
}
li {
vertical-align: middle;
padding: 5px 12px;
display: flex;
flex-direction: row;
}
}
}
.settings-panel {
padding-left: 20px;
flex: 1 auto;
overflow-x: hidden;
.settings-section {
margin-bottom: 40px;
}
.container-name {
margin-bottom: 20px;
input {
width: 40%;
}
p {
font-weight: 300;
margin-top: 5px;
color: @gray-lighter;
font-size: 12px;
strong {
font-weight: 500;
}
}
}
.env-vars-labels {
width: 100%;
font-size: 12px;
color: @gray-lightest;
margin-left: 5px;
margin-bottom: 5px;
margin-top: 20px;
.label-key {
display: inline-block;
margin-right: 30px;
width: 30%;
}
.label-val {
display: inline-block;
width: 50%;
}
}
.env-vars {
margin-bottom: 20px;
.keyval-row {
margin-bottom: 5px;
}
input {
margin-right: 30px;
&.key {
width: 30%;
}
&.val {
width: 50%;
}
}
}
.table {
margin-bottom: 0;
.icon-arrow-right {
color: #BBB;
font-size: 20px;
margin: 0px 10px;
flex: 0 auto;
min-width: 13px;
}
&.ports {
.table-labels {
margin-top: 20px;
flex: 1 auto;
display: flex;
font-size: 12px;
color: @gray-lightest;
.label-left {
flex: 0 auto;
min-width: 85px;
margin-right: 30px;
text-align: right;
}
.label-right {
flex: 1 auto;
display: inline-block;
margin-left: 10px;
width: 40%;
}
}
.table-values {
flex: 1 auto;
display: flex;
flex-direction: row;
margin: 8px 0;
.value-left {
text-align: right;
min-width: 85px;
flex: 0 auto;
padding: 0px;
}
.value-right {
flex: 1 auto;
-webkit-user-select: text;
max-width: 170px;
padding: 0px;
}
label {
margin-left: 8px;
margin-top: 1px;
font-weight: 400;
font-size: 13px;
}
input[type="checked"] {
}
}
}
&.volumes {
.table-labels {
margin-top: 20px;
flex: 1 auto;
display: flex;
font-size: 12px;
color: @gray-lightest;
.label-left {
flex: 0 auto;
margin-right: 30px;
}
.label-right {
flex: 1 auto;
display: inline-block;
margin-left: 10px;
}
}
.table-values {
flex: 1 auto;
display: flex;
flex-direction: row;
margin: 8px 0;
.value-left {
flex: 0 auto;
padding: 0px;
}
.value-right {
flex: 1 auto;
-webkit-user-select: text;
padding: 0px;
}
.btn {
margin-left: 10px;
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,12 @@
@import "bootstrap/bootstrap.less";
.header {
position: absolute;
min-width: 100%;
flex: 0;
min-height: 40px;
-webkit-app-region: drag;
-webkit-user-select: none;
// border-bottom: 1px solid #efefef;
&.no-drag {
-webkit-app-region: no-drag;
}
.logo {
position: relative;
float: right;
@@ -20,13 +14,11 @@
right: 10px;
z-index: 1000;
}
.buttons {
display: inline-block;
position: relative;
top: 10px;
left: 15px;
&:hover {
.button-minimize.enabled {
.at2x('minimize.png', 10px, 10px);
@@ -41,42 +33,23 @@
.at2x('fullscreenclose.png', 10px, 10px);
}
}
.button {
box-sizing: border-box;
display: inline-block;
background: white;
margin-right: 9px;
height: 12px;
width: 12px;
border: 1px solid #CCD3D5;
border-radius: 6px;
box-shadow: 0px 1px 1px 0px rgba(234,234,234,0.50);
-webkit-app-region: no-drag;
&.red {
background-color: #FF5F52;
border-color: #E33E32;
.traffic-light();
&.button-close {
background-color: @traffic-light-red;
border-color: @traffic-light-red-border;
}
&.yellow {
background-color: #FFBE05;
border-color: #E2A100;
&.button-minimize {
background-color: @traffic-light-yellow;
border-color: @traffic-light-yellow-border;
}
&.green {
background-color: #15CC35;
border-color: #17B230;
&.button-fullscreen {
background-color: @traffic-light-green;
border-color: @traffic-light-green-border;
}
&.disabled {
background-color: #DDDDDD;
border: 1px solid #D3D3D3;
}
&.enabled:hover {
box-shadow: 0px 1px 1px 0px rgba(195,198,201,0.50);
}
&.enabled:hover:active {
cursor: default;
-webkit-filter: brightness(92%);
background-color: @traffic-light-gray;
border-color: @traffic-light-gray-border;
}
}
}

12
styles/layout.less Normal file
View File

@@ -0,0 +1,12 @@
.containers {
box-sizing: border-box;
height: 100%;
display: flex;
flex-direction: column;
.containers-body {
flex: 1;
display: flex;
flex-direction: row;
padding: 0px;
}
}

249
styles/left-panel.less Normal file
View File

@@ -0,0 +1,249 @@
/* Sidebar */
.sidebar {
padding-top: 28px;
background-color: white;
margin: 0;
border-right: 1px solid @color-divider;
display: flex;
flex-direction: column;
min-width: 260px;
box-sizing: border-box;
.sidebar-header {
flex: 0 auto;
min-width: 240px;
min-height: 47px;
display: flex;
border-bottom: 1px solid transparent;
transition: border-bottom 0.25s;
&.sep {
border-bottom: 1px solid #EEE;
box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.03);
}
h4 {
align-self: flex-start;
padding-left: 26px;
margin: 14px 0 0;
display: inline-block;
position: relative;
}
.create {
flex: 1 auto;
text-align: right;
margin-right: 20px;
margin-top: 3px;
.btn-new {
font-size: 24px;
color: @brand-action;
transition: all 0.25s;
&:hover {
color: darken(@brand-action, 15%);
}
}
}
}
.sidebar-containers {
position: relative;
flex: 1 auto;
overflow-y: auto;
overflow-x: hidden;
box-sizing: border-box;
max-width: 260px;
ul {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
.new-container-item {
.info {
position: relative;
top: 9px;
}
}
a {
color: inherit;
flex-shrink: 0;
cursor: default;
outline: none;
&:hover {
text-decoration: none;
cursor: default;
}
&:focus {
text-decoration: none;
}
&.active {
background: @brand-action;
li {
height: 57px;
border-bottom: none;
.brand-gradient();
.name {
color: white;
}
.image {
color: white;
opacity: 0.8;
}
.btn-delete {
font-size: 24px;
color: white;
position: relative;
z-index: 9999;
}
.state-new {
.at2x('container-white.png', 20px, 20px);
}
.state-running {
.at2x('running-white.png', 20px, 20px);
.runningwave {
.at2x('runningwave-white.png', 20px, 20px);
}
}
.state-paused {
.at2x('wavy-white.png', 20px, 20px);
}
.state-stopped {
.at2x('stopped-white.png', 20px, 20px);
}
.state-downloading {
.at2x('downloading-white.png', 20px, 20px);
.downloading-arrow {
.at2x('downloading-arrow-white.png', 20px, 20px);
}
}
}
}
}
li {
vertical-align: middle;
padding: 10px 16px 10px 26px;
display: flex;
flex-direction: row;
height: 57px;
.info {
font-size: 13px;
margin-left: 16px;
.name {
text-overflow: ellipsis;
max-width: 140px;
white-space: nowrap;
overflow: hidden;
font-size: 14px;
font-weight: 400;
color: @gray-darkest;
}
.image {
color: @gray-lighter;
font-size: 10px;
font-weight: 400;
text-overflow: ellipsis;
max-width: 140px;
white-space: nowrap;
overflow: hidden;
}
}
.action {
display: none;
flex: 1;
position: relative;
top: 5px;
text-align: right;
margin-right: 4px;
.btn-delete {
font-size: 24px;
color: @gray-lighter;
position: relative;
z-index: 9999;
}
}
.state {
margin-top: 9px;
display: inline-block;
position: relative;
min-width: 20px;
height: 20px;
}
.state-error {
.at2x('error.png', 20px, 20px);
}
.state-stopped {
.at2x('stopped.png', 20px, 20px);
}
.state-paused {
.at2x('paused.png', 20px, 20px);
}
.state-new {
.at2x('container.png', 20px, 20px);
}
.state-downloading {
.at2x('downloading.png', 20px, 20px);
overflow: hidden;
.downloading-arrow {
width: 20px;
height: 20px;
.at2x('downloading-arrow.png', 20px, 20px);
position: absolute;
-webkit-animation-name: translatedownload;
-webkit-animation-duration: 1.8s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
}
.state-running {
.at2x('running.png', 20px, 20px);
overflow: hidden;
.runningwave {
position: absolute;
width: 40px;
height: 20px;
left: -20px;
.at2x('runningwave.png', 20px, 20px);
-webkit-animation-name: translatewave;
-webkit-animation-duration: 8.0s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
}
.state-restarting {
display: inline-block;
width: 20px;
height: 20px;
.at2x('restarting.png', 20px, 20px);
background-repeat: repeat-x;
-webkit-animation-delay: -1s;
-webkit-animation-name: rotate;
-webkit-animation-duration: 3.0s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
}
}
}
}
/* Auto-Update */
.update-notification {
background-color: white;
opacity: 0.9;
position: fixed;
bottom: 0;
width: 259px;
padding: 10px;
color: @gray-normal;
font-size: 12px;
.text {
position: relative;
top: 3px;
}
.btn {
position: relative;
float: right;
}
}
.update-padding {
position: relative;
height: 40px;
}

View File

@@ -1,6 +1,6 @@
@import "bootstrap/bootstrap.less";
@import "variables.less";
@import "clearsans.less";
@import "mixins.less";
@import "theme.less";
@import "icons.less";
@import "retina.less";
@@ -8,117 +8,23 @@
@import "radial.less";
@import "preferences.less";
@import "header.less";
@import "containers.less";
@import "container-modal.less";
@import "layout.less";
@import "left-panel.less";
@import "right-panel.less";
@import "new-container.less";
@import "container-home.less";
@import "container-logs.less";
@import "container-settings.less";
@import "animation.less";
html, body {
height: 100%;
width: 100%;
overflow: hidden;
-webkit-user-select: none;
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-family: @font-regular;
cursor: default;
img {
pointer-events: none;
}
}
/*::-webkit-scrollbar {
width: 13px;
}
::-webkit-scrollbar-track {
margin: 3px;
-webkit-border-radius: 5px;
border-radius: 5px;
background: none;
}
::-webkit-scrollbar-thumb {
border: 3px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
width: 7px;
border-radius: 8px;
background-color: rgba(0,0,0,0.2);
&:hover {
background-color: rgba(0,0,0,0.25);
}
}*/
.question {
color: @gray-lightest;
font-size: 10px;
}
.popover {
font-family: 'Clear Sans', sans-serif;
color: @gray-normal;
font-weight: 400;
font-size: 13px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.10);
border: 1px solid #ddd;
}
.update-notification {
background-color: white;
opacity: 0.9;
position: fixed;
bottom: 0;
width: 259px;
padding: 10px;
//border-top: 1px solid darken(#FCF8E3, 5%);
color: @gray-normal;
font-size: 12px;
.text {
position: relative;
top: 3px;
}
.btn {
position: relative;
float: right;
}
}
.update-padding {
position: relative;
height: 40px;
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@-webkit-keyframes translatewave {
from {
-webkit-transform: translateX(0px);
}
to {
-webkit-transform: translateX(20px);
}
}
@-webkit-keyframes translatedownload {
0% {
-webkit-transform: translateY(6px);
opacity: 0;
}
25% {
opacity: 1;
-webkit-transform: translateY(6px);
}
50% {
opacity: 1;
-webkit-transform: translateY(20px);
}
100% {
opacity: 1;
-webkit-transform: translateY(20px);
}
}

30
styles/mixins.less Normal file
View File

@@ -0,0 +1,30 @@
.traffic-light() {
box-sizing: border-box;
display: inline-block;
background: white;
margin-right: 9px;
height: 12px;
width: 12px;
border: 1px solid @traffic-light-gray-border;
border-radius: 6px;
box-shadow: 0px 1px 1px 0px rgba(234,234,234,0.50);
-webkit-app-region: no-drag;
&.enabled:hover {
box-shadow: 0px 1px 1px 0px rgba(195,198,201,0.50);
}
&.enabled:hover:active {
cursor: default;
-webkit-filter: brightness(92%);
}
}
.brand-gradient() {
background-image: linear-gradient(-180deg, #24B8EB 4%, #24A3EB 100%);
}
.widget-style() {
border-radius: 4px;
border: 1px solid @gray-lightest;
position: relative;
overflow: hidden;
}

259
styles/new-container.less Normal file
View File

@@ -0,0 +1,259 @@
.new-container {
display: flex;
flex: 1 auto;
flex-direction: column;
padding: 35px 20px 32px 25px;
.results {
display: flex;
flex-direction: column;
flex: 1 auto;
.no-results {
flex: 1 auto;
display: flex;
align-items: center;
.loader {
margin: 0 auto;
margin-top: -20%;
text-align: center;
width: 300px;
h2 {
margin-bottom: 20px;
}
}
h1 {
color: @gray-lightest;
font-size: 24px;
margin: 0 auto;
margin-top: -20%;
}
}
}
.new-container-header {
margin-bottom: 18px;
display: flex;
flex: 0 auto;
.text {
flex: 1 auto;
width: 50%;
font-size: 14px;
color: @gray-lighter;
}
.search {
flex: 1 auto;
margin-right: 30px;
.search-bar {
top: -7px;
position: relative;
.loading {
position: absolute;
left: 10px;
top: 7px;
width: 16px;
height: 16px;
-webkit-animation-name: spin;
-webkit-animation-duration: 1.8s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
.search-icon {
font-size: 18px;
color: @gray-lighter;
position: absolute;
top: 5px;
left: 10px;
}
input {
border-radius: 20px;
font-size: 12px;
height: 30px;
padding: 4px 8px 4px 35px;
color: @gray-darkest;
margin-bottom: 3px;
border-color: @gray-lightest;
box-shadow: none;
&:focus {
box-shadow: none;
border-color: @gray-lighter;
}
&::-webkit-input-placeholder {
color: #DDD;
font-weight: 400;
}
}
}
}
}
}
.result-grid {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
margin-top: 10px;
overflow: auto;
.image-item {
display: flex;
width: 320px;
height: 166px;
border-radius: 4px;
border: 1px solid @gray-lightest;
background-color: white;
margin-right: 20px;
margin-bottom: 20px;
.tag-overlay {
z-index: 999;
background-color: rgba(0,0,0,0.8);
border-radius: 4px;
width: 320px;
height: 166px;
position: absolute;
color: white;
font-size: 13px;
display: none;
padding: 10px;
.tag-list {
display: flex;
flex-direction: row;
align-items: flex-start;
align-content: flex-start;
flex-flow: row wrap;
height: 140px;
overflow: auto;
.tag {
display: inline-block;
flex: 0 auto;
margin-right: 2px;
padding: 3px 5px;
&:hover {
background-color: rgba(255,255,255,0.2);
border-radius: 20px;
}
}
}
.tags-loading {
position: relative;
left: 42%;
top: 20%;
text-align: center;
margin: 14px auto;
-webkit-animation-name: spin;
-webkit-animation-duration: 1.8s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
}
.logo {
flex: 1 auto;
min-width: 90px;
background-color: @brand-action;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
justify-content: center;
text-align: center;
img {
margin-top: 15px;
}
}
.card {
padding: 10px 20px 10px 20px;
position: relative;
.badges {
position: absolute;
right: 15px;
top: 8px;
}
.name {
font-size: 18px;
color: @gray-darkest;
margin-bottom: 0px;
position: relative;
width: 190px;
.namespace {
font-size: 11px;
color: @gray-lighter;
margin-bottom: -3px;
&.official {
color: @brand-action;
}
}
.repo {
display: inline-block;
max-width: 190px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.description {
font-size: 12px;
color: @gray-normal;
height: 50px;
width: 190px;
text-overflow: ellipsis;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
display: -webkit-box;
word-wrap: break-word;
}
.actions {
width: 190px;
position: absolute;
bottom: 8px;
.stars {
height: 15px;
font-size: 10px;
color: @gray-darker;
border-right: 1px solid @gray-lightest;
padding-right: 10px;
.icon {
position: relative;
font-size: 16px;
margin-right: 3px;
top: -1px;
color: @gray-darkest;
}
.text {
position: relative;
top: -6px;
}
}
.tags {
height: 15px;
font-size: 10px;
color: @gray-darker;
padding-left: 10px;
.icon {
position: relative;
font-size: 12px;
margin-right: 2px;
top: 2px;
color: @gray-darkest;
}
.text {
position: relative;
top: -2px;
padding: 3px 5px;
text-decoration: underline;
&:hover {
background-color: @brand-action;
color: white;
border-radius: 20px;
}
}
}
.action {
flex: 1 auto;
.btn {
text-align: right;
position: relative;
float: right;
top: -7px;
}
}
display: flex;
flex-direaction: row;
}
}
}
}

View File

@@ -6,7 +6,6 @@
align-items: flex-start;
justify-content: center;
.preferences-content {
flex: 1 auto;
margin-top: 45px;
@@ -17,7 +16,7 @@
.title {
margin-top: 40px;
border-bottom: 1px solid #eee;
border-bottom: 1px solid #EEE;
text-align: left;
font-size: 18px;
font-weight: 400;

View File

@@ -104,8 +104,8 @@
}
&.radial-transparent {
@inset-color: #F9F9F9;
background: #F9F9F9;
@inset-color: @color-background;
background: @color-background;
.inset {
background-color: @inset-color;
}

125
styles/right-panel.less Normal file
View File

@@ -0,0 +1,125 @@
.details {
background-color: @color-background;
margin: 0;
padding: 0;
box-sizing: border-box;
flex: 1;
display: flex;
flex-direction: column;
.details-subheader {
flex: 0 auto;
display: flex;
flex-direction: row;
position: relative;
border-bottom: 1px solid @color-divider;
background-color: white;
height: 57px;
padding: 6px 10px 10px 24px;
font-size: 13px;
color: @gray-normal;
.details-header-actions {
flex: 1 auto;
text-align: left;
margin-top: -12px;
.action {
display: inline-block;
&.disabled {
opacity: 0.3;
}
.action-icon {
color: @gray-normal;
font-size: 30px;
margin-right: 20px;
}
.btn-label {
position: relative;
top: 0px;
display: block;
color: @brand-action;
font-size: 10px;
&.run {
left: 8px;
}
&.restart {
left: 1px;
}
&.terminal {
left: -2px;
}
visibility: hidden;
}
}
}
.details-subheader-tabs {
flex: 1 auto;
text-align: right;
margin-right: 3px;
margin-top: 3px;
.tab {
margin-left: 16px;
padding: 6px 10px;
font-weight: 400;
&:hover {
border-radius: 40px;
background-color: @color-background;
}
&.active {
border-radius: 40px;
color: white;
.brand-gradient();
}
&.disabled {
opacity: 0.5;
}
}
}
}
.details-header {
flex: 0 auto;
display: flex;
flex-direction: row;
padding: 31px 24px 18px 24px;
position: relative;
background-color: white;
height: 75px;
h1 {
margin: 0;
font-size: 20px;
font-weight: 400;
margin: 0;
color: @gray-darkest;
}
.status {
font-size: 10px;
font-weight: 500;
position: relative;
top: 8px;
left: 14px;
&.running {
color: @brand-positive;
}
&.paused {
color: @gray-lighter;
}
&.stopped {
color: @gray-lighter;
}
&.downloading {
color: @brand-action;
}
}
}
.details-progress {
margin: 20% auto 0;
text-align: center;
width: 300px;
h2 {
margin-bottom: 20px;
}
}
.details-panel {
flex: 1;
overflow: auto;
background-color: white;
}
}

View File

@@ -22,17 +22,12 @@ h4 {
}
a {
transition: all 0.25s;
transition: color 0.25s;
&:hover {
text-decoration: none;
}
}
.popover-content {
color: @gray-normal;
font-size: 13px;
}
input[type="text"] {
&.line {
border: 0;
@@ -46,7 +41,7 @@ input[type="text"] {
border-bottom: 1px solid @brand-action;
}
&::-webkit-input-placeholder {
color: #ddd;
color: #DDD;
font-weight: 300;
}
}
@@ -206,3 +201,10 @@ input[type="text"] {
.btn-info { .btn-styles(@btn-info-bg); }
.btn-warning { .btn-styles(@btn-warning-bg); }
.btn-danger { .btn-styles(@btn-danger-bg); }
.tooltip {
.tooltip-inner {
font-size: 10px;
padding-bottom: 5px;
}
}

View File

@@ -3,8 +3,23 @@
@brand-positive: #15CC35;
@brand-negative: #FF5F52;
@traffic-light-green: @brand-positive;
@traffic-light-green-border: #17B230;
@traffic-light-red: @brand-negative;
@traffic-light-red-border: #E33E32;
@traffic-light-yellow: #FFBE05;
@traffic-light-yellow-border: #E2A100;
@traffic-light-gray: #DDDDDD;
@traffic-light-gray-border: #D3D3D3;
@gray-darkest: #253237;
@gray-darker: #394C51;
@gray-normal: #546C70;
@gray-lighter: #7A9999;
@gray-lightest: #C7D7D7;
@color-divider: #DCE2E2;
@color-background: #F9F9F9;
@font-regular: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
@font-code: Menlo;