diff --git a/images/loading-white.png b/images/loading-white.png
new file mode 100644
index 00000000..17096a36
Binary files /dev/null and b/images/loading-white.png differ
diff --git a/images/loading-white@2x.png b/images/loading-white@2x.png
new file mode 100644
index 00000000..75051f37
Binary files /dev/null and b/images/loading-white@2x.png differ
diff --git a/src/ImageCard.react.js b/src/ImageCard.react.js
new file mode 100644
index 00000000..2c01f670
--- /dev/null
+++ b/src/ImageCard.react.js
@@ -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 = {this.props.image.name};
+ } else {
+ name = {this.props.image.name};
+ }
+ 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
{t.name}
;
+ });
+ tags = (
+
+ {tagDisplay}
+
+ );
+ } else {
+ tags = ;
+ }
+ return (
+
+
+ {tags}
+
+
+
+
+
+
+ {name}
+
+
+ {description}
+
+
+
+
+ {this.props.image.star_count}
+
+
+
+ {this.state.chosenTag}
+
+
+
+
+
+ );
+ }
+});
+
+module.exports = ImageCard;
diff --git a/src/Main.js b/src/Main.js
index 69beea64..63f46262 100644
--- a/src/Main.js
+++ b/src/Main.js
@@ -10,7 +10,6 @@ var boot2docker = require('./boot2docker');
var ContainerStore = require('./ContainerStore');
var SetupStore = require('./SetupStore');
var settingsjson;
-var Menu = require('./Menu');
try {
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
diff --git a/src/NewContainer.react.js b/src/NewContainer.react.js
index 02b3a17a..ccda2514 100644
--- a/src/NewContainer.react.js
+++ b/src/NewContainer.react.js
@@ -1,10 +1,9 @@
-var _ = require('underscore');
var $ = require('jquery');
var React = require('react/addons');
var RetinaImage = require('react-retina-image');
var ContainerStore = require('./ContainerStore');
var Radial = require('./Radial.react');
-var assign = require('object-assign');
+var ImageCard = require('./ImageCard.react');
var NewContainer = React.createClass({
_searchRequest: null,
@@ -12,10 +11,7 @@ var NewContainer = React.createClass({
return {
query: '',
results: [],
- loading: false,
- tags: {},
- active: null,
- creating: []
+ loading: false
};
},
componentDidMount: function () {
@@ -79,32 +75,7 @@ var NewContainer = React.createClass({
}, 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 () {
- var self = this;
var title = this.state.query ? 'Results' : 'Recommended';
var data = [];
if (this.state.results) {
@@ -112,61 +83,9 @@ var NewContainer = React.createClass({
}
var results;
if (data.length) {
- var items = data.map(function (r) {
- var name;
- if (r.is_official) {
- name = {r.name};
- } else {
- name = {r.name};
- }
- 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 = ;
- } else {
- action = Create;
- }
+ var items = data.map(function (image) {
return (
-
-
-
-
-
-
- {name}
-
-
- {description}
-
-
-
-
- {r.star_count}
-
-
-
- latest
-
-
- {action}
-
-
-
-
+
);
});
diff --git a/src/NoContainers.react.js b/src/NoContainers.react.js
deleted file mode 100644
index 2be1c9d0..00000000
--- a/src/NoContainers.react.js
+++ /dev/null
@@ -1,13 +0,0 @@
-var React = require('react/addons');
-
-var NoContainers = React.createClass({
- render: function () {
- return (
-
-
No Containers
-
- );
- }
-});
-
-module.exports = NoContainers;
diff --git a/styles/containers.less b/styles/containers.less
index 750a29ae..32a24493 100644
--- a/styles/containers.less
+++ b/styles/containers.less
@@ -34,6 +34,48 @@
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: 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 {
flex: 1 auto;
min-width: 90px;
@@ -100,13 +142,19 @@
.icon {
position: relative;
font-size: 11px;
- margin-right: 5px;
+ margin-right: 2px;
top: 2px;
color: @gray-darkest;
}
.text {
position: relative;
top: 0px;
+ padding: 3px 5px;
+ &:hover {
+ background-color: @brand-action;
+ color: white;
+ border-radius: 20px;
+ }
}
}
.action {