From da98dcd47ec304d26c0702843cc2e063b4f79176 Mon Sep 17 00:00:00 2001 From: catarak Date: Wed, 3 Aug 2016 15:11:59 -0400 Subject: [PATCH 01/15] add file deletion --- client/constants.js | 6 + client/modules/IDE/actions/files.js | 29 +++++ client/modules/IDE/components/Sidebar.js | 125 ++++++++++--------- client/modules/IDE/components/SidebarItem.js | 73 +++++++++++ client/modules/IDE/pages/IDEView.js | 11 +- client/modules/IDE/reducers/files.js | 34 +++++ client/styles/components/_sidebar.scss | 26 ++++ 7 files changed, 245 insertions(+), 59 deletions(-) create mode 100644 client/modules/IDE/components/SidebarItem.js diff --git a/client/constants.js b/client/constants.js index 50ca8f8e..8e41ad91 100644 --- a/client/constants.js +++ b/client/constants.js @@ -42,5 +42,11 @@ export const CONSOLE_EVENT = 'CONSOLE_EVENT'; export const EXPAND_CONSOLE = 'EXPAND_CONSOLE'; export const COLLAPSE_CONSOLE = 'COLLAPSE_CONSOLE'; +export const SHOW_FILE_OPTIONS = 'SHOW_FILE_OPTIONS'; +export const HIDE_FILE_OPTIONS = 'HIDE_FILE_OPTIONS'; + +export const UPDATE_FILE_NAME = 'UPDATE_FILE_NAME'; +export const DELETE_FILE = 'DELETE_FILE'; + // eventually, handle errors more specifically and better export const ERROR = 'ERROR'; diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index a4db7961..e7bed3a2 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -112,3 +112,32 @@ export function createFile(formProps) { } }; } + +export function showFileOptions(fileId) { + return { + type: ActionTypes.SHOW_FILE_OPTIONS, + id: fileId + }; +} + +export function hideFileOptions(fileId) { + return { + type: ActionTypes.HIDE_FILE_OPTIONS, + id: fileId + }; +} + +export function updateFileName(id, name) { + return { + type: ActionTypes.UPDATE_FILE_NAME, + id, + name + }; +} + +export function deleteFile(id) { + return { + type: ActionTypes.DELETE_FILE, + id + }; +} diff --git a/client/modules/IDE/components/Sidebar.js b/client/modules/IDE/components/Sidebar.js index b680364a..54bcd246 100644 --- a/client/modules/IDE/components/Sidebar.js +++ b/client/modules/IDE/components/Sidebar.js @@ -1,71 +1,84 @@ import React, { PropTypes } from 'react'; import classNames from 'classnames'; import InlineSVG from 'react-inlinesvg'; +import SidebarItem from './SidebarItem'; const rightArrowUrl = require('../../../images/right-arrow.svg'); const leftArrowUrl = require('../../../images/left-arrow.svg'); -function Sidebar(props) { - const sidebarClass = classNames({ - sidebar: true, - 'sidebar--contracted': !props.isExpanded - }); +class Sidebar extends React.Component { + constructor(props) { + super(props); + this.resetSelectedFile = this.resetSelectedFile.bind(this); + } - return ( - - ); + + + + + + + + + + ); + } } Sidebar.propTypes = { files: PropTypes.array.isRequired, - selectedFile: PropTypes.shape({ - id: PropTypes.string.isRequired - }), - setSelectedFile: PropTypes.func.isRequired + setSelectedFile: PropTypes.func.isRequired, + isExpanded: PropTypes.bool.isRequired, + newFile: PropTypes.func.isRequired, + collapseSidebar: PropTypes.func.isRequired, + expandSidebar: PropTypes.func.isRequired, + showFileOptions: PropTypes.func.isRequired, + hideFileOptions: PropTypes.func.isRequired, + deleteFile: PropTypes.func.isRequired }; export default Sidebar; diff --git a/client/modules/IDE/components/SidebarItem.js b/client/modules/IDE/components/SidebarItem.js new file mode 100644 index 00000000..6b749307 --- /dev/null +++ b/client/modules/IDE/components/SidebarItem.js @@ -0,0 +1,73 @@ +import React, { PropTypes } from 'react'; +import InlineSVG from 'react-inlinesvg'; +import classNames from 'classnames'; +const downArrowUrl = require('../../../images/down-arrow.svg'); + +class SidebarItem extends React.Component { + onFocus() { + + } + + render() { + let itemClass = classNames({ + 'sidebar__file-item': true, + 'sidebar__file-item--selected': this.props.file.isSelected, + 'sidebar__file-item--open': this.props.file.isOptionsOpen + }); + return ( +
  • this.props.hideFileOptions(this.props.file.id)} + tabIndex={this.props.fileIndex} + > + this.props.setSelectedFile(this.props.file.id)} + >{this.props.file.name} + this.props.showFileOptions(this.props.file.id)} + > + + +
    + +
    +
  • + ); + } +} + +SidebarItem.propTypes = { + file: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + isSelected: PropTypes.bool, + isOptionsOpen: PropTypes.bool + }).isRequired, + setSelectedFile: PropTypes.func.isRequired, + fileIndex: PropTypes.number.isRequired, + showFileOptions: PropTypes.func.isRequired, + hideFileOptions: PropTypes.func.isRequired, + deleteFile: PropTypes.func.isRequired, + resetSelectedFile: PropTypes.func.isRequired +}; + +export default SidebarItem; diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js index c5dfd30f..db31bedb 100644 --- a/client/modules/IDE/pages/IDEView.js +++ b/client/modules/IDE/pages/IDEView.js @@ -12,7 +12,7 @@ import { connect } from 'react-redux'; import * as FileActions from '../actions/files'; import * as IDEActions from '../actions/ide'; import * as ProjectActions from '../actions/project'; -import { getFile, getHTMLFile, getJSFiles, getCSSFiles } from '../reducers/files'; +import { getFile, getHTMLFile, getJSFiles, getCSSFiles, setSelectedFile } from '../reducers/files'; class IDEView extends React.Component { componentDidMount() { @@ -50,12 +50,14 @@ class IDEView extends React.Component {
    { return [...action.files]; case ActionTypes.CREATE_FILE: return [...state, { name: action.name, id: action.id, content: '', url: action.url }]; + case ActionTypes.SHOW_FILE_OPTIONS: + return state.map(file => { + if (file.id !== action.id) { + return file; + } + + return Object.assign({}, file, { isOptionsOpen: true }); + }); + case ActionTypes.HIDE_FILE_OPTIONS: + return state.map(file => { + if (file.id !== action.id) { + return file; + } + + return Object.assign({}, file, { isOptionsOpen: false }); + }); + case ActionTypes.UPDATE_FILE_NAME: + return state.map(file => { + if (file.id !== action.id) { + return file; + } + + return Object.assign({}, file, { name: action.name }); + }); + case ActionTypes.DELETE_FILE: + return state.filter(file => file.id !== action.id); default: return state; } }; +export const setSelectedFile = (state, id) => + state.map(file => { + if (file.id === id) { + return Object.assign({}, file, { isSelected: true }); + } + return file; + }); + export const getFile = (state, id) => state.filter(file => file.id === id)[0]; export const getHTMLFile = (state) => state.filter(file => file.name.match(/.*\.html$/))[0]; export const getJSFiles = (state) => state.filter(file => file.name.match(/.*\.js$/)); diff --git a/client/styles/components/_sidebar.scss b/client/styles/components/_sidebar.scss index 5dcd5725..b42dd303 100644 --- a/client/styles/components/_sidebar.scss +++ b/client/styles/components/_sidebar.scss @@ -38,11 +38,37 @@ padding: #{8 / $base-font-size}rem #{20 / $base-font-size}rem; color: $light-inactive-text-color; cursor: pointer; + display: flex; + justify-content: space-between; + position: relative; &--selected { background-color: $ide-border-color; } } +.sidebar__file-item-show-options { + @extend %icon; + display: none; + .sidebar__file-item--selected & { + display: inline-block; + } +} + +.sidebar__file-item-options { + @extend %modal; + position: absolute; + top: 95%; + left: 77%; + display: none; + z-index: 100; + padding: #{8 / $base-font-size}rem #{16 / $base-font-size}rem; + background-color: $light-modal-background-color; + z-index: 100; + .sidebar__file-item--open & { + display: block; + } +} + .sidebar__contract { @extend %icon; height: #{14 / $base-font-size}rem; From 443a9f57d527da8841c788c0cd19e69e513aec74 Mon Sep 17 00:00:00 2001 From: catarak Date: Wed, 3 Aug 2016 17:10:03 -0400 Subject: [PATCH 02/15] add file renaming --- client/constants.js | 2 + client/modules/IDE/actions/files.js | 14 +++++++ client/modules/IDE/components/Sidebar.js | 8 +++- client/modules/IDE/components/SidebarItem.js | 44 +++++++++++++++++--- client/modules/IDE/pages/IDEView.js | 8 +++- client/modules/IDE/reducers/files.js | 16 +++++++ client/styles/components/_sidebar.scss | 17 ++++++++ 7 files changed, 102 insertions(+), 7 deletions(-) diff --git a/client/constants.js b/client/constants.js index 8e41ad91..aaa4973a 100644 --- a/client/constants.js +++ b/client/constants.js @@ -47,6 +47,8 @@ export const HIDE_FILE_OPTIONS = 'HIDE_FILE_OPTIONS'; export const UPDATE_FILE_NAME = 'UPDATE_FILE_NAME'; export const DELETE_FILE = 'DELETE_FILE'; +export const SHOW_EDIT_FILE_NAME = 'SHOW_EDIT_FILE_NAME'; +export const HIDE_EDIT_FILE_NAME = 'HIDE_EDIT_FILE_NAME'; // eventually, handle errors more specifically and better export const ERROR = 'ERROR'; diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index e7bed3a2..788871c1 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -127,6 +127,20 @@ export function hideFileOptions(fileId) { }; } +export function showEditFileName(id) { + return { + type: ActionTypes.SHOW_EDIT_FILE_NAME, + id + }; +} + +export function hideEditFileName(id) { + return { + type: ActionTypes.HIDE_EDIT_FILE_NAME, + id + }; +} + export function updateFileName(id, name) { return { type: ActionTypes.UPDATE_FILE_NAME, diff --git a/client/modules/IDE/components/Sidebar.js b/client/modules/IDE/components/Sidebar.js index 54bcd246..3ee28506 100644 --- a/client/modules/IDE/components/Sidebar.js +++ b/client/modules/IDE/components/Sidebar.js @@ -61,6 +61,9 @@ class Sidebar extends React.Component { hideFileOptions={this.props.hideFileOptions} deleteFile={this.props.deleteFile} resetSelectedFile={this.resetSelectedFile} + showEditFileName={this.props.showEditFileName} + hideEditFileName={this.props.hideEditFileName} + updateFileName={this.props.updateFileName} /> )} @@ -78,7 +81,10 @@ Sidebar.propTypes = { expandSidebar: PropTypes.func.isRequired, showFileOptions: PropTypes.func.isRequired, hideFileOptions: PropTypes.func.isRequired, - deleteFile: PropTypes.func.isRequired + deleteFile: PropTypes.func.isRequired, + showEditFileName: PropTypes.func.isRequired, + hideEditFileName: PropTypes.func.isRequired, + updateFileName: PropTypes.func.isRequired }; export default Sidebar; diff --git a/client/modules/IDE/components/SidebarItem.js b/client/modules/IDE/components/SidebarItem.js index 6b749307..4a00c8dd 100644 --- a/client/modules/IDE/components/SidebarItem.js +++ b/client/modules/IDE/components/SidebarItem.js @@ -4,16 +4,31 @@ import classNames from 'classnames'; const downArrowUrl = require('../../../images/down-arrow.svg'); class SidebarItem extends React.Component { - onFocus() { + constructor(props) { + super(props); + this.handleKeyPress = this.handleKeyPress.bind(this); + this.handleFileNameChange = this.handleFileNameChange.bind(this); + } + handleFileNameChange(event) { + this.props.updateFileName(this.props.file.id, event.target.value); + } + + handleKeyPress(event) { + console.log(event.key); + if (event.key === 'Enter') { + this.props.hideEditFileName(this.props.file.id); + } } render() { let itemClass = classNames({ 'sidebar__file-item': true, 'sidebar__file-item--selected': this.props.file.isSelected, - 'sidebar__file-item--open': this.props.file.isOptionsOpen + 'sidebar__file-item--open': this.props.file.isOptionsOpen, + 'sidebar__file-item--editing': this.props.file.isEditingName }); + return (
  • this.props.setSelectedFile(this.props.file.id)} >{this.props.file.name} + this.props.hideEditFileName(this.props.file.id)} + onKeyPress={this.handleKeyPress} + /> this.props.showFileOptions(this.props.file.id)} @@ -32,7 +57,12 @@ class SidebarItem extends React.Component {