New simplfied collection list when adding a sketch

This commit is contained in:
Andrew Nicolaou 2019-11-05 18:23:57 +01:00
parent 18af6aed3a
commit 08fd6b826d
10 changed files with 362 additions and 66 deletions

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="check-encircled" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path id="circle" d="M50,26.5c-14.4,0-26,11.5-25.9,25.9c0,14.5,11.6,26,26,26c14.5,0,25.9-11.5,25.9-26C76,38,64.5,26.5,50,26.5z
M47.6,66.6L34,53.4l5.6-5.5l7.1,6.8l14-15.4l6.1,5.5L47.6,66.6z"/>
<polygon id="check" class="st0 counter-form" points="46.7,54.7 39.6,47.9 34,53.4 47.6,66.6 66.8,44.8 60.7,39.3 "/>
</svg>

After

Width:  |  Height:  |  Size: 727 B

12
client/images/close.svg Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="close" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path id="circle" d="M50,26.5c-14.4,0-26,11.5-25.9,25.9c0,14.5,11.6,26,26,26c14.5,0,25.9-11.5,25.9-26C76,38,64.5,26.5,50,26.5z
M63.4,60.2L58,65.6l-7.9-8L42,65.7l-5.4-5.4l8.1-8l-8.1-8l5.4-5.4l8,8.1l8-8l5.4,5.4l-8,7.8L63.4,60.2z"/>
<polygon id="x" class="st0 counter-form" points="58,39 50,47 42,38.9 36.6,44.3 44.7,52.3 36.6,60.3 42,65.7 50.1,57.6 58,65.6 63.4,60.2
55.4,52.2 63.4,44.4 "/>
</svg>

After

Width:  |  Height:  |  Size: 801 B

View file

