From 17efc4277808b50703abf48926fa07ba08f4fa91 Mon Sep 17 00:00:00 2001 From: catarak Date: Mon, 15 Aug 2016 12:42:13 -0400 Subject: [PATCH 1/4] switch project name edit to html5 input --- client/constants.js | 2 + client/modules/IDE/actions/project.js | 15 +- client/modules/IDE/components/SidebarItem.js | 1 - client/modules/IDE/components/Toolbar.js | 142 ++++++++++++------- client/modules/IDE/pages/IDEView.js | 8 +- client/modules/IDE/reducers/project.js | 4 + client/styles/components/_toolbar.scss | 12 ++ 7 files changed, 130 insertions(+), 54 deletions(-) diff --git a/client/constants.js b/client/constants.js index f71c2317..cabaa570 100644 --- a/client/constants.js +++ b/client/constants.js @@ -27,6 +27,8 @@ export const PROJECT_SAVE_SUCCESS = 'PROJECT_SAVE_SUCCESS'; export const PROJECT_SAVE_FAIL = 'PROJECT_SAVE_FAIL'; export const NEW_PROJECT = 'NEW_PROJECT'; export const RESET_PROJECT = 'RESET_PROJECT'; +export const SHOW_EDIT_PROJECT_NAME = 'SHOW_EDIT_PROJECT_NAME'; +export const HIDE_EDIT_PROJECT_NAME = 'HIDE_EDIT_PROJECT_NAME'; export const SET_PROJECT = 'SET_PROJECT'; export const SET_PROJECTS = 'SET_PROJECTS'; diff --git a/client/modules/IDE/actions/project.js b/client/modules/IDE/actions/project.js index d541a49f..926b88b9 100644 --- a/client/modules/IDE/actions/project.js +++ b/client/modules/IDE/actions/project.js @@ -41,8 +41,7 @@ export function getProject(id) { }; } -export function setProjectName(event) { - const name = event.target.textContent; +export function setProjectName(name) { return { type: ActionTypes.SET_PROJECT_NAME, name @@ -171,3 +170,15 @@ export function cloneProject() { }; } +export function showEditProjectName() { + return { + type: ActionTypes.SHOW_EDIT_PROJECT_NAME + }; +} + +export function hideEditProjectName() { + return { + type: ActionTypes.HIDE_EDIT_PROJECT_NAME + }; +} + diff --git a/client/modules/IDE/components/SidebarItem.js b/client/modules/IDE/components/SidebarItem.js index 4d58377a..f68e0706 100644 --- a/client/modules/IDE/components/SidebarItem.js +++ b/client/modules/IDE/components/SidebarItem.js @@ -16,7 +16,6 @@ class SidebarItem extends React.Component { } handleKeyPress(event) { - console.log(event.key); if (event.key === 'Enter') { this.props.hideEditFileName(this.props.file.id); } diff --git a/client/modules/IDE/components/Toolbar.js b/client/modules/IDE/components/Toolbar.js index c69f04c5..463c2045 100644 --- a/client/modules/IDE/components/Toolbar.js +++ b/client/modules/IDE/components/Toolbar.js @@ -6,57 +6,96 @@ const stopUrl = require('../../../images/stop.svg'); const preferencesUrl = require('../../../images/preferences.svg'); import classNames from 'classnames'; -function Toolbar(props) { - let playButtonClass = classNames({ - 'toolbar__play-button': true, - 'toolbar__play-button--selected': props.isPlaying - }); - let stopButtonClass = classNames({ - 'toolbar__stop-button': true, - 'toolbar__stop-button--selected': !props.isPlaying - }); - let preferencesButtonClass = classNames({ - 'toolbar__preferences-button': true, - 'toolbar__preferences-button--selected': props.preferencesIsVisible - }); +class Toolbar extends React.Component { + constructor(props) { + super(props); + this.handleKeyPress = this.handleKeyPress.bind(this); + this.handleProjectNameChange = this.handleProjectNameChange.bind(this); + } - return ( -
- p5js Logo - + handleKeyPress(event) { + if (event.key === 'Enter') { + this.props.hideEditProjectName(); + } + } - -
- + p5js Logo + + + +
+ { + this.originalProjectName = this.props.project.name; + this.props.showEditProjectName(); + setTimeout(() => this.refs.projectNameInput.focus(), 0); + }} + >{this.props.project.name} + { + this.validateProjectName(); + this.props.hideEditProjectName(); + }} + onKeyPress={this.handleKeyPress} + /> + {(() => { // eslint-disable-line + if (this.props.owner) { + return ( +

by {this.props.owner.username}

+ ); + } + })()} +
+
- -
- ); + ); + } } Toolbar.propTypes = { @@ -65,11 +104,16 @@ Toolbar.propTypes = { startSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired, setProjectName: PropTypes.func.isRequired, - projectName: PropTypes.string.isRequired, openPreferences: PropTypes.func.isRequired, owner: PropTypes.shape({ username: PropTypes.string - }) + }), + project: PropTypes.shape({ + name: PropTypes.string.isRequired, + isEditingName: PropTypes.bool + }).isRequired, + showEditProjectName: PropTypes.func.isRequired, + hideEditProjectName: PropTypes.func.isRequired }; export default Toolbar; diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js index ae73357b..4da5c9b1 100644 --- a/client/modules/IDE/pages/IDEView.js +++ b/client/modules/IDE/pages/IDEView.js @@ -113,11 +113,13 @@ class IDEView extends React.Component { isPlaying={this.props.ide.isPlaying} startSketch={this.props.startSketch} stopSketch={this.props.stopSketch} - projectName={this.props.project.name} setProjectName={this.props.setProjectName} + showEditProjectName={this.props.showEditProjectName} + hideEditProjectName={this.props.hideEditProjectName} openPreferences={this.props.openPreferences} preferencesIsVisible={this.props.ide.preferencesIsVisible} owner={this.props.project.owner} + project={this.props.project} /> { }; case ActionTypes.RESET_PROJECT: return initialState; + case ActionTypes.SHOW_EDIT_PROJECT_NAME: + return Object.assign({}, state, { isEditingName: true }); + case ActionTypes.HIDE_EDIT_PROJECT_NAME: + return Object.assign({}, state, { isEditingName: false }); default: return state; } diff --git a/client/styles/components/_toolbar.scss b/client/styles/components/_toolbar.scss index 3716c907..77ba6109 100644 --- a/client/styles/components/_toolbar.scss +++ b/client/styles/components/_toolbar.scss @@ -53,6 +53,18 @@ &:focus { color: $light-inactive-text-color; } + + .toolbar__project-name-container--editing & { + display: none; + } +} + +.toolbar__project-name-input { + display: none; + border: 0px; + .toolbar__project-name-container--editing & { + display: block; + } } .toolbar__project-owner { From 89c641c8457d8d649445c13f234cc317c85d8f9c Mon Sep 17 00:00:00 2001 From: catarak Date: Mon, 15 Aug 2016 13:03:52 -0400 Subject: [PATCH 2/4] fix sketch list view bug which made the nav look ugly --- client/modules/Sketch/pages/SketchListView.js | 36 ++++++++++--------- client/styles/components/_sketch-list.scss | 1 + client/styles/layout/_sketch-list.scss | 5 +++ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/client/modules/Sketch/pages/SketchListView.js b/client/modules/Sketch/pages/SketchListView.js index e46cab23..1f775429 100644 --- a/client/modules/Sketch/pages/SketchListView.js +++ b/client/modules/Sketch/pages/SketchListView.js @@ -22,24 +22,26 @@ class SketchListView extends React.Component { exportProjectAsZip={this.props.exportProjectAsZip} cloneProject={this.props.cloneProject} /> - - - - - - - - - - {this.props.sketches.map(sketch => - - - - +
+
NameCreatedLast Updated
{sketch.name}{moment(sketch.createdAt).format('MMM D, YYYY')}{moment(sketch.updatedAt).format('MMM D, YYYY')}
+ + + + + - )} - -
NameCreatedLast Updated
+ + + {this.props.sketches.map(sketch => + + {sketch.name} + {moment(sketch.createdAt).format('MMM D, YYYY')} + {moment(sketch.updatedAt).format('MMM D, YYYY')} + + )} + + + ); } diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss index 9ef6a786..1658855f 100644 --- a/client/styles/components/_sketch-list.scss +++ b/client/styles/components/_sketch-list.scss @@ -2,6 +2,7 @@ width: 100%; padding: #{10 / $base-font-size}rem 0; padding-left: #{170 / $base-font-size}rem; + height: 100%; } .sketches-table__row { diff --git a/client/styles/layout/_sketch-list.scss b/client/styles/layout/_sketch-list.scss index 979c48d4..0784629c 100644 --- a/client/styles/layout/_sketch-list.scss +++ b/client/styles/layout/_sketch-list.scss @@ -3,4 +3,9 @@ flex-wrap: wrap; height: 100%; flex-flow: column; +} + +.sketches-table-container { + flex: 1 0 0%; + overflow-y: scroll; } \ No newline at end of file From 2f6d5e84e8c8d43eb113bd059603cacfead7bad7 Mon Sep 17 00:00:00 2001 From: catarak Date: Mon, 15 Aug 2016 17:06:12 -0400 Subject: [PATCH 3/4] switch sketch list to sketch list modal, which you now can close --- client/modules/App/components/Overlay.js | 17 ++++++ client/modules/IDE/actions/projects.js | 25 ++++++++ client/modules/IDE/components/SketchList.js | 68 +++++++++++++++++++++ client/modules/IDE/pages/IDEView.js | 19 ++++++ client/modules/IDE/reducers/projects.js | 12 ++++ client/routes.js | 4 +- client/styles/components/_overlay.scss | 17 ++++++ client/styles/components/_sketch-list.scss | 17 +++++- client/styles/layout/_sketch-list.scss | 9 +-- client/styles/main.scss | 1 + 10 files changed, 180 insertions(+), 9 deletions(-) create mode 100644 client/modules/App/components/Overlay.js create mode 100644 client/modules/IDE/actions/projects.js create mode 100644 client/modules/IDE/components/SketchList.js create mode 100644 client/modules/IDE/reducers/projects.js create mode 100644 client/styles/components/_overlay.scss diff --git a/client/modules/App/components/Overlay.js b/client/modules/App/components/Overlay.js new file mode 100644 index 00000000..31a451c4 --- /dev/null +++ b/client/modules/App/components/Overlay.js @@ -0,0 +1,17 @@ +import React, { PropTypes } from 'react'; + +function Overlay(props) { + return ( +
+
+ {props.children} +
+
+ ); +} + +Overlay.propTypes = { + children: PropTypes.object +}; + +export default Overlay; diff --git a/client/modules/IDE/actions/projects.js b/client/modules/IDE/actions/projects.js new file mode 100644 index 00000000..d1898d77 --- /dev/null +++ b/client/modules/IDE/actions/projects.js @@ -0,0 +1,25 @@ +import * as ActionTypes from '../../../constants'; +import { browserHistory } from 'react-router'; +import axios from 'axios'; + +const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api'; + +export function getProjects() { + return (dispatch) => { + axios.get(`${ROOT_URL}/projects`, { withCredentials: true }) + .then(response => { + dispatch({ + type: ActionTypes.SET_PROJECTS, + projects: response.data + }); + }) + .catch(response => dispatch({ + type: ActionTypes.ERROR, + error: response.data + })); + }; +} + +export function closeSketchList() { + browserHistory.push('/'); +} diff --git a/client/modules/IDE/components/SketchList.js b/client/modules/IDE/components/SketchList.js new file mode 100644 index 00000000..718a1849 --- /dev/null +++ b/client/modules/IDE/components/SketchList.js @@ -0,0 +1,68 @@ +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import moment from 'moment'; +import { Link } from 'react-router'; +import * as SketchActions from '../actions/projects'; +import * as ProjectActions from '../actions/project'; +import InlineSVG from 'react-inlinesvg'; +const exitUrl = require('../../../images/exit.svg'); + +class SketchList extends React.Component { + componentDidMount() { + this.props.getProjects(); + } + + render() { + return ( +
+
+

