diff --git a/client/components/AddRemoveButton.jsx b/client/components/AddRemoveButton.jsx
new file mode 100644
index 00000000..f0ec1272
--- /dev/null
+++ b/client/components/AddRemoveButton.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import InlineSVG from 'react-inlinesvg';
+
+const addIcon = require('../images/plus.svg');
+const removeIcon = require('../images/minus.svg');
+
+const AddRemoveButton = ({ type, onClick }) => {
+ const alt = type === 'add' ? 'add to collection' : 'remove from collection';
+ const icon = type === 'add' ? addIcon : removeIcon;
+
+ return (
+
+ );
+};
+
+AddRemoveButton.propTypes = {
+ type: PropTypes.oneOf(['add', 'remove']).isRequired,
+ onClick: PropTypes.func.isRequired,
+};
+
+export default AddRemoveButton;
diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx
index 05ef9dce..69a04219 100644
--- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx
+++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx
@@ -9,26 +9,9 @@ import * as ProjectActions from '../../actions/project';
import * as CollectionsActions from '../../actions/collections';
import * as IdeActions from '../../actions/ide';
import * as ToastActions from '../../actions/toast';
+import AddRemoveButton from '../../../../components/AddRemoveButton';
const downFilledTriangle = require('../../../../images/down-filled-triangle.svg');
-const addIcon = require('../../../../images/plus.svg');
-const removeIcon = require('../../../../images/minus.svg');
-
-const AddRemoveButton = ({ type, onClick }) => {
- const alt = type === 'add' ? 'add to collection' : 'remove from collection';
- const icon = type === 'add' ? addIcon : removeIcon;
-
- return (
-
- );
-};
-
-AddRemoveButton.propTypes = {
- type: PropTypes.oneOf(['add', 'remove']).isRequired,
- onClick: PropTypes.func.isRequired,
-};
class CollectionListRowBase extends React.Component {
static projectInCollection(project, collection) {
diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx
index b430df14..09d19168 100644
--- a/client/modules/IDE/components/SketchList.jsx
+++ b/client/modules/IDE/components/SketchList.jsx
@@ -10,11 +10,13 @@ import classNames from 'classnames';
import slugify from 'slugify';
import * as ProjectActions from '../actions/project';
import * as ProjectsActions from '../actions/projects';
+import * as CollectionsActions from '../actions/collections';
import * as ToastActions from '../actions/toast';
import * as SortingActions from '../actions/sorting';
import * as IdeActions from '../actions/ide';
import getSortedSketches from '../selectors/projects';
import Loader from '../../App/components/loader';
+import AddRemoveButton from '../../../components/AddRemoveButton';
const arrowUp = require('../../../images/sort-arrow-up.svg');
const arrowDown = require('../../../images/sort-arrow-down.svg');
@@ -134,10 +136,100 @@ class SketchListRowBase extends React.Component {
}
}
+ renderDropdown = () => {
+ const { optionsOpen } = this.state;
+ const userIsOwner = this.props.user.username === this.props.username;
+
+ return (
+
+
+ {optionsOpen &&
+
+ {userIsOwner &&
+ -
+
+
}
+ -
+
+
+ {this.props.user.authenticated &&
+ -
+
+
}
+ { /* -
+
+
*/ }
+ {userIsOwner &&
+ -
+
+
}
+ }
+ |
+ );
+ }
+
+ renderAddRemoveButtons = () => {
+ return (
+ {
+ this.props.inCollection ?
+ :
+
+ }
+ |
+ );
+ }
+
+ renderActions = () => {
+ return this.props.addMode === true ? this.renderAddRemoveButtons() : this.renderDropdown();
+ }
+
render() {
const { sketch, username } = this.props;
- const { renameOpen, optionsOpen, renameValue } = this.state;
- const userIsOwner = this.props.user.username === this.props.username;
+ const { renameOpen, renameValue } = this.state;
let url = `/${username}/sketches/${sketch.id}`;
if (username === 'p5') {
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
@@ -164,74 +256,7 @@ class SketchListRowBase extends React.Component {
{format(new Date(sketch.createdAt), 'MMM D, YYYY h:mm A')} |
{format(new Date(sketch.updatedAt), 'MMM D, YYYY h:mm A')} |
-
-
- {optionsOpen &&
-
- {userIsOwner &&
- -
-
-
}
- -
-
-
- {this.props.user.authenticated &&
- -
-
-
}
- { /* -
-
-
*/ }
- {userIsOwner &&
- -
-
-
}
- }
- |
+ {this.renderActions()}
);
}
}
@@ -311,6 +336,14 @@ class SketchList extends React.Component {
);
}
+ handleCollectionAdd = (sketchId) => {
+ this.props.addToCollection(this.props.collection.id, sketchId);
+ }
+
+ handleCollectionRemove = (sketchId) => {
+ this.props.removeFromCollection(this.props.collection.id, sketchId);
+ }
+
render() {
const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
return (
@@ -337,6 +370,10 @@ class SketchList extends React.Component {
sketch={sketch}
user={this.props.user}
username={username}
+ addMode={this.props.addMode}
+ onCollectionAdd={() => this.handleCollectionAdd(sketch.id)}
+ onCollectionRemove={() => this.handleCollectionRemove(sketch.id)}
+ inCollection={this.props.collection && this.props.collection.items.find(item => item.project.id === sketch.id) != null}
/>))}
}
@@ -365,12 +402,7 @@ SketchList.propTypes = {
field: PropTypes.string.isRequired,
direction: PropTypes.string.isRequired
}).isRequired,
- project: PropTypes.shape({
- id: PropTypes.string,
- owner: PropTypes.shape({
- id: PropTypes.string
- })
- })
+ addMode: PropTypes.bool,
};
SketchList.defaultProps = {
@@ -392,7 +424,7 @@ function mapStateToProps(state) {
}
function mapDispatchToProps(dispatch) {
- return bindActionCreators(Object.assign({}, ProjectsActions, ToastActions, SortingActions), dispatch);
+ return bindActionCreators(Object.assign({}, ProjectsActions, CollectionsActions, ToastActions, SortingActions), dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(SketchList);
diff --git a/client/modules/User/components/Collection.jsx b/client/modules/User/components/Collection.jsx
index 480001e8..73ca442f 100644
--- a/client/modules/User/components/Collection.jsx
+++ b/client/modules/User/components/Collection.jsx
@@ -16,6 +16,8 @@ import * as IdeActions from '../../IDE/actions/ide';
import { getCollection } from '../../IDE/selectors/collections';
import Loader from '../../App/components/loader';
import EditableInput from '../../IDE/components/EditableInput';
+import Overlay from '../../App/components/Overlay';
+import SketchList from '../../IDE/components/SketchList';
const arrowUp = require('../../../images/sort-arrow-up.svg');
const arrowDown = require('../../../images/sort-arrow-down.svg');
@@ -232,6 +234,12 @@ class Collection extends React.Component {
this.props.getCollections(this.props.username);
this.props.resetSorting();
this._renderFieldHeader = this._renderFieldHeader.bind(this);
+ this.showAddSketches = this.showAddSketches.bind(this);
+ this.hideAddSketches = this.hideAddSketches.bind(this);
+
+ this.state = {
+ isAddingSketches: false,
+ };
}
getTitle() {
@@ -318,9 +326,21 @@ class Collection extends React.Component {
);
}
+ showAddSketches() {
+ this.setState({
+ isAddingSketches: true,
+ });
+ }
+
+ hideAddSketches() {
+ this.setState({
+ isAddingSketches: false,
+ });
+ }
+
_renderEmptyTable() {
if (!this.hasCollectionItems()) {
- return (No sketches in collection.
);
+ return (No sketches in collection.
);
}
return null;
}
@@ -379,8 +399,19 @@ class Collection extends React.Component {
/>))}
+
+
}
+ {
+ this.state.isAddingSketches && (
+
+
+
+
+
+ )
+ }
);
diff --git a/client/styles/components/_collection.scss b/client/styles/components/_collection.scss
index 92768d38..2927ec62 100644
--- a/client/styles/components/_collection.scss
+++ b/client/styles/components/_collection.scss
@@ -43,3 +43,8 @@
.collection-table-wrapper {
margin: #{28 / $base-font-size}rem #{56 / $base-font-size}rem;
}
+
+.collection-add-sketch {
+ padding: #{24 / $base-font-size}rem;
+ overflow: scroll;
+}