@ -0,0 +1,169 @@
import PropTypes from 'prop-types';
import React from 'react';
import { Helmet } from 'react-helmet';
import InlineSVG from 'react-inlinesvg';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import classNames from 'classnames';
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 getSortedCollections from '../selectors/collections';
import Loader from '../../App/components/loader';
import QuickAddList from './QuickAddList/QuickAddList';
const projectInCollection = (project, collection) => collection.items.find(item => item.project.id === project.id) != null;
class CollectionList extends React.Component {
constructor(props) {
super(props);
if (props.projectId) {
props.getProject(props.projectId);
}
this.props.getCollections(this.props.username);
this.state = {
hasLoadedData: false,
};
}
componentDidUpdate(prevProps) {
if (prevProps.loading === true && this.props.loading === false) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({
hasLoadedData: true,
});
}
}
getTitle() {
if (this.props.username === this.props.user.username) {
return 'p5.js Web Editor | My collections';
}
return `p5.js Web Editor | ${this.props.username}'s collections`;
}
handleCollectionAdd = (collection) => {
this.props.addToCollection(collection.id, this.props.project.id);
}
handleCollectionRemove = (collection) => {
this.props.removeFromCollection(collection.id, this.props.project.id);
}
handleAddRemove = (collection) => {
if (projectInCollection(this.props.project, collection)) {
this.handleCollectionRemove(collection);
} else {
this.handleCollectionAdd(collection);
}
}
render() {
const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
const { collections, project } = this.props;
const hasCollections = collections.length > 0;
const collectionWithSketchStatus = collections.map(collection => ({
...collection,
url: `/${collection.owner.username}/collections/${collection.id}`,
isAdded: projectInCollection(project, collection),
}));
let content = null;
if (this.props.loading && !this.state.hasLoadedData) {
content = <Loader />;
} else if (hasCollections) {
content = <QuickAddList items={collectionWithSketchStatus} onSelect={this.handleAddRemove} />;
} else {
content = 'No collections';
}
return (
<div className="sketches-table-container">
<Helmet>
<title>{this.getTitle()}</title>
</Helmet>
{content}
</div>
);
}
}
const ProjectShape = PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
user: PropTypes.shape({
username: PropTypes.string.isRequired
}).isRequired,
});
const ItemsShape = PropTypes.shape({
createdAt: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
project: ProjectShape
});
CollectionList.propTypes = {
user: PropTypes.shape({
username: PropTypes.string,
authenticated: PropTypes.bool.isRequired
}).isRequired,
projectId: PropTypes.string.isRequired,
getCollections: PropTypes.func.isRequired,
getProject: PropTypes.func.isRequired,
addToCollection: PropTypes.func.isRequired,
removeFromCollection: PropTypes.func.isRequired,
collections: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string,
createdAt: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
items: PropTypes.arrayOf(ItemsShape),
})).isRequired,
username: PropTypes.string,
loading: PropTypes.bool.isRequired,
project: PropTypes.shape({
id: PropTypes.string,
owner: PropTypes.shape({
id: PropTypes.string
})
})
};
CollectionList.defaultProps = {
project: {
id: undefined,
owner: undefined
},
username: undefined
};
function mapStateToProps(state, ownProps) {
return {
user: state.user,
collections: getSortedCollections(state),
sorting: state.sorting,
loading: state.loading,
project: state.project,
projectId: ownProps && ownProps.params ? ownProps.prams.project_id : null,
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(
Object.assign({}, CollectionsActions, ProjectsActions, ProjectActions, ToastActions, SortingActions),
dispatch
);
}
export default connect(mapStateToProps, mapDispatchToProps)(CollectionList);

View file

@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';
import InlineSVG from 'react-inlinesvg';
const check = require('../../../../images/check_encircled.svg');
const close = require('../../../../images/close.svg');
const Icons = ({ isAdded }) => {
const classes = [
'quick-add__icon',
isAdded ? 'quick-add__icon--in-collection' : 'quick-add__icon--not-in-collection'
].join(' ');
return (
<div className={classes}>
<InlineSVG className="quick-add__remove-icon" src={close} alt="Remove from collection" />
<InlineSVG className="quick-add__in-icon" src={check} alt="In collection" />
<InlineSVG className="quick-add__add-icon" src={close} alt="Add to collection" />
</div>
);
};
Icons.propTypes = {
isAdded: PropTypes.bool.isRequired,
};
export default Icons;

View file

@ -0,0 +1,46 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
import Icons from './Icons';
const Item = ({
isAdded, onSelect, name, url
}) => (
<li className="quick-add__item">
<button className="quick-add__item-toggle" onClick={onSelect}>
<Icons isAdded={isAdded} />
{name}
</button>
<Link className="quick-add__item-view" to={url}>View</Link>
</li>
);
const ItemType = PropTypes.shape({
name: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
isAdded: PropTypes.bool.isRequired,
});
Item.propTypes = {
...ItemType,
onSelect: PropTypes.func.isRequired,
};
const QuickAddList = ({ items, onSelect }) => (
<ul className="quick-add">{items.map(item => (<Item
key={item.id}
{...item}
onSelect={
() => onSelect(item)
}
/>))}
</ul>
);
QuickAddList.propTypes = {
items: PropTypes.arrayOf(ItemType).isRequired,
onSelect: PropTypes.func.isRequired,
};
export default QuickAddList;

View file

@ -0,0 +1 @@
export { default } from './QuickAddList.jsx';

View file

@ -30,7 +30,7 @@ import * as ConsoleActions from '../actions/console';
import { getHTMLFile } from '../reducers/files';
import Overlay from '../../App/components/Overlay';
import About from '../components/About';
import CollectionList from '../components/CollectionList';
import CollectionList from '../components/AddToCollectionList';
import Feedback from '../components/Feedback';
class IDEView extends React.Component {
@ -392,7 +392,6 @@ class IDEView extends React.Component {
previousPath={this.props.ide.previousPath}
>
<CollectionList
addMode
projectId={this.props.params.project_id}
username={this.props.params.username}
user={this.props.user}

View file

@ -0,0 +1,94 @@
.quick-add {
padding: #{24 / $base-font-size}rem;
width: #{600 / $base-font-size}rem;
}
.quick-add__item {
display: flex;
align-items: center;
height: #{64 / $base-font-size}rem;
padding-right: #{24 / $base-font-size}rem;
button, a {
@include themify() {
color: getThemifyVariable('primary-text-color');
}
}
}
.quick-add__item:nth-child(odd) {
@include themify() {
background: getThemifyVariable('table-row-stripe-color');
}
}
.quick-add__item-toggle {
display: flex;
align-items: center;
flex: 1;
}
.quick-add__icon {
display: inline-block;
margin-right:#{15 / $base-font-size}rem;
width:#{35 / $base-font-size}rem;
height:#{35 / $base-font-size}rem;
@include icon();
@include themify() {
& path {
fill: getThemifyVariable('dropdown-color');
}
& svg {
width:#{35 / $base-font-size}rem;
height:#{35 / $base-font-size}rem;
}
}
}
.quick-add__icon > * {
display: none;
}
.quick-add__in-icon {
display: inline-block;
& svg {
opacity: 0.3;
}
}
.quick-add__icon--in-collection .quick-add__in-icon svg {
opacity: 1;
}
.quick-add__add-icon {
transform: rotate(45deg);
}
.quick-add__item-toggle:hover {
.quick-add__in-icon {
display: none;
}
.quick-add__icon--in-collection {
.quick-add__remove-icon {
display: inline-block;
}
.quick-add__add-icon {
display: none;
}
}
.quick-add__icon--not-in-collection {
.quick-add__add-icon {
display: inline-block;
}
.quick-add__remove-icon {
display: none;
}
}
}

View file

@ -118,70 +118,6 @@
width: #{35 / $base-font-size}rem;
}
.sketch-list__icon {
display: inline-block;
margin-right:#{15 / $base-font-size}rem;
width:#{35 / $base-font-size}rem;
height:#{35 / $base-font-size}rem;
@include icon();
@include themify() {
& path {
fill: getThemifyVariable('dropdown-color');
}
& svg {
width:#{35 / $base-font-size}rem;
height:#{35 / $base-font-size}rem;
}
}
}
.sketch-list__icon > * {
display: none;
}
.sketch-list__in-icon {
display: inline-block;
& svg {
opacity: 0.3;
}
}
.sketch-list__icon--in-collection .sketch-list__in-icon svg {
opacity: 1;
}
.sketch-list__add-icon {
transform: rotate(45deg);
}
.sketches-table__row:hover {
.sketch-list__in-icon {
display: none;
}
.sketch-list__icon--in-collection {
.sketch-list__remove-icon {
display: inline-block;
}
.sketch-list__add-icon {
display: none;
}
}
.sketch-list__icon--not-in-collection {
.sketch-list__add-icon {
display: inline-block;
}
.sketch-list__remove-icon {
display: none;
}
}
}
.sketch-list__action-dialogue {
@extend %dropdown-open-right;
top: 63%;

View file

@ -52,6 +52,7 @@
@import 'components/collection';
@import 'components/collection-create';
@import 'components/collection-popover';
@import 'components/quick-add';
@import 'layout/dashboard';
@import 'layout/ide';