Sketches

+ +
+
+ + + + + + + + + + {this.props.sketches.map(sketch => + + + + + + )} + +
NameCreatedLast Updated
{sketch.name}{moment(sketch.createdAt).format('MMM D, YYYY')}{moment(sketch.updatedAt).format('MMM D, YYYY')}
+
+
+ ); + } +} + +SketchList.propTypes = { + user: PropTypes.object.isRequired, + getProjects: PropTypes.func.isRequired, + sketches: PropTypes.array.isRequired, + closeSketchList: PropTypes.func.isRequired +}; + +function mapStateToProps(state) { + return { + user: state.user, + sketches: state.sketches + }; +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(Object.assign({}, SketchActions, ProjectActions), dispatch); +} + +export default connect(mapStateToProps, mapDispatchToProps)(SketchList); diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js index 4da5c9b1..034c797b 100644 --- a/client/modules/IDE/pages/IDEView.js +++ b/client/modules/IDE/pages/IDEView.js @@ -16,9 +16,12 @@ import * as EditorAccessibilityActions from '../actions/editorAccessibility'; import * as PreferencesActions from '../actions/preferences'; import { getFile, getHTMLFile, getJSFiles, getCSSFiles, setSelectedFile } from '../reducers/files'; import SplitPane from 'react-split-pane'; +import Overlay from '../../App/components/Overlay'; +import SketchList from '../components/SketchList'; class IDEView extends React.Component { constructor(props) { + console.log(props); super(props); this._handleConsolePaneOnDragFinished = this._handleConsolePaneOnDragFinished.bind(this); this._handleSidebarPaneOnDragFinished = this._handleSidebarPaneOnDragFinished.bind(this); @@ -50,6 +53,10 @@ class IDEView extends React.Component { if (this.props.ide.sidebarIsExpanded !== nextProps.ide.sidebarIsExpanded) { this.sidebarSize = nextProps.ide.sidebarIsExpanded ? 180 : 20; } + + if (nextProps.params.project_id && !this.props.params.project_id) { + this.props.getProject(nextProps.params.project_id); + } } componentDidUpdate(prevProps) { @@ -227,6 +234,15 @@ class IDEView extends React.Component { } return ''; })()} + {(() => { // eslint-disable-line + if (this.props.location.pathname === '/sketches') { + return ( + + + + ); + } + })()} ); @@ -237,6 +253,9 @@ IDEView.propTypes = { params: PropTypes.shape({ project_id: PropTypes.string }), + location: PropTypes.shape({ + pathname: PropTypes.string + }), getProject: PropTypes.func.isRequired, user: PropTypes.shape({ authenticated: PropTypes.bool.isRequired, diff --git a/client/modules/IDE/reducers/projects.js b/client/modules/IDE/reducers/projects.js new file mode 100644 index 00000000..b973bccc --- /dev/null +++ b/client/modules/IDE/reducers/projects.js @@ -0,0 +1,12 @@ +import * as ActionTypes from '../../../constants'; + +const sketches = (state = [], action) => { + switch (action.type) { + case ActionTypes.SET_PROJECTS: + return action.projects; + default: + return state; + } +}; + +export default sketches; diff --git a/client/routes.js b/client/routes.js index e071eb7f..356a27da 100644 --- a/client/routes.js +++ b/client/routes.js @@ -4,7 +4,7 @@ import App from './modules/App/App'; import IDEView from './modules/IDE/pages/IDEView'; import LoginView from './modules/User/pages/LoginView'; import SignupView from './modules/User/pages/SignupView'; -import SketchListView from './modules/Sketch/pages/SketchListView'; +// import SketchListView from './modules/Sketch/pages/SketchListView'; import { getUser } from './modules/User/actions'; const checkAuth = (store) => { @@ -18,7 +18,7 @@ const routes = (store) => - + ); diff --git a/client/styles/components/_overlay.scss b/client/styles/components/_overlay.scss new file mode 100644 index 00000000..3ece1be1 --- /dev/null +++ b/client/styles/components/_overlay.scss @@ -0,0 +1,17 @@ +.overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 9999; + background-color: rgba(0, 0, 0, 0.1); +} + +.overlay-content { + height: 100%; + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss index 1658855f..4780b12a 100644 --- a/client/styles/components/_sketch-list.scss +++ b/client/styles/components/_sketch-list.scss @@ -1,10 +1,25 @@ +.sketch-list__header { + display: flex; + justify-content: space-between; + padding: #{20 / $base-font-size}rem; +} + +.sketches-table-container { + flex: 1 0 0%; + overflow-y: scroll; +} + .sketches-table { width: 100%; padding: #{10 / $base-font-size}rem 0; - padding-left: #{170 / $base-font-size}rem; + padding-left: #{20 / $base-font-size}rem; height: 100%; } .sketches-table__row { margin: #{10 / $base-font-size}rem; +} + +.sketch-list__exit-button { + @extend %icon; } \ No newline at end of file diff --git a/client/styles/layout/_sketch-list.scss b/client/styles/layout/_sketch-list.scss index 0784629c..7587262d 100644 --- a/client/styles/layout/_sketch-list.scss +++ b/client/styles/layout/_sketch-list.scss @@ -1,11 +1,8 @@ .sketch-list { + @extend %modal; display: flex; flex-wrap: wrap; - height: 100%; flex-flow: column; + width: #{1000 / $base-font-size}rem; + height: #{700 / $base-font-size}rem; } - -.sketches-table-container { - flex: 1 0 0%; - overflow-y: scroll; -} \ No newline at end of file diff --git a/client/styles/main.scss b/client/styles/main.scss index 7a565c25..3b3a79a3 100644 --- a/client/styles/main.scss +++ b/client/styles/main.scss @@ -20,6 +20,7 @@ @import 'components/modal'; @import 'components/console'; @import 'components/resizer'; +@import 'components/overlay'; @import 'layout/ide'; @import 'layout/sketch-list'; From e823e383e7591a939a360a4fa1f22d210affdf20 Mon Sep 17 00:00:00 2001 From: catarak Date: Mon, 15 Aug 2016 17:14:55 -0400 Subject: [PATCH 4/4] add timestamp to sketch list view --- client/modules/IDE/components/SketchList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/modules/IDE/components/SketchList.js b/client/modules/IDE/components/SketchList.js index 718a1849..5d2a759e 100644 --- a/client/modules/IDE/components/SketchList.js +++ b/client/modules/IDE/components/SketchList.js @@ -35,8 +35,8 @@ class SketchList extends React.Component { {this.props.sketches.map(sketch => {sketch.name} - {moment(sketch.createdAt).format('MMM D, YYYY')} - {moment(sketch.updatedAt).format('MMM D, YYYY')} + {moment(sketch.createdAt).format('MMM D, YYYY h:mm:ss A')} + {moment(sketch.updatedAt).format('MMM D, YYYY h:mm:ss A')} )}