This commit is contained in:
Sean Li 2015-02-16 10:50:26 -08:00
Родитель d51d34ff0c
Коммит bebb2395f9
7 изменённых файлов: 166 добавлений и 100 удалений

Двоичные данные
images/loading-white.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 530 B

Двоичные данные
images/loading-white@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

113
src/ImageCard.react.js Normal file
Просмотреть файл

@ -0,0 +1,113 @@
var $ = require('jquery');
var React = require('react/addons');
var RetinaImage = require('react-retina-image');
var ContainerStore = require('./ContainerStore');
var ImageCard = React.createClass({
getInitialState: function () {
return {
tags: [],
chosenTag: 'latest'
};
},
handleTagClick: function (tag) {
this.setState({
chosenTag: tag
});
var $tagOverlay = $(this.getDOMNode()).find('.tag-overlay');
$tagOverlay.fadeOut(300);
},
handleClick: function (name) {
ContainerStore.create(name, this.state.chosenTag, function (err) {
if (err) {
throw err;
}
$(document.body).find('.new-container-item').parent().fadeOut();
}.bind(this));
},
handleTagOverlayClick: function (name) {
var $tagOverlay = $(this.getDOMNode()).find('.tag-overlay');
$tagOverlay.fadeIn(300);
$.get('https://registry.hub.docker.com/v1/repositories/' + name + '/tags', function (result) {
console.log(result);
this.setState({
tags: result
});
}.bind(this));
},
handleCloseTagOverlay: function () {
var $tagOverlay = $(this.getDOMNode()).find('.tag-overlay');
$tagOverlay.fadeOut(300);
},
render: function () {
var self = this;
var name;
if (this.props.image.is_official) {
name = <span><RetinaImage src="official.png"/>{this.props.image.name}</span>;
} else {
name = <span>{this.props.image.name}</span>;
}
var description;
if (this.props.image.description) {
description = this.props.image.description;
} else {
description = "No description.";
}
var logoStyle = {
backgroundImage: `linear-gradient(-180deg, ${this.props.image.gradient_start} 4%, ${this.props.image.gradient_end} 100%)`
};
var imgsrc;
if (this.props.image.img) {
imgsrc = `http://kitematic.com/recommended/${this.props.image.img}`;
} else {
imgsrc = 'http://kitematic.com/recommended/kitematic_html.png';
}
var tags;
if (this.state.tags.length > 0) {
var tagDisplay = this.state.tags.map(function (t) {
return <div className="tag" key={t.name} onClick={self.handleTagClick.bind(self, t.name)}>{t.name}</div>;
});
tags = (
<div className="tag-list">
{tagDisplay}
</div>
);
} else {
tags = <RetinaImage className="tags-loading" src="loading-white.png"/>;
}
return (
<div className="image-item">
<div className="tag-overlay" onClick={self.handleCloseTagOverlay}>
{tags}
</div>
<div className="logo" style={logoStyle}>
<RetinaImage src={imgsrc}/>
</div>
<div className="card">
<div className="name">
{name}
</div>
<div className="description">
{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>
<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>
</div>
<div className="action">
<a className="btn btn-action" onClick={self.handleClick.bind(self, this.props.image.name)}>Create</a>
</div>
</div>
</div>
</div>
);
}
});
module.exports = ImageCard;

Просмотреть файл

@ -10,7 +10,6 @@ var boot2docker = require('./boot2docker');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var SetupStore = require('./SetupStore'); var SetupStore = require('./SetupStore');
var settingsjson; var settingsjson;
var Menu = require('./Menu');
try { try {
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8')); settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));

Просмотреть файл

@ -1,10 +1,9 @@
var _ = require('underscore');
var $ = require('jquery'); var $ = require('jquery');
var React = require('react/addons'); var React = require('react/addons');
var RetinaImage = require('react-retina-image'); var RetinaImage = require('react-retina-image');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var Radial = require('./Radial.react'); var Radial = require('./Radial.react');
var assign = require('object-assign'); var ImageCard = require('./ImageCard.react');
var NewContainer = React.createClass({ var NewContainer = React.createClass({
_searchRequest: null, _searchRequest: null,
@ -12,10 +11,7 @@ var NewContainer = React.createClass({
return { return {
query: '', query: '',
results: [], results: [],
loading: false, loading: false
tags: {},
active: null,
creating: []
}; };
}, },
componentDidMount: function () { componentDidMount: function () {
@ -79,32 +75,7 @@ var NewContainer = React.createClass({
}, 200); }, 200);
} }
}, },
handleClick: function (name) {
ContainerStore.create(name, 'latest', function (err) {
if (err) {
throw err;
}
$(document.body).find('.new-container-item').parent().fadeOut();
}.bind(this));
},
handleDropdownClick: function (name) {
this.setState({
active: name
});
if (this.state.tags[name]) {
return;
}
$.get('https://registry.hub.docker.com/v1/repositories/' + name + '/tags', function (result) {
var res = {};
res[name] = result;
console.log(assign(this.state.tags, res));
this.setState({
tags: assign(this.state.tags, res)
});
}.bind(this));
},
render: function () { render: function () {
var self = this;
var title = this.state.query ? 'Results' : 'Recommended'; var title = this.state.query ? 'Results' : 'Recommended';
var data = []; var data = [];
if (this.state.results) { if (this.state.results) {
@ -112,61 +83,9 @@ var NewContainer = React.createClass({
} }
var results; var results;
if (data.length) { if (data.length) {
var items = data.map(function (r) { var items = data.map(function (image) {
var name;
if (r.is_official) {
name = <span><RetinaImage src="official.png"/>{r.name}</span>;
} else {
name = <span>{r.name}</span>;
}
var description;
if (r.description) {
description = r.description;
} else {
description = "No description.";
}
var logoStyle = {
backgroundImage: `linear-gradient(-180deg, ${r.gradient_start} 4%, ${r.gradient_end} 100%)`
};
var imgsrc;
if (r.img) {
imgsrc = `http://kitematic.com/recommended/${r.img}`;
} else {
imgsrc = 'http://kitematic.com/recommended/kitematic_html.png';
}
var action;
if (_.find(self.state.creating, r.name)) {
action = <RetinaImage src="loading.png"/>;
} else {
action = <a className="btn btn-action" onClick={self.handleClick.bind(self, r.name)}>Create</a>;
}
return ( return (
<div key={r.name} className="image-item"> <ImageCard key={image.name} image={image} />
<div className="logo" style={logoStyle}>
<RetinaImage src={imgsrc}/>
</div>
<div className="card">
<div className="name">
{name}
</div>
<div className="description">
{description}
</div>
<div className="actions">
<div className="stars">
<span className="icon icon-star-9"></span>
<span className="text">{r.star_count}</span>
</div>
<div className="tags">
<span className="icon icon-tag-1"></span>
<span className="text">latest</span>
</div>
<div className="action">
{action}
</div>
</div>
</div>
</div>
); );
}); });

Просмотреть файл

@ -1,13 +0,0 @@
var React = require('react/addons');
var NoContainers = React.createClass({
render: function () {
return (
<div className="no-containers">
<h3>No Containers</h3>
</div>
);
}
});
module.exports = NoContainers;

Просмотреть файл

@ -34,6 +34,48 @@
background-color: white; background-color: white;
margin-right: 20px; margin-right: 20px;
margin-bottom: 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: scroll;
.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 { .logo {
flex: 1 auto; flex: 1 auto;
min-width: 90px; min-width: 90px;
@ -100,13 +142,19 @@
.icon { .icon {
position: relative; position: relative;
font-size: 11px; font-size: 11px;
margin-right: 5px; margin-right: 2px;
top: 2px; top: 2px;
color: @gray-darkest; color: @gray-darkest;
} }
.text { .text {
position: relative; position: relative;
top: 0px; top: 0px;
padding: 3px 5px;
&:hover {
background-color: @brand-action;
color: white;
border-radius: 20px;
}
} }
} }
.action { .action {