зеркало из https://github.com/docker/kitematic.git
Implemented tags dropdown.
This commit is contained in:
Родитель
d51d34ff0c
Коммит
bebb2395f9
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 530 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -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 {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче